[BUG] Windows: plugin-shipped MCP servers using bare `npx` fail with `spawn ENOENT` (LSP fix from #17312 missed the MCP spawn path)

Resolved 💬 8 comments Opened May 12, 2026 by JohnOBiner Closed Jul 14, 2026

Summary

Plugin-shipped stdio MCP servers that use bare npx as their command (the default for most official plugins) fail with spawn npx ENOENT on Windows. The LSP spawn fix from #17312 (landed in v2.1.132) addressed the equivalent bug for LSP plugins but didn't extend to the MCP server spawn path — so MCP plugins are still broken in the same way.

This affects every official plugin I tested whose .mcp.json / plugin.json ships "command": "npx".

Affected official plugins (as of 2.1.139)

All of these Failed to connect until I manually wrapped each with cmd /c:

| Plugin | Config location | Command shipped |
|---|---|---|
| context7@claude-plugins-official | .mcp.json | npx -y @upstash/context7-mcp |
| chrome-devtools-mcp@claude-plugins-official | .claude-plugin/plugin.json (inline) | npx chrome-devtools-mcp@latest |
| azure@claude-plugins-official | .mcp.json | npx -y @azure/mcp@latest server start |
| mongodb@claude-plugins-official | mcp.json (referenced from plugin.json) | npx -y mongodb-mcp-server@1 |
| desktop-commander@claude-plugins-official | .claude-plugin/plugin.json (inline) | npx -y @wonderwhy-er/desktop-commander@latest |
| playwright@claude-plugins-official | .mcp.json | npx @playwright/mcp@latest |

Reproducer (no Claude Code needed)

const { spawn } = require('child_process');
const p = spawn('npx', ['-y', '@upstash/context7-mcp', '--version'], { stdio: 'inherit' });
p.on('error', e => console.error('SPAWN ERROR:', e.code, e.message));

On Windows 10/11, Node 20.x or 22.x:

SPAWN ERROR: ENOENT spawn npx ENOENT

With { shell: true } (or wrapping in cmd /c), it succeeds immediately:

2.2.5

Root cause

On Windows, npx is the batch shim npx.cmd. Node's child_process.spawn only resolves .cmd/.bat extensions via PATHEXT when shell: true (or shell: 'cmd.exe') is set, or when the caller passes the explicit .cmd filename. This is the same Node-on-Windows pattern that #17312 fixed for LSP server spawning in v2.1.132.

Expected behavior

The MCP server spawn path should use shell: true (or equivalent) on process.platform === 'win32' — matching whatever the LSP path now does post-#17312.

Workaround (fragile)

Edit each plugin's manifest under ~/.claude/plugins/cache/<marketplace>/<plugin>/<version>/... to wrap the command:

- "command": "npx",
- "args": ["-y", "@upstash/context7-mcp"]
+ "command": "cmd",
+ "args": ["/c", "npx", "-y", "@upstash/context7-mcp"]

This works (verified all 6 plugins above now show ✓ Connected), but gets wiped whenever the plugin updates, since the patched files live in the plugin cache rather than in any user-owned config.

Note: the location of the MCP block varies across plugins — .mcp.json at the install root, mcpServers inline in .claude-plugin/plugin.json, or a separate mcp.json referenced from plugin.json. The patch has to land in whichever file the plugin actually uses, and claude mcp list doesn't tell you which.

Why this is distinct from existing open issues

  • #46360 (Playwright/Windows) is about the claude mcp add CLI mangling /c into C:/ for user-configured servers. This issue is about plugin-shipped configs that never go through claude mcp add.
  • #32951 (local stdio MCP not loaded on native Windows) is about local servers being silently absent from /mcp. Here the servers do appear in claude mcp list — they just fail at the spawn step with a visible "Failed to connect".
  • #17312 / #19658 / #21115 are all LSP-specific. The fix that closed them addressed the LSP code path; the MCP path has the same bug and needs the same fix.

Environment

  • Claude Code: 2.1.139 (latest as of filing)
  • OS: Windows 10 Pro 10.0.19045
  • Node: tested on 20.15.0 and 22.22.2 — both reproduce the spawn ENOENT
  • Shell: PowerShell 7 (also reproduces from Git Bash and a raw node -e invocation)
  • Plugin marketplace: claude-plugins-official

Suggested fix

In whatever module spawns stdio MCP servers, mirror the LSP fix from #17312 — pass shell: true (or shell: 'cmd.exe') when process.platform === 'win32'. Same one-line change that worked for LSP should clear this entire category of plugin failures.

View original on GitHub ↗

This issue has 8 comments on GitHub. Read the full discussion on GitHub ↗