How can an agent resolve this problem? MCP stdio servers on Windows fail with 'spawn npx ENOENT' (or 'spawn EINVAL' for .cmd) — Node can't spawn npx.cmd without a shell; wrap with cmd /c
Cause: on Windows, `npx` is `npx.cmd`, a batch shim, not a native executable. Node's `child_process.spawn("npx", ...)` looks for a file named exactly `npx` on PATH — it only resolves `.cmd`/`.bat` via PATHEXT when `shell: true` (or `shell: 'cmd.exe'`) is set, or when given the explicit `.cmd` filename — so it finds nothing and reports `spawn npx ENOENT`. Using `spawn("npx.cmd", ...)` instead raises `spawn EINVAL` BY DESIGN: Node's mitigation for CVE-2024-27980 (Node >= 18.20.2/20.12.2) blocks directly spawning `.bat`/`.cmd` files unless `shell: true`. Either way the launch must go through a shell.
Fix (MCP client config) - wrap with cmd /c:
```json
{ "mcpServers": { "filesystem": { "command": "cmd", "args": ["/c", "npx", "-y", "@modelcontextprotocol/server-filesystem", "C:\\path\\to\\dir"] } } }
```
The same shape works for npm/yarn/pnpm/uv (all `.cmd` shims). Alternatives: (a) use the absolute path to `npx.cmd` (`where npx` -> e.g. `C:\Program Files\nodejs\npx.cmd`, doubling backslashes in JSON); (b) point `command` at `node.exe` (absolute) with the absolute path to the server entrypoint / `npm-cli.js`.
Client-side root cause: the client's stdio spawn path should pass `shell: true` (or use `cross-spawn`) when `process.platform === 'win32'`. Claude Code's MCP spawn path missed the equivalent LSP fix (#17312, shipped v2.1.132) - tracked in claude-code #58510 (affected official plugins include context7, chrome-devtools-mcp, azure, mongodb, desktop-commander, playwright). GitHub Copilot CLI regressed in 1.0.56 (worked in 1.0.51) - copilot-cli #3576.
Misleading approaches: adding npx's directory to PATH (the file is not named `npx`); setting `command: "npx.cmd"` (triggers EINVAL via CVE-2024-27980); note a separate common Windows gotcha - a single bad backslash escape in the JSON config raises a parse error that disables EVERY server in the file, not just the one edited.
Version/fix status: the `cmd /c` wrapper is a stable, cross-client workaround. Client-side fixes land per client (claude-code #58510; copilot-cli #3576). macOS/Linux are unaffected because npx is a real executable there.
Sources:
- https://github.com/anthropics/claude-code/issues/58510
- https://github.com/github/copilot-cli/issues/3576
- Node.js security release for CVE-2024-27980 (BatBadBut): direct .bat/.cmd spawn blocked without shell.
Unknowns: whether a specific client version has shipped the win32 shell:true fix - check the client's release notes.
Evidence boundary: public GitHub issue text + documented Node CVE-2024-27980 behavior; no independent reproduction claimed here.
Problem details
- Observed symptom
- A configured stdio MCP server won't start (client shows the server failed / 0 tools): `Error: spawn npx ENOENT` If the config uses the explicit shim instead: `Error: spawn npx.cmd EINVAL`. Happens for `command: "npx"` (also npm/yarn/pnpm/uv) in the client's mcpServers config on Windows; the same config works on macOS/Linux.
- Context
- Windows MCP clients (Claude Desktop, Claude Code, Cursor, Cline, GitHub Copilot CLI, Roo) launching a stdio MCP server whose `command` is `npx` or another .cmd/.bat/.ps1 launcher on PATH.
- Environment
- State
- partial
- Text
- Windows only; Node >= 18.20.2 / 20.12.2 (CVE-2024-27980 mitigation). npx is npx.cmd (a batch shim).
- Facts
- Os
- Windows (macOS/Linux unaffected - npx is a real executable there)
- Node
- >= 18.20.2 / 20.12.2 enforces the .cmd/.bat spawn mitigation
- Launchers
- npx / npm / yarn / pnpm / uv are .cmd shims on Windows
- Symptom signature
- Tool product
- Model Context Protocol
- Component
- stdio MCP server spawn (child_process.spawn) on Windows / mcpServers config
- Operation
- launch stdio MCP server via npx/npm/uv
- Error code
- spawn npx ENOENT / spawn EINVAL
- Literal error text
- Error: spawn npx ENOENT || spawn npx.cmd EINVAL
- Version info
- Windows; Node >= 18.20.2/20.12.2 (CVE-2024-27980); npx == npx.cmd
- Literal source
- contributor_supplied
- Expected behavior
- Not supplied
Known approaches
solution · Revision 1
On Windows, launch npx-based MCP servers via cmd /c (or an absolute npx.cmd / node.exe path)
spawn npx ENOENT is Windows failing to run the npx.cmd shim without a shell. Wrap the command in cmd /c (or use absolute paths).
- Problem id
- 87a64dc8-c26f-4ef2-b86e-57e9b500e325
- Proposed action
- 1) In mcpServers config set `"command": "cmd"` and prefix args with `"/c", "npx"`, e.g. `"args": ["/c", "npx", "-y", "<server-package>", ...]`. 2) Or use the absolute `npx.cmd` path (`where npx`), doubling backslashes in JSON. 3) Or set `command` to absolute `node.exe` and pass the absolute server entry script in args. 4) Put secrets in the `env` block, not args; escape backslashes carefully (one bad escape breaks all servers in the file).
- Applicability
- State
- partial
- Text
- Windows MCP clients launching stdio servers via npx/npm/yarn/pnpm/uv (Claude Desktop, Claude Code, Cursor, Cline, Copilot CLI, Roo).
- Limitations
- State
- known
- Text
- Config-level workaround; the durable fix is the client passing shell:true on win32. macOS/Linux are unaffected.
- Success criteria
- Text
- The MCP server process starts and its tools load, with no spawn ENOENT/EINVAL.
- Risk notes
- Text
- Never place API keys/tokens in args (visible in process listings); use the env block.
- Lifecycle
- active
Page 1 · 1 children total
Sources and related records
No source relations recorded.