Quick Answer
When Claude shows "MCP failed to connect", the fastest path to the root cause is:
- Claude Desktop → open
~/Library/Logs/Claude/mcp.log(macOS) or%APPDATA%\Claude\logs\mcp.log(Windows). Find the firsterror,exit, orENOENTline before any reconnect loop starts. - Claude Code → relaunch with
claude --mcp-debugand watch stderr output, or check~/.claude/logs/if a log file is written. - Both clients → check the per-server log (
mcp-server-{name}.logfor Desktop) or capture raw server stderr to find what the server process itself printed before dying. - Test independently → run the server through MCP Inspector to confirm it works outside Claude entirely.
If you are using Claude Code specifically, see MCP Failed to Connect in Claude Code for a deeper dive into that client's behavior.
Claude MCP Failed to Connect Logs: 60-Second Checklist
Work through this in order. Stop at the first check that reveals something.
- Identify which client is failing — Claude Desktop or Claude Code. They have separate log systems, separate config files, and separate diagnostics.
- Open the main MCP log for Claude Desktop (
mcp.log). For Claude Code, relaunch with--mcp-debug. - Find the server name in the log. Claude logs which server failed before listing the error.
- Search for the first error before reconnect messages:
grep -n 'error\|exit\|ENOENT\|fail' mcp.log | head -20 - Check the per-server stderr log (
mcp-server-{servername}.log) for what the server process itself printed. - Verify the command path in your config. Run
which nodeorwhich python3in a fresh terminal — does it match what Claude would see? - Check for stdout contamination if the server uses stdio transport. Any non-JSON on stdout breaks the stream.
- Test with MCP Inspector to confirm the server works independently.
- Check HTTP status codes if the server is SSE or HTTP-based (401, 403, 404, 429, 5xx).
- Redact the log before sharing: remove API keys, tokens, file paths with usernames.
Which Claude MCP Logs Should You Check?
| Problem | Log or Diagnostic Source | What to Look For |
|---|---|---|
| Server never starts | mcp.log (Desktop) or --mcp-debug output (Code) | spawn ENOENT, command not found, non-zero exit code immediately after launch |
| Server starts but disconnects | Per-server stderr log (mcp-server-{name}.log) | Process crash output, uncaught exception stack traces |
| Tools never appear after connect | mcp.log + server stderr | Missing initialized handshake, tools/list error or empty array |
| HTTP server authentication failure | mcp.log | HTTP 401, 403 status codes, OAuth redirect responses |
| Intermittent timeouts | mcp.log | Request timeout entries, error -32001, slow response warnings |
| PATH or environment problems | mcp.log + your shell config | ENOENT, wrong Node/Python version loaded, missing env vars |
| stdout contamination (stdio) | Per-server stderr log | JSON parse errors immediately after server launch |
| Rate limiting | mcp.log or server logs | HTTP 429, Too Many Requests, exponential backoff messages |
Want to analyze your API security?
Import your OpenAPI spec and generate a Security Report automatically.
Claude Desktop MCP Log Locations
Claude Desktop produces two types of MCP logs. Know both — they answer different questions.
Main connection log (mcp.log)
This is where Claude Desktop records the connection lifecycle for all configured MCP servers: startup attempts, handshake results, transport errors, and reconnect events.
# macOS
~/Library/Logs/Claude/mcp.log
# Windows
%APPDATA%\Claude\logs\mcp.log
Tail it live while Claude starts:
# macOS / Linux
tail -f ~/Library/Logs/Claude/mcp.log
# Windows PowerShell
Get-Content "$env:APPDATA\Claude\logs\mcp.log" -Wait
Per-server stderr log (mcp-server-{name}.log)
Claude Desktop captures each server's stderr output into a separate file named after the server key in your claude_desktop_config.json.
# macOS — example for a server named "filesystem"
~/Library/Logs/Claude/mcp-server-filesystem.log
# Windows
%APPDATA%\Claude\logs\mcp-server-filesystem.log
This is where you find the server's own crash output, missing dependency errors, and startup failures that the server printed before dying.
Claude Desktop config location (for cross-referencing server names):
# macOS
~/Library/Application Support/Claude/claude_desktop_config.json
# Windows
%APPDATA%\Claude\claude_desktop_config.json
Tip: Open both
mcp.logand the relevantmcp-server-{name}.logside by side. The main log tells you when something failed; the server log tells you why.
Claude Code MCP Diagnostics
Claude Code does not write a persistent mcp.log file in the same way Claude Desktop does. MCP diagnostic output goes to the session's stderr and is controlled by debug flags.
Enable verbose MCP output:
claude --mcp-debug
This flag increases verbosity for transport events, initialization messages, and connection lifecycle. Run it in a terminal where you can see stderr directly.
Environment variable alternative:
MCP_DEBUG=1 claude
Check for session log files:
ls ~/.claude/logs/
If Claude Code writes session logs on your version, they appear here. The file naming varies by release.
List configured MCP servers:
claude mcp list
Check a specific server's status:
claude mcp get <server-name>
Remove and re-add a broken server:
claude mcp remove <server-name>
claude mcp add <server-name> -- <command> [args]
Claude Code stores MCP server configuration in ~/.claude/claude.json (global) or .claude/claude.json (project-level). Cross-reference the server name in logs against the keys in that file.
For a complete Claude Code MCP configuration reference, see Claude Code MCP Server Configuration.
Reading the Log: Finding the First Useful Error
The most common mistake when debugging MCP failures is reading the wrong part of the log. After a connection fails, Claude retries — and each retry generates more log lines. The root cause is buried before the first retry.
Find it fast:
# Show first 20 error/failure lines — the first one is almost always the cause
grep -n 'error\|Error\|exit\|ENOENT\|fail\|Fail\|exception\|Exception' \
~/Library/Logs/Claude/mcp.log | head -20
Typical log sequence for a failed stdio server:
2025-01-30T10:14:01.234Z [mcp] Starting server: filesystem
2025-01-30T10:14:01.235Z [mcp] spawn ENOENT /usr/local/bin/node ← FIRST USEFUL ERROR
2025-01-30T10:14:01.236Z [mcp] Server filesystem exited with code 1
2025-01-30T10:14:02.000Z [mcp] Retrying connection to filesystem (1/3)
2025-01-30T10:14:02.001Z [mcp] spawn ENOENT /usr/local/bin/node
2025-01-30T10:14:03.001Z [mcp] Retrying connection to filesystem (2/3)
... (repeat)
2025-01-30T10:14:05.000Z [mcp] Failed to connect: filesystem
The line spawn ENOENT /usr/local/bin/node at 10:14:01.235 is the diagnosis. Everything after it is noise.
Log Message Decoder Table
| Log Message or Symptom | Likely Cause | Next Check |
|---|---|---|
spawn ENOENT | Binary not found at the specified path | Run which node / which python3; use absolute path in config |
command not found | Shell wrapper can't locate the command | Check PATH in Claude's environment vs your shell |
Module not found / Cannot find module | Missing npm package or wrong working directory | Run npm install; check cwd in config |
Error: EACCES | Permission denied on the binary or directory | chmod +x the binary; check directory permissions |
Process exited with code 1 immediately | Server crashed on startup | Open mcp-server-{name}.log for the crash output |
Process exited with code 127 | Command not found (shell exit code) | PATH problem — use absolute binary path |
| JSON parse error on first message | stdout contamination | Remove all console.log from server startup path |
| HTTP 401 | Missing or expired auth token | Re-authorize; check OAuth token validity |
| HTTP 403 | Token valid but lacks permissions | Check scopes; verify server-side authorization |
| HTTP 404 | Wrong server URL or endpoint path | Verify the url field in your config |
| HTTP 429 | Rate limited | Back off; check server-side rate limit config |
| HTTP 5xx | Server-side crash or misconfiguration | Check server deployment logs |
Connection closed / error -32000 | Server process died after connecting | Check server stderr for crash; see How to Fix MCP Error -32000 |
Request timed out / error -32001 | Server too slow to respond | Increase timeout; profile slow operations; see How to Fix MCP Error -32001 |
| Connected but no tools listed | Handshake incomplete or tools/list returns empty | Run MCP Inspector; check server tools registration |
The Most Common Failure Causes (and How to Confirm Each)
1. PATH and Environment Variable Problems
Claude Desktop launches as a GUI application. It inherits a restricted environment — not the same PATH your terminal has. This is the single most common cause of spawn ENOENT and command not found errors.
Evidence in logs:
spawn ENOENT node
spawn ENOENT python3
Verify:
# In your terminal — find the absolute path
which node
# → /Users/you/.nvm/versions/node/v20.11.0/bin/node
which python3
# → /opt/homebrew/bin/python3
Fix: Use absolute paths in claude_desktop_config.json:
{
"mcpServers": {
"my-server": {
"command": "/Users/you/.nvm/versions/node/v20.11.0/bin/node",
"args": ["/Users/you/projects/my-mcp-server/index.js"]
}
}
}
You can also pass environment variables explicitly:
{
"mcpServers": {
"my-server": {
"command": "/opt/homebrew/bin/python3",
"args": ["-m", "my_mcp_server"],
"env": {
"API_KEY": "your-key-here",
"PYTHONPATH": "/Users/you/projects/my-mcp-server"
}
}
}
}
Confirm recovery: Restart Claude Desktop and check mcp.log — the spawn ENOENT line should be gone, replaced by a successful initialization sequence.
2. stdout Contamination (stdio Transport)
For stdio-based MCP servers, Claude reads the process's stdout as a newline-delimited JSON-RPC stream. Any non-JSON output breaks the parser immediately.
Evidence in logs:
JSON parse error: Unexpected token 'S' at position 0
Failed to parse message: "Server starting...\n"
Common culprits:
console.log("Server started")in Node.js startup- Python
print()debug statements - Third-party libraries that print banners on import
- npm package postinstall scripts printing to stdout
Fix: In Node.js servers:
// WRONG — this breaks stdio MCP transport
console.log("Server initialized");
// CORRECT — stderr is safe
console.error("Server initialized");
process.stderr.write("Server initialized\n");
In Python:
import sys
# WRONG
print("Server ready")
# CORRECT
print("Server ready", file=sys.stderr)
Confirm recovery: The JSON parse error disappears from mcp.log and the server progresses to the initialization handshake.
3. Server Process Exits Immediately
If the server exits before completing the MCP initialization handshake, Claude logs a non-zero exit code.
Evidence in logs:
[mcp] Server my-server exited with code 1
[mcp] Server my-server exited with code 127
Exit code 1 = generic error (check server stderr log for the actual exception). Exit code 127 = shell can't find the command (PATH problem).
What to do:
# Read what the server printed before dying
cat ~/Library/Logs/Claude/mcp-server-my-server.log
# Common output you'll see:
# Error: Cannot find module 'some-package'
# ModuleNotFoundError: No module named 'mcp'
# SyntaxError: Unexpected token
Fix by error type:
Cannot find module→ runnpm installin the server directory, or check thecwdconfig field points to the right directoryModuleNotFoundError→ activate the correct virtualenv; usepip installin the right environmentSyntaxError→ server code has a bug; fix the syntax error
4. MCP Initialization Handshake Failures
Even if the server process starts successfully, it must complete the MCP initialize/initialized handshake before Claude considers it connected. A server that hangs or responds incorrectly during handshake results in a timeout.
Evidence in logs:
[mcp] Initialization timeout for server: my-server
[mcp] Server my-server failed to respond to initialize request
Most common causes:
- Server is waiting for user input on stdin instead of reading JSON-RPC
- Server's initialize handler throws an uncaught exception
- Server sends the initialized notification before receiving initialize (protocol order violation)
Verify with MCP Inspector:
npx @modelcontextprotocol/inspector node /path/to/your/server.js
MCP Inspector opens a browser UI that shows the exact JSON-RPC messages exchanged. You'll immediately see if initialize/initialized is completing.
5. HTTP and Authentication Errors (SSE / HTTP Transport)
For servers using SSE or HTTP transport, Claude logs the HTTP status code. Each code points to a different problem.
Evidence in mcp.log:
[mcp] HTTP 401 connecting to https://api.example.com/mcp
[mcp] HTTP 403 connecting to https://api.example.com/mcp
[mcp] HTTP 404 connecting to https://api.example.com/mcp
401 — Unauthorized: The Authorization header is missing or the token is expired.
# Test manually
curl -H "Authorization: Bearer YOUR_TOKEN" https://api.example.com/mcp/health
Fix: Refresh the OAuth token; re-run the authorization flow; check the headers field in your MCP config.
403 — Forbidden: The token is valid but lacks required scopes or the server's authorization policy blocks the request. Check what scopes your OAuth application requested vs what the server requires.
404 — Not Found: The URL in your config is wrong, or the server path changed. Verify the exact endpoint URL with the server operator.
429 — Too Many Requests: You've hit the server's rate limit. This often happens during reconnect storms — each retry counts as a new request. Check your server's rate limit documentation and add delay between retries.
5xx — Server Error: The remote MCP server itself is crashing or misconfigured. Check the server's own deployment logs — this is outside Claude's control.
6. Server Connects but Tools Don't Appear
The hardest failure to diagnose: Claude reports the server as connected, but the tool list is empty.
Evidence in logs:
[mcp] Server connected: my-server
[mcp] tools/list returned 0 tools
Or no tools/list line at all — meaning Claude hasn't even requested tools yet.
Checklist:
- Confirm the server sends
capabilities.toolsin its initialize response - Confirm
tools/listreturns a non-empty array - Check that tool definitions have valid
name,description, andinputSchemafields - Verify the server doesn't throw during tools registration
Test with MCP Inspector:
npx @modelcontextprotocol/inspector node /path/to/server.js
Navigate to the Tools tab in the Inspector UI. If tools appear there but not in Claude, the issue is in Claude's tool rendering or a capability negotiation mismatch. If tools don't appear in Inspector either, the server's tool registration code has a bug.
Correlating Timestamps Across Logs
When you have multiple log sources — Claude's mcp.log, your server's stderr, and a deployment log from a remote service — timestamps are your alignment anchor.
Practical approach:
- Note the timestamp of the first failure in
mcp.log - Search your server's log for entries within ±5 seconds of that timestamp
- Note the timestamp of the last successful log line before the failure
# Find all log entries from both files around a specific time
grep '10:14:0[0-9]' ~/Library/Logs/Claude/mcp.log
grep '10:14:0[0-9]' ~/Library/Logs/Claude/mcp-server-my-server.log
If the server log shows a crash at 10:14:01 and Claude's log shows a disconnect at 10:14:01.300, the server crashed first — that's your root cause direction.
Testing MCP Servers Independently with MCP Inspector
Before filing a bug report or spending more time in logs, test the server directly:
# Install and run inspector
npx @modelcontextprotocol/inspector <command> [args]
# Example: Node.js server
npx @modelcontextprotocol/inspector node /path/to/server/index.js
# Example: Python server
npx @modelcontextprotocol/inspector python3 -m my_mcp_server
# Example: HTTP server
npx @modelcontextprotocol/inspector --transport sse https://my-server.com/sse
The Inspector UI shows:
- Whether initialize/initialized completes
- What tools, resources, and prompts the server exposes
- The raw JSON-RPC messages in both directions
- Any errors during tool calls
If the server fails in Inspector with the same error as in Claude, the bug is in the server. If it works in Inspector but fails in Claude, the bug is in Claude's config or environment.
Minimal Reproduction Steps
If you need to report a bug, gather these before opening an issue:
- Exact error — the first error line from
mcp.log, not the reconnect spam - Server stderr — full content of
mcp-server-{name}.log - Config excerpt — the relevant block from
claude_desktop_config.jsonor~/.claude/claude.jsonwith secrets redacted - MCP Inspector result — does the server work outside Claude?
- Versions — Claude Desktop/Code version, Node/Python version, OS version, server package version
- Reproduction steps — exact sequence to trigger the failure from a fresh Claude restart
Bug Report Checklist
Before sharing logs:
- Remove API keys, OAuth tokens, and Bearer tokens — replace with
[REDACTED_API_KEY] - Remove full file paths that contain your username — replace
/Users/yourname/with[HOME]/ - Remove any personal data from tool call arguments visible in logs
- Strip database connection strings, including passwords
- Verify no internal hostnames or IP addresses are exposed
- Confirm you're sharing only the relevant time window, not hours of log history
MCP Inspector is safer for sharing than raw logs because you can screenshot only the specific interaction, without exposing system paths or environment.
Visual: stdio MCP Connection Lifecycle
Claude Desktop
│
│ 1. Read claude_desktop_config.json
│ 2. Resolve command + args
▼
spawn(command, args)
│
├─ FAIL: spawn ENOENT → command not found → check PATH
│
▼
Child Process (MCP Server)
│ stdout → Claude reads JSON-RPC stream
│ stderr → captured to mcp-server-{name}.log
│
│ 3. Server sends: initialize request
│ 4. Server responds: initialize response + capabilities
│ 5. Claude sends: initialized notification
│
├─ FAIL: timeout → server hung or not reading stdin
├─ FAIL: parse error → stdout contaminated with non-JSON
│
▼
6. Claude requests: tools/list
│
├─ FAIL: empty array → server registered no tools
├─ FAIL: error response → server tools handler threw
│
▼
7. Tools appear in Claude UI ✓
Related Troubleshooting Resources
If this guide didn't resolve your specific failure:
- General MCP connection failures — MCP Failed to Connect: Causes and Fixes covers the full range of failure modes across all MCP clients
- Claude Desktop complete setup — Claude Desktop MCP Complete Guide includes correct configuration patterns and common setup mistakes
- Error -32000 specifically — How to Fix MCP Error -32000 Connection Closed covers the connection-closed error in detail
- Error -32001 specifically — How to Fix MCP Error -32001 Request Timed Out covers timeout diagnosis and fixes
Key Takeaways
- Claude Desktop and Claude Code have separate log systems. Never apply Desktop log paths to Code or vice versa.
- The root cause is always before the first reconnect message. Don't read the reconnect spam — grep for errors and look at the first hit.
- Per-server stderr logs (
mcp-server-{name}.log) are the most underused diagnostic. They capture what the server printed before dying. - PATH problems cause the majority of Desktop failures. GUI apps don't inherit your shell PATH. Use absolute paths.
- stdout contamination silently breaks stdio servers. Any non-JSON on stdout is a protocol violation.
- MCP Inspector is the fastest way to confirm a server works outside Claude. If it fails in Inspector too, the bug is in the server.
- Redact logs before sharing. Tokens and API keys appear in logs more often than developers expect.