Skip to content

Commit 0814650

Browse files
committed
Fixes #4739: Add support for VS Code magic variables in MCP configuration
- Enhanced injectVariables function to resolve VS Code magic variables like , , etc. - Added comprehensive test coverage for variable injection functionality - Fixed issue where VS Code magic variables in MCP server configurations would cause 'Invalid MCP settings JSON format' errors - Variables now properly resolve to actual paths instead of remaining as literal strings Resolves: #4739
1 parent 2e2f83b commit 0814650

File tree

3 files changed

+378
-125
lines changed

3 files changed

+378
-125
lines changed
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import { describe, it, expect, beforeEach, vi } from "vitest"
2+
import * as vscode from "vscode"
3+
import { injectVariables } from "../../../utils/config"
4+
5+
// Mock vscode module
6+
vi.mock("vscode", () => ({
7+
workspace: {
8+
workspaceFolders: [
9+
{
10+
uri: {
11+
fsPath: "/test/workspace",
12+
},
13+
},
14+
],
15+
getWorkspaceFolder: vi.fn(),
16+
},
17+
window: {
18+
activeTextEditor: {
19+
document: {
20+
uri: {
21+
fsPath: "/test/workspace/src/test.ts",
22+
},
23+
},
24+
},
25+
},
26+
}))
27+
28+
describe("MCP Variable Injection", () => {
29+
beforeEach(() => {
30+
vi.clearAllMocks()
31+
32+
// Setup workspace folder mock
33+
const mockWorkspaceFolder = {
34+
uri: { fsPath: "/test/workspace" },
35+
}
36+
;(vscode.workspace.getWorkspaceFolder as any).mockReturnValue(mockWorkspaceFolder)
37+
})
38+
39+
it("should resolve workspaceFolder in MCP server configuration", async () => {
40+
const mcpConfig = {
41+
type: "stdio",
42+
command: "node",
43+
args: ["${workspaceFolder}/mcp-server/index.js"],
44+
env: {
45+
CONFIG_PATH: "${workspaceFolder}/.config",
46+
},
47+
}
48+
49+
const result = await injectVariables(mcpConfig, {
50+
env: process.env,
51+
workspaceFolder: vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? "",
52+
})
53+
54+
expect(result.args[0]).toBe("/test/workspace/mcp-server/index.js")
55+
expect(result.env.CONFIG_PATH).toBe("/test/workspace/.config")
56+
})
57+
58+
it("should resolve fileWorkspaceFolder in MCP server configuration", async () => {
59+
const mcpConfig = {
60+
type: "stdio",
61+
command: "node",
62+
args: ["${fileWorkspaceFolder}/server.js"],
63+
}
64+
65+
const result = await injectVariables(mcpConfig, {
66+
env: process.env,
67+
workspaceFolder: vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? "",
68+
})
69+
70+
expect(result.args[0]).toBe("/test/workspace/server.js")
71+
})
72+
73+
it("should handle complex MCP configuration with multiple variables", async () => {
74+
const mcpConfig = {
75+
type: "stdio",
76+
command: "node",
77+
args: [
78+
"${workspaceFolder}/node_modules/.bin/mcp-server-git",
79+
"--repository",
80+
"${workspaceFolder}",
81+
"--config",
82+
"${userHome}/.gitconfig",
83+
],
84+
env: {
85+
GIT_DIR: "${workspaceFolder}/.git",
86+
HOME: "${userHome}",
87+
},
88+
}
89+
90+
const result = await injectVariables(mcpConfig, {
91+
env: process.env,
92+
workspaceFolder: vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? "",
93+
})
94+
95+
expect(result.args[0]).toBe("/test/workspace/node_modules/.bin/mcp-server-git")
96+
expect(result.args[2]).toBe("/test/workspace")
97+
expect(result.args[4]).toMatch(/\/.*\/.gitconfig$/) // Should contain userHome path
98+
expect(result.env.GIT_DIR).toBe("/test/workspace/.git")
99+
expect(result.env.HOME).toMatch(/\/.*/) // Should contain userHome path
100+
})
101+
102+
it("should handle environment variables with env: prefix", async () => {
103+
const mcpConfig = {
104+
type: "stdio",
105+
command: "node",
106+
args: ["${workspaceFolder}/server.js"],
107+
env: {
108+
PATH: "${env:PATH}",
109+
NODE_ENV: "${env:NODE_ENV}",
110+
},
111+
}
112+
113+
const result = await injectVariables(mcpConfig, {
114+
env: {
115+
PATH: "/usr/bin:/bin",
116+
NODE_ENV: "development",
117+
},
118+
workspaceFolder: vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? "",
119+
})
120+
121+
expect(result.args[0]).toBe("/test/workspace/server.js")
122+
expect(result.env.PATH).toBe("/usr/bin:/bin")
123+
expect(result.env.NODE_ENV).toBe("development")
124+
})
125+
126+
it("should leave unresolved variables unchanged", async () => {
127+
const mcpConfig = {
128+
type: "stdio",
129+
command: "node",
130+
args: ["${workspaceFolder}/server.js", "${unknownVariable}"],
131+
}
132+
133+
const result = await injectVariables(mcpConfig, {
134+
env: process.env,
135+
workspaceFolder: vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? "",
136+
})
137+
138+
expect(result.args[0]).toBe("/test/workspace/server.js")
139+
expect(result.args[1]).toBe("${unknownVariable}")
140+
})
141+
142+
it("should handle the exact scenario from the GitHub issue", async () => {
143+
// This is the exact configuration that was failing in the issue
144+
const mcpConfig = {
145+
type: "stdio",
146+
command: "node",
147+
args: ["${workspaceFolder}/mcp-server-git/index.js"],
148+
}
149+
150+
const result = await injectVariables(mcpConfig, {
151+
env: process.env,
152+
workspaceFolder: vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? "",
153+
})
154+
155+
// This should now work instead of causing "Invalid MCP settings JSON format"
156+
expect(result.args[0]).toBe("/test/workspace/mcp-server-git/index.js")
157+
expect(result.type).toBe("stdio")
158+
expect(result.command).toBe("node")
159+
})
160+
})

0 commit comments

Comments
 (0)