fix(installer): copilot-vscode global entry drops ${workspaceFolder} — VS Code toasts an error in every folderless window

A user-level mcp.json entry using ${workspaceFolder} makes VS Code
refuse to start the server in ANY window without a folder open (loose
files, welcome tab), toasting "Variable workspaceFolder can not be
resolved" — recurring error-noise, hit live during validation.

The pin was never needed for VS Code: unlike Cursor, VS Code documents
stdio-server cwd as the workspace folder, and the codegraph server
resolves its project via roots/list with a cwd fallback. Global entries
are now variable-free (`serve --mcp`); local installs keep the absolute
--path. This supersedes the "open a folder" install note from the
previous commit, which is removed again.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Colby McHenry
2026-07-23 21:29:47 -05:00
co-authored by Claude Fable 5
parent 73313213e1
commit 9769d6be0f
2 changed files with 33 additions and 32 deletions
+9 -11
View File
@@ -1945,11 +1945,18 @@ describe('Installer targets — Copilot family', () => {
expect(cfg.mcpServers).toBeUndefined();
});
it('copilot-vscode: global install pins --path to ${workspaceFolder}', () => {
it('copilot-vscode: global install writes a variable-free entry — no --path, no ${workspaceFolder}', () => {
// VS Code refuses to start a user-level server whose entry uses
// ${workspaceFolder} in any window with no folder open, toasting
// "Variable workspaceFolder can not be resolved" (hit live). VS Code
// documents cwd = workspace folder for stdio servers, and the
// codegraph server resolves the project from roots/cwd — so the
// global entry must carry no --path and no variables at all.
const t = getTarget('copilot-vscode')!;
const result = t.install('global', { autoAllow: true });
const cfg = JSON.parse(fs.readFileSync(result.files[0].path, 'utf-8'));
expect(cfg.servers.codegraph.args).toEqual(['serve', '--mcp', '--path', '${workspaceFolder}']);
expect(cfg.servers.codegraph.args).toEqual(['serve', '--mcp']);
expect(JSON.stringify(cfg)).not.toContain('${');
});
it.runIf(process.platform === 'darwin')('copilot-vscode: global path is ~/Library/Application Support/Code/User/mcp.json on macOS', () => {
@@ -2095,15 +2102,6 @@ describe('Installer targets — Copilot family', () => {
expect(result.notes?.join(' ')).toMatch(/[Rr]estart VS Code/);
});
it('copilot-vscode: global install warns that ${workspaceFolder} needs an open folder; local does not', () => {
const t = getTarget('copilot-vscode')!;
// VS Code refuses to start a user-level server whose entry uses
// ${workspaceFolder} when no folder is open — surface that up front.
const globalNotes = t.install('global', { autoAllow: true }).notes?.join(' ');
expect(globalNotes).toMatch(/open a folder/i);
const localNotes = t.install('local', { autoAllow: true }).notes?.join(' ');
expect(localNotes).not.toMatch(/open a folder/i);
});
// ---- copilot-cli ----