MCP debugging guide

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:

  1. 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.

  2. 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:


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:

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.


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):

  1. Use the absolute path to the binary as command: jsonc { "command": "/Users/me/.nvm/versions/node/v20.11.0/bin/node", "args": ["..."] }
  2. Inject PATH via the env block 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 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:

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

Published by Hatchloop. Free MCP config linter: pip install mcp-config-lint · MCP Setup Pack →