How to Fix Silent MCP Server Failures in Claude Desktop (spawn ENOENT, uvx not found, Windows paths)
If your MCP server is not showing up in Claude Desktop, the most likely cause is a PATH problem: Claude Desktop launches servers in a restricted shell that does not inherit your terminal's PATH, so bare commands like npx or uvx are invisible to it. The fix is to use the absolute path in the command field. Below are all six silent failure modes, each with the exact fix.
On this page
1. spawn ENOENT — server never starts
Symptom: No tools icon. MCP logs say spawn ENOENT or Error: spawn npx ENOENT.
Why it happens: Claude Desktop spawns MCP servers as child processes using a minimal shell environment. It does not inherit the PATH your terminal sees. Any command installed via Homebrew, nvm, pyenv, asdf, or a user-level package manager is invisible from inside Claude Desktop.
Fix — use the absolute path in the command field:
// Find the path first: which npx # macOS / Linux where npx # Windows PowerShell // Then use it in your config: { "mcpServers": { "filesystem": { "command": "/usr/local/bin/npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/you/projects"] } } }
~/.nvm/versions/node/v20.x.x/bin/npx. Run which npx after activating the right node version to get the exact path for your machine.
For uvx:
which uvx # typically one of: # /home/you/.local/bin/uvx (Linux) # /opt/homebrew/bin/uvx (macOS via Homebrew)
2. uvx not found — uv is not installed
Symptom: Servers using uvx (git, sqlite, sentry, time, fetch, redis) never start. Logs show uvx: command not found or spawn uvx ENOENT.
Why it happens: uvx ships as part of the uv package manager, which is separate from pip or Python itself. If you have not installed uv, every server that uses uvx will silently fail.
Fix — install uv:
# 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, restart your terminal, run which uvx, and add that absolute path to your config. Then restart Claude Desktop.
3. npx vs uvx — using the wrong runtime
Symptom: The command is there but the server never starts. The log shows a package-not-found error, or the wrong package manager tries to install a package it cannot find.
Why it happens: MCP servers are distributed through two separate ecosystems. npm servers need npx. Python/uv servers need uvx. Using the wrong one silently fails.
| Runtime | Servers |
|---|---|
npx |
filesystem, github, postgres, slack, memory, playwright, puppeteer, brave-search, google-maps, google-drive, sequential-thinking, context7, linear, everything |
uvx |
git, sqlite, sentry, time, fetch, redis |
Quick rule: if the package name starts with @modelcontextprotocol/server- and is on npm, use npx. If it starts with mcp-server- and is on PyPI, use uvx.
// npx server (npm): { "github": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"], "env": {"GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_..."} } } // uvx server (Python/uv): { "git": { "command": "uvx", "args": ["mcp-server-git", "--repository", "/home/you/myrepo"] } }
4. Windows path escaping
Symptom: On Windows, filesystem, git, or SQLite server starts but errors on any path operation. Or servers fail to start at all because the config is invalid.
Why it happens: JSON requires backslashes to be escaped as \\, but many MCP servers also parse Windows-style paths unreliably. A single unescaped backslash silently invalidates your entire config file.
Fix — use forward slashes everywhere on Windows:
{
"mcpServers": {
"filesystem": {
"command": "C:/Users/you/AppData/Roaming/npm/npx.cmd",
"args": ["-y", "@modelcontextprotocol/server-filesystem",
"C:/Users/you/projects"]
}
}
}
npx may fail because the actual executable is npx.cmd. If npx gives spawn ENOENT on Windows, switch to npx.cmd or use the full path.
Validate your JSON before restarting Claude Desktop — one bad comma or backslash silently disables all servers:
# PowerShell
Get-Content "$env:APPDATA\Claude\claude_desktop_config.json" | ConvertFrom-Json
If that throws an error, your JSON is invalid. Fix it before restarting.
5. Config not loading — no tools icon at all
You edited the config, restarted Claude Desktop, and the hammer icon (tools) never appears. Five causes in order of likelihood:
- 5a. Wrong file location
- The config must be at the exact OS-specific path. macOS:
~/Library/Application Support/Claude/claude_desktop_config.json— Windows:%APPDATA%\Claude\claude_desktop_config.json— Linux:~/.config/Claude/claude_desktop_config.json.
Open it directly to confirm you are editing the right file:
macOS:open ~/Library/Application\ Support/Claude/claude_desktop_config.json
Windows:notepad "$env:APPDATA\Claude\claude_desktop_config.json" - 5b. JSON syntax error
- A trailing comma, a missing brace, or an unescaped character silently disables every server. Validate at jsonlint.com or with the PowerShell command above.
- 5c. Did not fully quit Claude Desktop
- On macOS, Cmd+W closes the window but leaves the process running. Use Cmd+Q, or right-click the Dock icon and choose Quit. On Windows, right-click the system tray icon and choose Quit.
- 5d. Incorrect JSON structure
- Servers must be nested inside
"mcpServers"at the top level:
{ "mcpServers": { "server-name": { "command": "...", "args": [] } } } - 5e. Empty or placeholder env var
- If a server requires an API key and the value is an empty string
""or a literal like"your-token-here", the server starts and immediately crashes with no visible error in the UI. Either fill in a real value or remove theenvblock entirely if you are not using that server yet. The free auditor catches these automatically.
6. Tools appear but every call fails or returns empty
Symptom: The tools icon is there. Claude acknowledges the tool. But every call returns empty, times out, or gives a generic error.
The server started successfully but is failing at runtime. The first step is always to read the log file for that server (see below). Common runtime causes:
| Server | Symptom | Fix |
|---|---|---|
| filesystem | path errors on any operation | The path in args must exist and be absolute |
| sqlite | database errors | Create the file first: touch /path/to/file.db |
| postgres | connection refused | Test outside Claude: psql postgresql://user:pass@host/db |
| playwright | browser launch fails | Run npx playwright install chromium once in a terminal |
| google-drive | auth errors | OAuth token expired — delete token.json and re-run the server manually |
| redis | AUTH required / connection errors | Use redis://:password@host:6379 format in REDIS_URL |
| github | 403 or empty results | Fine-grained PAT needs Contents: Read, Issues: Read, Metadata: Read minimum |
| puppeteer / npx servers | first run timeout | Pre-download: run the server command manually first, wait for it to finish, then Ctrl+C |
| sentry | 401 unauthorized | Use an org auth token from sentry.io/settings/auth-tokens, not a user API token |
| supabase | auth errors | --access-token must be a personal access token (starts sbp_), not an anon or service role key |
How to read the MCP server logs
Most developers skip this step. Each MCP server gets its own log file and the errors there are almost always more specific than anything Claude shows in the chat UI.
# macOS ls ~/Library/Logs/Claude/ tail -50 ~/Library/Logs/Claude/mcp-server-filesystem.log # Windows (PowerShell) ls "$env:APPDATA\Claude\logs\" Get-Content "$env:APPDATA\Claude\logs\mcp-server-filesystem.log" -Tail 50 # Linux ls ~/.config/Claude/logs/ tail -50 ~/.config/Claude/logs/mcp-server-filesystem.log
Look for: Python tracebacks, lines containing Error:, ENOENT, EACCES, ModuleNotFoundError, or HTTP 401/403 responses.
Catch all of these in one command
mcp-config-lint is a CLI tool that reads your claude_desktop_config.json and reports every issue in one pass: bare commands that will cause spawn ENOENT, npx/uvx mismatches, placeholder tokens, empty required env vars, JSON syntax errors, and relative paths.
pip install mcp-config-lint mcp-config-lint
Drop it in a pre-commit hook or a GitHub Actions step to keep shared configs valid in CI.
If you prefer a browser-based check with a per-server visual report card: hatchloop.dev/tools/mcp-audit/ — paste your config, get an instant report. 100% client-side, nothing leaves your browser.
Setting up multiple servers from scratch rather than debugging? The $15 MCP Setup Pack includes pre-validated configs for all 22 official servers plus the credential setup guide for each, so you skip the trial-and-error on first install.
FAQ
spawn ENOENT means Claude Desktop cannot locate the executable in the command field. Claude Desktop spawns servers in a minimal shell that does not inherit your terminal's PATH, so tools installed via Homebrew, nvm, pyenv, or asdf are invisible. Fix: use the absolute path. Run which npx (macOS/Linux) or where npx (Windows) to get it, then use that full path in command.
Use npx for npm packages: all @modelcontextprotocol/server-* servers (filesystem, github, postgres, slack, memory, playwright, puppeteer, brave-search, google-maps, sequential-thinking, context7, linear, and others).
Use uvx for Python/uv packages: git (mcp-server-git), sqlite (mcp-server-sqlite), sentry (mcp-server-sentry), time (mcp-server-time), fetch (mcp-server-fetch), redis (mcp-server-redis). If the package is on PyPI rather than npm, it needs uvx.
Use forward slashes everywhere. C:/Users/you/projects works in JSON without any escaping. If you use backslashes, double them: C:\\Users\\you\\projects — a single backslash silently breaks the JSON and disables all your servers.
Also: on Windows the npx executable is actually npx.cmd. If bare npx gives spawn ENOENT, switch to npx.cmd or use the full absolute path.
Most likely causes: (1) you edited the wrong file — confirm the config is at the exact OS-specific path; (2) your JSON has a syntax error — validate at jsonlint.com; (3) you did not fully quit Claude Desktop — on macOS use Cmd+Q, on Windows right-click the tray icon; (4) you have a placeholder env var value like "your-token-here" that causes the server to crash silently on startup.
macOS: ~/Library/Logs/Claude/mcp*.log
Windows: %APPDATA%\Claude\logs\mcp*.log
Linux: ~/.config/Claude/logs/mcp*.log
Each server gets its own log file. Open it and look for Python tracebacks, ENOENT, EACCES, or HTTP 401/403 messages. This is almost always more informative than anything the chat UI shows.
The server started but is failing at runtime. Check the MCP log file for that server. Common causes: the path given to filesystem does not exist; the SQLite .db file has not been created yet; Playwright Chromium is not installed (run npx playwright install chromium once); a database connection string is malformed; a Google Drive OAuth token has expired (delete token.json and re-authorize); a GitHub token is missing a required permission scope.
Install uv (which provides uvx):
macOS/Linux: curl -LsSf https://astral.sh/uv/install.sh | sh
Windows: powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
After installing, restart your terminal, run which uvx to get the absolute path, put that path in the command field of your MCP config, and restart Claude Desktop.
Run pip install mcp-config-lint then mcp-config-lint. It parses your claude_desktop_config.json and reports: bare commands that will cause spawn ENOENT, npx/uvx mismatches, placeholder or empty env vars, JSON syntax errors, and relative paths. You can also run it in CI to keep shared configs valid.
For a visual per-server report in the browser: hatchloop.dev/tools/mcp-audit/ — paste your config and get an instant report. Nothing leaves your browser.