MCP Server spawn ENOENT — Fix for npx, uvx, and Node
Quick fix: spawn ENOENT means Claude Desktop cannot find the executable you put in the command field. Run which npx (macOS/Linux) or where npx (Windows) in your terminal, then replace "npx" in your config with that full absolute path. Restart Claude Desktop (Cmd+Q, not Cmd+W).
In this guide
Why spawn ENOENT happens
ENOENT is the Unix/POSIX error code for "No such file or directory". When you see spawn ENOENT in an MCP server log, it means the operating system's execvp call failed because the binary you specified does not exist at that path or on any directory in the process's PATH.
Claude Desktop launches MCP servers using child_process.spawn() in Node.js with a minimal inherited environment. On macOS and Linux, the PATH available to Claude Desktop typically contains only /usr/bin, /bin, and /usr/sbin. It does not contain:
- Homebrew paths (
/usr/local/bin,/opt/homebrew/bin) - nvm shim directories (
~/.nvm/versions/node/vX/bin) - pyenv paths (
~/.pyenv/shims) - uv/uvx paths (
~/.local/bin) - npm global bin (
~/.npm/bin,~/AppData/Roaming/npmon Windows)
So even though npx works in your terminal, Claude Desktop cannot find it.
Confirm this is your error
# macOS tail -20 ~/Library/Logs/Claude/mcp-server-SERVERNAME.log # Windows Get-Content "$env:APPDATA\Claude\logs\mcp-server-SERVERNAME.log" -Tail 20 # Linux tail -20 ~/.config/Claude/logs/mcp-server-SERVERNAME.log
You will see something like:
Error: spawn npx ENOENT
at ChildProcess._handle.onexit (node:internal/child_process:285:19)
at onErrorNT (node:internal/child_process:483:16)
Or on Windows:
Error: spawn uvx ENOENT
at Process.ChildProcess._handle.onexit
Fix on macOS
# Find the absolute path to npx which npx # Intel Mac (system Node): /usr/local/bin/npx # Apple Silicon (Homebrew): /opt/homebrew/bin/npx # nvm: something like /Users/you/.nvm/versions/node/v20.0.0/bin/npx # Find uvx if you use Python MCP servers which uvx # Usually: /Users/you/.local/bin/uvx
Update your config:
{
"mcpServers": {
"filesystem": {
"command": "/opt/homebrew/bin/npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/you/projects"]
},
"git": {
"command": "/Users/you/.local/bin/uvx",
"args": ["mcp-server-git", "--repository", "/Users/you/myrepo"]
}
}
}
nvm use to switch Node versions, so a hardcoded path like ~/.nvm/versions/node/v20.0.0/bin/npx will break silently after an upgrade. Use nvm which node to get the currently active binary path, or install a system Node via Homebrew and use that stable path instead.
Fix on Windows
# PowerShell - find npx where npx # Typically: C:\Users\you\AppData\Roaming\npm\npx.cmd # If multiple results, use the .cmd version
Update your config, using forward slashes and npx.cmd:
{
"mcpServers": {
"filesystem": {
"command": "C:/Users/you/AppData/Roaming/npm/npx.cmd",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "C:/Users/you/projects"]
}
}
}
npx almost always triggers spawn ENOENT on Windows even if npx is on your PATH, because .cmd extensions are not resolved in the same way. Always use npx.cmd or the full absolute path.
Fix on Linux
# Find paths which npx # e.g. /usr/local/bin/npx or /usr/bin/npx which uvx # e.g. /home/you/.local/bin/uvx which node # e.g. /usr/bin/node
If Node.js was installed via nvm, the path will look like: /home/you/.nvm/versions/node/v20.11.1/bin/npx. Use the full path from which npx.
uvx not found / spawn uvx ENOENT
If which uvx returns nothing, uv (the package manager that provides uvx) is not installed. Install it:
# macOS/Linux curl -LsSf https://astral.sh/uv/install.sh | sh # Windows (PowerShell) powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
After installing, open a new terminal (the installer modifies your shell profile and the current session needs to reload it), then run which uvx again and use that absolute path in your config.
Preventing future spawn ENOENT errors
The pattern that causes this is fragile: the config depends on binaries installed at paths that could change. A more durable approach:
| Scenario | Resilient approach |
|---|---|
| Node.js via nvm | Install a system-level Node.js (e.g. via Homebrew) alongside nvm; use the system binary path in MCP config |
| Multiple Node versions | Set a default with nvm alias default 20 and use the stable path |
| Python/uv tools | Run which uvx after every uv upgrade to confirm the path has not changed |
| CI or shared configs | Use mcp-config-lint in CI to catch bare commands before they reach production |
Catch bare commands automatically: the MCP Config Auditor flags every bare command in your config that will cause spawn ENOENT. Paste your config, get a per-server report. 100% client-side.
CLI option: pip install mcp-config-lint && mcp-config-lint — reports bare commands, placeholder tokens, and JSON errors in one pass.
FAQ
spawn ENOENT means the operating system could not find the binary specified in command. ENOENT = No such file or directory. Claude Desktop uses a restricted PATH that does not include Homebrew, nvm, pyenv, or npm global bin directories. Use the absolute path from which npx instead of bare npx.
Run which npx on macOS/Linux or where npx on Windows. Common paths: /usr/local/bin/npx (Intel Mac), /opt/homebrew/bin/npx (Apple Silicon), C:/Users/NAME/AppData/Roaming/npm/npx.cmd (Windows). Replace "npx" in your config with that full path. On Windows use npx.cmd.
Run which uvx — usually /Users/NAME/.local/bin/uvx or /home/NAME/.local/bin/uvx. If uvx is not installed, install uv: curl -LsSf https://astral.sh/uv/install.sh | sh. Then use the absolute path in your config.
Your terminal session has a rich PATH set by your shell profile (.bashrc, .zshrc) that includes nvm, Homebrew, etc. Claude Desktop spawns child processes with a minimal system PATH that does not include those directories. The fix is always the same: use the absolute path.