Skip to content

Commit b623247

Browse files
fix(mcp): fix Windows MCP spawn double-quoting that breaks all MCP servers
The quoteWindowsShellArg function wrapped every argument in double quotes unconditionally, producing command strings like '"npx" "-y" "@playwright/mcp"'. When passed to spawn() with shell:true, Node.js wraps the entire string again for cmd.exe, causing double-quoting that breaks command parsing. All MCP servers (playwright, fetch, memory, github) failed to start on Windows. Fix: only quote arguments that contain spaces or double-quotes, leaving simple args unquoted.
1 parent fc1223b commit b623247

2 files changed

Lines changed: 12 additions & 7 deletions

File tree

src/mcp/mcp-client.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -425,9 +425,11 @@ export function createMcpSpawnSpec(
425425
if (platform === "win32") {
426426
return {
427427
// On Windows, shell: true lets cmd.exe resolve the command via PATHEXT
428-
// (npx -> npx.cmd, etc.). Pass one quoted command line with no spawn
429-
// args to avoid Node 24 DEP0190.
430-
command: [command, ...args].map(quoteWindowsShellArg).join(" "),
428+
// (npx -> npx.cmd, etc.). Join command and args into a single string
429+
// with empty spawn args to avoid Node 24 DEP0190.
430+
// Only quote arguments that contain spaces or double-quotes to prevent
431+
// double-wrapping by Node.js's own shell quoting.
432+
command: [command, ...args].map(quoteWindowsArgIfNeeded).join(" "),
431433
args: [],
432434
shell: true,
433435
windowsHide: true,
@@ -441,6 +443,9 @@ export function createMcpSpawnSpec(
441443
};
442444
}
443445

444-
function quoteWindowsShellArg(arg: string): string {
445-
return `"${arg.replace(/(\\*)"/g, '$1$1\\"').replace(/\\+$/g, "$&$&")}"`;
446+
function quoteWindowsArgIfNeeded(arg: string): string {
447+
if (arg.includes(" ") || arg.includes('"')) {
448+
return `"${arg.replace(/(\\*)"/g, '$1$1\\"').replace(/\\+$/g, "$&$&")}"`;
449+
}
450+
return arg;
446451
}

src/tests/mcp-client.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ test("createMcpSpawnSpec keeps non-Windows MCP launches shell-free", () => {
1010
});
1111
});
1212

13-
test("createMcpSpawnSpec avoids Windows shell args for Node 24", () => {
13+
test("createMcpSpawnSpec joins args without quoting when spaces are absent (Windows)", () => {
1414
assert.deepEqual(createMcpSpawnSpec("npx", ["-y", "@playwright/mcp@latest"], "win32"), {
15-
command: '"npx" "-y" "@playwright/mcp@latest"',
15+
command: "npx -y @playwright/mcp@latest",
1616
args: [],
1717
shell: true,
1818
windowsHide: true,

0 commit comments

Comments
 (0)