Most MCP connection failures come down to a handful of recurring causes. Work through these in order before assuming the server itself is broken.
Wrong root key (silent failure) #
The number-one mistake when copying a config between clients. Claude Desktop, Cursor, and Cline use mcpServers; VS Code uses servers; Zed uses context_servers; Continue uses mcpServers as an array. Use the wrong key and the client ignores your config entirely, with no error. Always confirm the key matches the client before debugging anything else.
Server connects but no tools appear #
The server connected but returned an empty tools list. This usually means it requires an API key to expose its tools — some servers only return tools after a successful handshake with valid credentials. Add your auth token and reconnect.
STDIO server: stdout corruption #
The STDIO transport uses stdout exclusively for JSON-RPC messages. If any dependency or your own code writes to stdout — logging, debug output, a stray print statement — it corrupts the protocol stream and the connection fails in confusing ways. Redirect all logging to stderr.
“npx command not found” / server fails to start #
Two common culprits:
- Missing
-yflag. Always usenpx -y. The flag skips npx’s install confirmation prompt; without it, the client hangs waiting for a y/n answer that never comes. - PATH mismatch. The PATH the client sees can differ from your terminal’s, especially with version managers like nvm or pyenv. Run
which npx(orwhich node) in your terminal and use the absolute path as thecommandvalue, e.g./usr/local/bin/npx.
JSON parse error / config not loading #
JSON does not allow trailing commas or comments. A trailing comma after the last key in an object is the most common cause. Validate before restarting:
cat config.json | python3 -m json.tool
403 Forbidden on a remote server #
The Bearer token is missing, wrong, or expired. Confirm the token value and that it’s in the right header: Authorization: Bearer <token>. Some servers use a custom header instead (e.g. X-API-Key) — check the server’s documentation.
Changes not taking effect #
Some clients read config only at startup. Claude Desktop, VS Code, Zed, and Codex CLI need a full restart after edits (for Claude Desktop, that means quitting completely, not just closing the window). Cursor, Cline, and Continue hot-reload.
Production hygiene #
- Pin versions.
@latestis convenient but can break on a server’s breaking change. Once a version is validated, pin it (e.g.@modelcontextprotocol/server-github@0.6.2). - Never hardcode secrets in committed configs. Tokens in a config file sit in plaintext. Use environment variables, or VS Code’s
${input:...}prompt syntax, and gitignore any project-scoped config such as.cursor/mcp.jsonor.vscode/mcp.json.