The Most Common claude_desktop_config.json Mistakes (and How to Fix Each)
You added an MCP server to Claude Desktop, restarted the app, and… nothing. No tools, no hammer icon, no error you can act on. The server "just doesn't show up."
Almost every time, the cause is one of a small handful of claude_desktop_config.json mistakes. This guide walks through each one — what it looks like, why it happens, and the exact fix — based on the issues people actually hit (linked at the bottom).
TL;DR: The overwhelming majority of failures are (1) a JSON syntax error, (2) editing the wrong config file, or (3) forgetting to fully restart Claude Desktop. Start there.
If you'd rather not eyeball JSON by hand, you can catch every mistake below automatically with a free linter:
pip install mcp-config-lint
mcp-config-lint # auto-detects your config and reports issues
First: where the file actually lives
A surprising number of "my config isn't working" reports are just edits to a file Claude Desktop never reads. The canonical locations are:
| OS | Path |
|---|---|
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
| Linux (preview builds) | ~/.config/Claude/claude_desktop_config.json |
The reliable way to open the right one: in Claude Desktop, go to Settings → Developer → Edit Config. That button creates the file if it doesn't exist and opens the directory Claude expects.
Now, the mistakes.
Mistake #1 — Editing the wrong config file (especially on Windows MSIX)
Symptom: You edited claude_desktop_config.json, saved, restarted — and your changes have no effect whatsoever.
Why it happens: There are two flavors of this:
-
You edited a different app's config. Claude Desktop uses
claude_desktop_config.json. Claude Code (the CLI) uses a different config and command (claude mcp add ...). They are not interchangeable. Pasting a Desktop config into Code's location, or vice versa, silently does nothing. -
The Windows MSIX virtualized-path trap. If you installed Claude Desktop via the MSIX/Microsoft Store build, there's a documented bug: the Edit Config button opens
%APPDATA%\Claude\claude_desktop_config.json, but the app actually reads from a virtualized copy under:%LOCALAPPDATA%\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming\Claude\So you edit one file and the app loads another. (anthropics/claude-code #26073)
The fix:
- Confirm you're configuring Claude Desktop, not Claude Code.
- On Windows, if edits via the button aren't taking, check the
%LOCALAPPDATA%\Packages\Claude_*\LocalCache\Roaming\Claude\path and edit the copy that's actually loaded. After a Claude Desktop update on Windows, this is also the first thing to re-check if servers that previously worked suddenly stopped. (startdebugging.net)
Mistake #2 — JSON syntax errors (the #1 silent killer)
Symptom: All of your MCP servers disappear at once — not just the one you were editing. The app loads as if the config were empty.
Why it happens: claude_desktop_config.json is strict JSON. A single syntax error invalidates the entire file, so Claude Desktop falls back to loading nothing. The usual culprits:
- Trailing commas — the last item in an object or array must not have a comma after it.
- Comments — JSON does not allow
//or/* */. Paste a config from a blog that includes comments and the parse fails. - Smart/curly quotes — copying from a webpage or doc can turn
"into"". JSON requires straight double quotes. - Unescaped backslashes in Windows paths —
"C:\Users\me\server"is invalid because\Uand\mare read as escape sequences. (See Mistake #6.) - Mismatched brackets/braces.
Example of a broken config:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/Documents"], // ← comment not allowed
} // ← trailing comma above breaks the parse
}
}
The fix: Run the file through any JSON validator before restarting. On the command line:
# macOS / Linux
python3 -m json.tool < ~/Library/Application\ Support/Claude/claude_desktop_config.json
# Windows PowerShell
Get-Content "$env:APPDATA\Claude\claude_desktop_config.json" -Raw | ConvertFrom-Json
If it parses without error, your syntax is clean. mcp-config-lint does this plus the semantic checks below in one pass and points at the exact line.
Mistake #3 — Not fully restarting Claude Desktop
Symptom: You fixed the config, but the change still hasn't taken effect.
Why it happens: Closing the window doesn't quit the app — Claude Desktop keeps running in the system tray / menu bar. MCP servers are only spawned at startup, and the config (including the env block) is read once and cached. Editing it while the app is running does nothing until a full relaunch. (apxml.com)
The fix: Quit completely, then reopen.
- macOS: ⌘Q (or right-click the Dock icon → Quit). Closing the window is not enough.
- Windows: Right-click the tray icon → Quit, or end the process in Task Manager, then relaunch.
Mistake #4 — spawn npx ENOENT on Windows (bare npx / node)
Symptom: The server fails to start; the log shows spawn npx ENOENT (or spawn node ENOENT).
Why it happens: On Windows, npx is a batch shim (npx.cmd). The low-level process spawn Claude Desktop uses only resolves .cmd/.bat files via PATHEXT when shell: true is set — which it isn't for stdio servers. So a bare "command": "npx" can't be found even though npx works fine in your terminal. (tomaspavlin/rohlik-mcp #6, fransiscuss.com)
The fix: Wrap the command in cmd /c so Windows' command interpreter resolves the shim:
// ❌ Fails on Windows with spawn ENOENT
{
"mcpServers": {
"context7": {
"command": "npx",
"args": ["-y", "@upstash/context7-mcp"]
}
}
}
// ✅ Works on Windows
{
"mcpServers": {
"context7": {
"command": "cmd",
"args": ["/c", "npx", "-y", "@upstash/context7-mcp"]
}
}
}
Alternative: point command at the absolute path to npx/node (e.g. C:\\Program Files\\nodejs\\npx.cmd). The cmd /c wrapper is more portable across machines.
Mistake #5 — Relative paths instead of absolute paths
Symptom: The server starts but can't find its script, or the filesystem server can't see the directory you intended.
Why it happens: Claude Desktop spawns servers from its own working directory, not the folder you think you're "in." A relative path like ./build/index.js or server.py resolves against the wrong base and fails. (modelcontextprotocol.io)
The fix: Use absolute paths everywhere — for the command, the script argument, and any directory arguments.
// ❌ Relative — breaks
{ "command": "node", "args": ["build/index.js"] }
// ✅ Absolute
{ "command": "node", "args": ["/Users/me/projects/my-server/build/index.js"] }
Mistake #6 — Unescaped backslashes in Windows paths
Symptom: JSON parse failure, or a path that's subtly wrong.
Why it happens: In JSON strings, \ starts an escape sequence. A Windows path pasted verbatim — "C:\Users\me\node_modules" — contains \U, \m, \n which are either invalid or silently mangled (\n becomes a newline!).
The fix: Escape every backslash as \\, or use forward slashes (Node and most tools accept them on Windows):
// ❌
{ "args": ["C:\Users\me\server\index.js"] }
// ✅ escaped
{ "args": ["C:\\Users\\me\\server\\index.js"] }
// ✅ forward slashes also work
{ "args": ["C:/Users/me/server/index.js"] }
Mistake #7 — Node/binary not on the PATH Claude sees
Symptom: spawn node ENOENT / spawn docker ENOENT even though the command works perfectly in your terminal. Common with nvm, asdf, mise, or Homebrew-installed runtimes.
Why it happens: A GUI app launched from Finder/Start menu does not inherit the PATH from your shell profile (.zshrc, .bashrc). Version managers install runtimes into directories that only get added to PATH by those shell init files — which Claude Desktop never sources. So the binary exists, but Claude can't find it. (emmanuelbernard.com)
The fix (pick one):
- Use the absolute path to the binary as
command:jsonc { "command": "/Users/me/.nvm/versions/node/v20.11.0/bin/node", "args": ["..."] } - Inject
PATHvia theenvblock so the server can find its peers:jsonc { "command": "node", "args": ["/abs/path/server.js"], "env": { "PATH": "/Users/me/.nvm/versions/node/v20.11.0/bin:/usr/local/bin:/usr/bin:/bin" } }
Run which node (macOS/Linux) or where node (Windows) in your terminal to get the absolute path to paste.
Mistake #8 — Misplaced or malformed env block
Symptom: The server starts but behaves as if its API key / environment variable is missing.
Why it happens: Several variations:
- The
envobject is placed at the top level or alongsidemcpServers, instead of inside the individual server's object. - Values are non-strings. Every value in
envmust be a JSON string —"PORT": "3000", not"PORT": 3000. - Case mismatch. Env var names are case-sensitive;
Github_Token≠GITHUB_TOKEN. - The variable simply isn't passed and you assumed the server would inherit it from your shell — it won't, for the same PATH reason as #7. (anthropics/claude-code #1254)
The fix: Nest env inside the server, use string values, and match names exactly:
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_xxxxxxxxxxxx"
}
}
}
}
Mistake #9 — Wrong top-level key (mcpServers typo)
Symptom: Valid JSON, app restarts fine, but no servers ever appear.
Why it happens: The top-level key must be exactly mcpServers (camelCase, plural). Common misspellings — mcp_servers, mcpServer, MCPServers, servers — are valid JSON, so nothing errors. Claude Desktop just looks for mcpServers, doesn't find it, and loads zero servers.
The fix: Verify the outer structure:
{
"mcpServers": { // ← exactly this key
"my-server": { ... }
}
}
The same applies to each server's required keys: command is mandatory; args and env are optional but must be spelled correctly.
Mistake #10 — Server name collisions and duplicate keys
Symptom: One of two configured servers silently doesn't load, or you get unpredictable behavior.
Why it happens: JSON object keys must be unique. If you copy-paste a server block and forget to rename it, you'll have two "filesystem" entries — JSON parsers keep only the last one, so the first is silently dropped.
The fix: Give every server under mcpServers a unique name.
A known-good reference config
Here's a complete, valid claude_desktop_config.json that avoids every mistake above (Windows-safe cmd /c, absolute paths, properly nested env):
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/Users/me/Documents"
]
},
"github": {
"command": "cmd",
"args": ["/c", "npx", "-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_xxxxxxxxxxxx"
}
}
}
}
On macOS/Linux, drop the
"cmd", "/c"wrapper — use"command": "npx"directly. It's only needed on Windows.
How to debug when it's still broken
When a server won't load, check the per-server logs. Claude Desktop writes one file per server:
- macOS:
~/Library/Logs/Claude/mcp-server-SERVERNAME.log - Windows:
%APPDATA%\Claude\logs\mcp-server-SERVERNAME.log
These contain the server's stderr — the actual stack trace or ENOENT line that tells you which mistake you're hitting. (Corcava troubleshooting)
A faster first pass is to lint the config before you even restart:
pip install mcp-config-lint
mcp-config-lint --strict
mcp-config-lint is a free, open-source checker that catches all ten mistakes above — invalid JSON, wrong top-level key, relative paths, unescaped Windows backslashes, bare npx on Windows, misplaced env blocks, duplicate server names, and non-string env values — and prints the exact line and fix. Running it before each restart turns the usual "edit → quit → relaunch → guess" loop into a single check.
If you'd rather skip configuring from scratch entirely, the Hatchloop MCP Setup Pack ($15) ships 22 pre-validated claude_desktop_config.json setups (filesystem, GitHub, Postgres, Puppeteer, and more) — each one already cross-platform, absolute-pathed, and lint-clean — so you can paste a known-good block instead of debugging your own.
FAQ
Why do all my MCP servers disappear when I only changed one? A single JSON syntax error invalidates the whole file, so Claude Desktop loads zero servers. Validate the JSON (Mistake #2).
My config works in Claude Code but not Claude Desktop (or vice versa).
They use different config files and formats. Claude Code uses claude mcp add; Claude Desktop uses claude_desktop_config.json. Configure the right one (Mistake #1).
I get spawn npx ENOENT on Windows but npx works in my terminal.
Wrap the command in cmd /c (Mistake #4). Windows can't resolve the npx.cmd shim through the raw spawn Claude Desktop uses.
My API key in env isn't being picked up.
Make sure env is nested inside the server object, all values are strings, and you fully quit and relaunched the app (Mistakes #8 and #3).
Where are the logs?
~/Library/Logs/Claude/ on macOS, %APPDATA%\Claude\logs\ on Windows — one mcp-server-*.log per server.
Sources
- Connect to local MCP servers — modelcontextprotocol.io
- Windows MSIX: "Edit Config" opens wrong file — anthropics/claude-code #26073
- Env variables from
envsection not passed — anthropics/claude-code #1254 - MCP fails to spawn npx (ENOENT) — tomaspavlin/rohlik-mcp #6
- Fixing "spawn npx ENOENT" on Windows 11 — fransiscuss.com
- MCP Servers, Claude Desktop and fun with PATHs — emmanuelbernard.com
- Environment Variable Management in MCP — apxml.com
- MCP server not showing up — Corcava troubleshooting
- Fix: MCP servers stop working after a Claude Desktop update on Windows — startdebugging.net
Published by Hatchloop. Free MCP config linter: pip install mcp-config-lint · MCP Setup Pack →