MCP error -32000: Connection closed
Claude Code Last checked 2026-10-14
The MCP server process died or never started — the client is reporting a dead pipe, not a network problem. In almost every case the command in your config cannot be found or exits immediately. Run the exact command from your config in a terminal; whatever it prints is the real error.
What you saw
MCP error -32000: Connection closed
A server that shows as failed in claude mcp list, or disappears from the tools list entirely. In Claude Desktop the server appears in settings but never turns on. In Cursor the MCP entry shows a red dot.
The error text carries no cause. It is the JSON-RPC client saying "the thing I was talking to on stdin/stdout is gone" — the useful message is whatever the server printed before it died, which the client usually swallows.
What it actually means
A local (stdio) MCP server is just a child process. The client spawns command with args, then speaks JSON-RPC over that process's stdin and stdout. If the process exits — at startup, or later — the client sees a closed pipe and reports -32000: Connection closed.
So -32000 is a symptom of process death, not a connection or firewall problem. The four usual causes, in order of how often they are the answer: the command is not on the PATH the client uses (spawn npx ENOENT, spawn uv ENOENT); the server crashes on startup because a required env var or API key is missing; the server writes logging to stdout, which corrupts the JSON-RPC stream; or claude_desktop_config.json / .mcp.json is malformed and the entry never launches properly.
The PATH case catches almost everyone on macOS. A GUI app launched from Finder or the Dock does not inherit the PATH from your shell profile, so npx, uv, bun and anything installed by nvm or Homebrew may be invisible to it even though they work fine in your terminal.
Stdout is reserved. For a stdio MCP server, anything a dependency prints to stdout — a banner, a deprecation warning, a console.log — lands in the middle of the protocol stream. Some clients drop the connection the moment they see a non-JSON line.
The fix
Run the exact command from your config, by hand, in a terminal. This is the whole debugging step — the error you get here is the real error.
npx -y @modelcontextprotocol/server-filesystem /Users/you/projects
If that fails with ENOENT or "command not found", replace the command with an absolute path. Find it with which, then paste the result into the config.
which npx
# -> /Users/you/.nvm/versions/node/v22.14.0/bin/npx
"mcpServers": {
"filesystem": {
"command": "/Users/you/.nvm/versions/node/v22.14.0/bin/npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/you/projects"]
}
}
In Claude Code, get the client's own view instead of guessing. --debug surfaces the server's stderr, which is where the real message is hiding.
claude mcp list
claude mcp get myserver
claude --debug
In Claude Desktop, read the log file for that server. Each server gets its own file named after it.
# macOS
tail -n 100 ~/Library/Logs/Claude/mcp-server-filesystem.log
# Windows (PowerShell)
Get-Content "$env:APPDATA\Claude\logs\mcp-server-filesystem.log" -Tail 100
Validate the config file itself. One trailing comma and the whole file is ignored — which looks identical to a server that will not start.
python3 -m json.tool ~/Library/Application\ Support/Claude/claude_desktop_config.json
If the server starts by hand but dies under the client, check for missing environment. GUI clients do not see your shell exports; pass secrets explicitly in the env block.
"env": { "GITHUB_TOKEN": "ghp_...", "PATH": "/opt/homebrew/bin:/usr/bin:/bin" }
If you wrote the server: send every log line to stderr, never stdout. In Python, print() defaults to stdout and will break the protocol.
# Node
console.error("starting"); // not console.log
# Python
import sys
print("starting", file=sys.stderr)
Quit the client completely and relaunch — not just close the window. On macOS use Cmd-Q or Claude → Quit; closing the window leaves the old process and the old config in memory.
How to stop it happening again
Use absolute paths for command in every MCP config. It costs you one which call and removes the single most common cause of this error permanently.
Keep one known-good server (the filesystem server is a good choice) in your config. If it also fails, the problem is the client or the config file, not the server you just added.
Never let a stdio server print to stdout. If you maintain one, add a test that pipes a tools/list request in and asserts the first byte of output is {.
After editing claude_desktop_config.json or .mcp.json, validate it with json.tool before restarting. Malformed JSON fails silently.
Pin server versions in args (@modelcontextprotocol/server-filesystem@2026.6.0) so an upstream release cannot break a working setup overnight — npx -y without a version pulls the latest every launch.
Related questions
Does -32000 mean my network or firewall is blocking something?
Not for a local stdio server — there is no network involved, only a child process and two pipes. For a remote HTTP/SSE server the same code can mean the connection dropped, in which case check the URL, the auth token and whether the endpoint is actually reachable with curl.
Why does it work in my terminal but not in Claude Desktop?
Because the app does not inherit your shell's PATH. Anything installed via nvm, Homebrew, pyenv or uv is often invisible to a GUI-launched app. Use absolute paths, or set PATH explicitly in the server's env block.
The server connects but the tools never appear. Same problem?
No. If the connection is up, you are hitting a different issue — usually too many tools loaded across all servers, or a tools/list that errors. Check claude mcp list for the server's actual status before assuming it is -32000.
Where are the Claude Desktop MCP logs?
macOS: ~/Library/Logs/Claude/ — one mcp-server-NAME.log per server plus a general mcp.log. Windows: %APPDATA%\Claude\logs\. The client's own error message is almost never useful; these files are.
I use Cursor, not Claude. Does this apply?
Yes. Cursor spawns stdio MCP servers the same way, from .cursor/mcp.json, and reports the same JSON-RPC error codes. The PATH, stdout and malformed-JSON causes are identical.