fix: restart ql-mcp server on vscode workspace folder changes#196
fix: restart ql-mcp server on vscode workspace folder changes#196data-douser wants to merge 5 commits intomainfrom
ql-mcp server on vscode workspace folder changes#196Conversation
When workspace folders were added or removed, fireDidChange() notified VS Code that the MCP server definitions changed, causing it to stop the running server. However, because the returned McpStdioServerDefinition had the same version as before, VS Code did not restart the server. Add a monotonically increasing revision counter to McpProvider that increments on each fireDidChange() call and is appended to the version string (e.g. 2.25.1.1, 2.25.1.2). This signals VS Code that the definition has genuinely changed and triggers a server restart with the updated environment instead of only stopping the server. - Add _revision counter and getEffectiveVersion() to McpProvider - Add 4 unit tests for version-bumping behaviour - Add integration test suite for workspace folder change scenarios
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Snapshot WarningsEnsure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice. Scanned FilesNone |
There was a problem hiding this comment.
Pull request overview
This PR fixes a VS Code MCP lifecycle issue where workspace folder changes would stop (but not restart) the ql-mcp server by ensuring the provided server definition’s version changes on each definition refresh.
Changes:
- Add a monotonically increasing revision counter to
McpProviderand append it to the effective server definition version afterfireDidChange(). - Add unit tests validating version bumping behavior across
fireDidChange()calls. - Add an extension-host integration test suite covering workspace folder add/remove scenarios and env refresh.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| extensions/vscode/src/server/mcp-provider.ts | Adds _revision and computes an “effective” version that changes after fireDidChange() to force VS Code to restart the server. |
| extensions/vscode/test/server/mcp-provider.test.ts | Adds unit tests verifying version changes and revision suffixing for pinned/latest cases. |
| extensions/vscode/test/suite/workspace-folder-change.integration.test.ts | Adds integration coverage for workspace-folder-driven definition changes and environment refresh behavior. |
Comments suppressed due to low confidence (2)
extensions/vscode/test/suite/workspace-folder-change.integration.test.ts:201
fs.rmdirSyncis deprecated in newer Node versions. Preferfs.rmSync(tempDir, { recursive: true, force: true })here as well (and wrap in try/catch if you want best-effort cleanup).
if (!added) {
fs.rmdirSync(tempDir);
this.skip();
extensions/vscode/test/suite/workspace-folder-change.integration.test.ts:132
- The comment says Mocha's timeout is 60s, but the test runner sets Mocha's timeout to 30s. Either update this comment or set a longer timeout for this test to avoid confusion / unexpected timeouts on slow CI.
// Listen for the onDidChangeMcpServerDefinitions event.
// Mocha's test timeout (60 s) handles the failure case.
const changePromise = new Promise<void>((resolve) => {
extensions/vscode/test/suite/workspace-folder-change.integration.test.ts
Outdated
Show resolved
Hide resolved
extensions/vscode/test/suite/workspace-folder-change.integration.test.ts
Outdated
Show resolved
Hide resolved
extensions/vscode/test/suite/workspace-folder-change.integration.test.ts
Outdated
Show resolved
Hide resolved
extensions/vscode/test/suite/workspace-folder-change.integration.test.ts
Outdated
Show resolved
Hide resolved
- Invalidate cached environment when workspace folders change so the next server start picks up updated folder list - getEffectiveVersion() always returns a concrete string (never undefined) so VS Code has a reliable baseline for version comparison - Add multi-root workspace integration tests verifying environment correctness (CODEQL_MCP_WORKSPACE_FOLDERS includes/excludes folders) - Add unit test for workspace folder change handler behavior - Add unit test for always-defined version string - Add multiRoot test profile with 4 workspace folders
extensions/vscode/test/fixtures/multi-root-workspace/test.code-workspace
Outdated
Show resolved
Hide resolved
Agent-Logs-Url: https://github.com/advanced-security/codeql-development-mcp-server/sessions/bc6e5960-6b48-4be3-addb-49a4f14b6efa Co-authored-by: data-douser <70299490+data-douser@users.noreply.github.com>
| const vscodeMock = vi.mocked(vscode); | ||
| vscodeMock.workspace.onDidChangeWorkspaceFolders = vi.fn().mockImplementation( | ||
| (cb: Function) => { workspaceFolderChangeCallback = cb; return { dispose: vi.fn() }; }, | ||
| ); |
There was a problem hiding this comment.
This test overwrites vscode.workspace.onDidChangeWorkspaceFolders by assignment and never restores it. If Vitest runs test files in parallel within the same worker, this mutation can leak into other tests and cause order-dependent failures. Prefer vi.spyOn(vscode.workspace, 'onDidChangeWorkspaceFolders') (or save/restore the original) and restore the spy at the end of the test.
| /** | ||
| * Request that VS Code restart the MCP server with a fresh environment. | ||
| * | ||
| * Bumps the internal revision counter so that the next call to | ||
| * `provideMcpServerDefinitions()` returns a definition with a different | ||
| * `version` string. VS Code compares the new version to the running | ||
| * server's version and, seeing a change, triggers a stop → start cycle. | ||
| * | ||
| * Use for changes that require a server restart (configuration changes). | ||
| */ | ||
| requestRestart(): void { | ||
| this._revision++; | ||
| this.logger.info( | ||
| `Requesting ql-mcp restart (revision ${this._revision})...`, | ||
| ); | ||
| this._onDidChange.fire(); | ||
| } |
There was a problem hiding this comment.
requestRestart() is documented as restarting the server “with a fresh environment”, but it only bumps the revision and fires the change event. Because EnvironmentBuilder caches results, a caller that forgets to call envBuilder.invalidate() could trigger a restart while still reusing a stale cached env. Either invalidate the env cache inside requestRestart() or adjust the docstring to state that callers must invalidate the environment separately.
|
@copilot apply changes based on the comments in this thread |
Problem
When workspace folders were added or removed, fireDidChange() notified VS Code that the MCP server definitions changed, causing it to stop the running server. However, because the returned
McpStdioServerDefinitionhad the same version as before, VS Code did not restart theql-mcpserver -- which was left in an inconsistent, partially running state.Summary of Changes
This pull request improves how the extension handles workspace folder changes and MCP server restarts in VS Code. The main changes ensure that the environment cache is correctly invalidated when workspace folders change, and that MCP server restarts are triggered only when necessary (such as on configuration changes, not folder changes). It also introduces versioning logic for MCP server definitions to ensure VS Code can reliably determine when to restart the server. Unit and integration tests are added to verify this behavior.
Outline of Changes
Workspace folder change handling:
envBuilder.invalidate()) when workspace folders change, relying on VS Code to manage MCP server restarts, rather than triggering a restart or sending unnecessary notifications.workspace-folder-change.integration.test.ts) to verify that the environment cache is properly rebuilt when workspace folders are added or removed, and that original folders persist after workspace mutations. [1] [2]updateWorkspaceFolders.MCP server restart mechanism:
requestRestart()method inMcpProviderthat increments a revision counter and appends it to the server version string, ensuring VS Code detects a version change and restarts the server when needed (e.g., on configuration changes). [1] [2] [3]requestRestart()on configuration changes, and clarified the distinction between soft and hard server update signals.Testing improvements:
McpProvider, including scenarios for pinned and unpinned versions, soft and hard signals, and event firing. [1] [2] [3]Fixture cleanup:
/private/var/.../T/ql-mcp-seq2-DMXgqX) fromtest.code-workspacethat made the fixture non-reproducible across machines and CI environments.These changes make the extension's behavior more predictable and robust in multi-root workspaces and dynamic workspace scenarios.
📝 Update Information
Primitive Details
McpProvider/ VS Code extension workspace folder handlingThis PR is for updating an existing MCP server primitive and must ONLY include these file types:
✅ ALLOWED FILES:
server/src/**/*.ts)server/src/tools/*.ts)server/test/**/*.ts)README.md, server docs)server/src/types/*.ts)server/src/lib/*.ts)package.json,tsconfig.json)🚫 FORBIDDEN FILES:
Rationale: This PR should contain only the files necessary to update and test the primitive.
🚨 PRs that include forbidden files will be rejected and must be revised.
🛑 MANDATORY PR VALIDATION CHECKLIST
BEFORE SUBMITTING THIS PR, CONFIRM:
Update Metadata
🎯 Changes Description
Current Behavior
When workspace folders were added or removed,
fireDidChange()notified VS Code that the MCP server definitions changed, causing it to stop the running server. Because the returnedMcpStdioServerDefinitionhad the same version as before, VS Code did not restart theql-mcpserver, leaving it in an inconsistent, partially running state. Additionally, the multi-root workspace test fixture contained a machine-specific absolute temp folder path that caused non-reproducible test failures on other machines and CI.Updated Behavior
The extension now correctly invalidates its environment cache on workspace folder changes and uses a monotonically increasing revision counter (via
requestRestart()) to ensure VS Code reliably detects version changes and restarts the server when needed. The test fixture is cleaned up to contain only repo-relative folders; runtime workspace mutations add/remove temp folders dynamically viaupdateWorkspaceFolders.Motivation
The previous implementation left the
ql-mcpserver in a broken state after workspace folder changes, and the committed fixture was non-reproducible across different development machines and CI environments.🔄 Before vs. After Comparison
Functionality Changes
API Changes
Output Format Changes
🧪 Testing & Validation
Test Coverage Updates
Validation Scenarios
requestRestart()correctly increments revision and fires change event; version string changes on each callTest Results
📋 Implementation Details
Files Modified
extensions/vscode/src/server/mcp-provider.tsextensions/vscode/src/extension.tsextensions/vscode/test/server/mcp-provider.test.ts,extensions/vscode/test/suite/workspace-folder-change.integration.test.tsextensions/vscode/test/fixtures/multi-root-workspace/test.code-workspace(removed machine-specific temp folder entry)Code Changes Summary
McpProviderfs.rmdirSyncreplaced withfs.rmSyncrequestRestart()method properly typedCODEQL_MCP_WORKSPACE_FOLDERSassertionsDependencies
🔍 Quality Improvements
Bug Fixes (if applicable)
ql-mcpserver stopped but not restarted after workspace folder changes; test fixture contained machine-specific pathfireDidChange()was called with identical version string; fixture was committed with absolute temp path from developer machinerequestRestart()with revision counter; removed machine-specific entry from fixturerequestRestart()call; fixture is now limited to repo-relative foldersCode Quality Enhancements
requestRestart()requestRestart()can be called from any handler that needs to force a server restart🔗 References
Related Issues/PRs
External References
Validation Materials
mcp-provider.test.ts(unit),workspace-folder-change.integration.test.ts(integration)🚀 Compatibility & Migration
Backward Compatibility
API Evolution
requestRestart()method added toMcpProvider👥 Review Guidelines
For Reviewers
Please verify:
requestRestart()Testing Instructions
Validation Checklist
requestRestart()increments revision and changes version string📊 Impact Assessment
Server Impact
AI Assistant Impact
🔄 Deployment Strategy
Rollout Considerations
Update Methodology: This update follows best practices: