Your MCP server was working five minutes ago. Now Claude Desktop, Claude Code, or Cursor just shows "disconnected" with no stack trace, no line number, just a red status dot.
Here's the thing: MCP servers run as a subprocess of your AI client, not as a remote service you can curl. That single fact explains almost every disconnect you'll ever see.
There are really only 4 possible causes:
1. The process never started
A relative path like ./server.py works fine in your terminal because your shell's working directory is your project folder. Your AI client launches from somewhere else entirely, so that path resolves to nothing.
Same story with npx, python, or uv. GUI apps on macOS don't inherit your shell's PATH, since they never load your .zshrc or .bash_profile.
Fix: use absolute paths for both command and args.
{
"mcpServers": {
"my-server": {
"command": "/usr/local/bin/python3",
"args": ["/Users/you/projects/my-server/server.py"]
}
}
}
Run which python3 or which node to get the real path, not a version manager shim.
2. Stdout pollution
This one gets everyone at least once. With stdio transport, stdout is reserved entirely for JSON-RPC messages. Any print(), any logging library that defaults to stdout, corrupts the stream.
# Breaks your server
print("Server starting up...")
# Fine
import sys
print("Server starting up...", file=sys.stderr)
// Breaks it
console.log("Connected to database");
// Fine
console.error("Connected to database");
Works when you run it manually but disconnects only through the client? Check your dependencies too, an ORM or framework banner logging to stdout will do the same damage.
3. Path and environment problems
GUI apps launch with a minimal environment, not the one built up by your shell profile. If your server reads an API key or DB URL from an env variable, you need to declare it explicitly in the config, even if it's already exported in your terminal.
{
"mcpServers": {
"my-server": {
"command": "/usr/local/bin/python3",
"args": ["/Users/you/projects/my-server/server.py"],
"env": {
"DATABASE_URL": "postgres://localhost/mydb",
"API_KEY": "your-key-here"
}
}
}
}
Symptom to watch for: the client briefly shows "connecting," then flips to disconnected a second later. That delay usually means the process started, then crashed on a missing env var.
4. Transport mismatch
Less common, but worth ruling out for remote or self-hosted servers. Your config might specify a url for Streamable HTTP when your server only speaks stdio, or vice versa. Looks identical to every other cause on the surface, just a red dot with no explanation.
How to actually debug it
Skip the guessing. Run the exact command from your config directly in a terminal first.
node /Users/you/projects/my-server/index.js
If it crashes here, it's your code, not MCP.
If it runs fine standalone, test it with the official MCP Inspector:
npx @modelcontextprotocol/inspector node my-server.js
This opens a browser UI showing the raw JSON-RPC traffic and lets you call each tool individually. If it works in the Inspector but still fails in your client, you've narrowed it down to config specifically, path, env vars, or working directory.
I wrote a full breakdown with a client-specific table for Claude Desktop, Claude Code, and Cursor, plus a Windows/WSL2 note, here:
🔗 https://devencyclopedia.com/blog/mcp-server-disconnected-fix
Also built a free browser tool that checks your mcp.json or claude_desktop_config.json for these exact mistakes: MCPConfigCheck
Have you hit a weirder MCP disconnect cause not covered here? Curious what else people have run into.
Top comments (0)