Claude MCP Server Keeps Disconnecting: Fix It for Good

MCP server connects then drops in Claude Desktop or Claude Code — fix the stdio crash, OAuth expiry, config path, or 60s startup timeout.

You launch Claude Desktop or Claude Code, see your MCP server appear in the tools list, and a minute or two later it greys out as “disconnected.” You reconnect, it works briefly, then drops again. This is the classic Claude MCP (Model Context Protocol) integration failure, and as of June 2026 the root cause is almost always one of: the local server process crashed, the startup blew past Claude’s ~60-second init window, an OAuth token expired, or the config points at the wrong path or Node binary.

Fastest fix (90% of cases): open the logs, find the line right after the disconnect, and match it to the table below. If you see exited with code 1 it’s a server crash; ENOENT / EACCES is a path/permission bug; Server transport closed ~60s after launch is a startup timeout; a 401 on tool calls is an expired token. Read once, fix once.

One thing worth knowing before you start: MCP is not an HTTP long-poll. For a local (stdio) server, Claude spawns a subprocess and talks to it over stdin/stdout. Stdio servers are not auto-reconnected — if the subprocess dies, the tool stays dead until you relaunch or reconnect. HTTP and SSE servers do auto-reconnect (Claude Code retries with exponential backoff, up to five attempts), so a stdio failure and a remote failure look the same in the UI but need different fixes.

Which bucket are you in?

Find the log line that appears right after the disconnect and jump to the matching fix.

Log / symptomMost likely causeGo to
exited with code 1, killed, or a stack traceServer process crashed / OOM-killedStep 2 + Step 3
Server transport closed ~60s after launch, no errorStartup exceeded the ~60s init windowStep 4
ENOENT: no such file or directoryWrong / relative path in configStep 2
EACCES: permission deniedClaude can’t read the file or dirStep 2
Tool calls return 401 / unauthorizedOAuth token expired, no auto-refreshStep 5
Drops on a regular 30s / 60s clock, remote onlyCorporate proxy cuts long-lived connectionsStep 6
Cannot find module / Unexpected tokenNode/Python version mismatchStep 7
Every server fails right after initializeClaude Desktop / OS-level bugSee FAQ

Common causes, by hit rate

1. Local stdio server crashes or gets OOM-killed

Stdio MCP servers are Node or Python subprocesses Claude spawns. They get OOM-killed, throw on an uncaught exception, or fail to start under the wrong runtime version. Because stdio servers don’t auto-reconnect, one crash means the tool is gone for the rest of the session.

How to spot it: in the logs, exited with code 1, killed, or a stack trace.

2. Startup exceeds the ~60-second init window

This is the most under-diagnosed cause. Claude waits roughly 60 seconds for a stdio server to finish initializing. Servers that download heavy dependencies on first run blow past it — a Puppeteer server pulling Chromium (~180 MB), a Python server resolving packages, or any npx-launched server doing a cold npm install. The log shows Server transport closed about 60s in with no actual error.

How to spot it: the disconnect lands ~60s after launch, the first run is slow but later runs are fine (or vice versa if a cache got cleared), and the server is npx- or container-launched.

3. Wrong path or permissions in the config

The most common local gotcha. The args use a relative path, point at a file that doesn’t exist, or live in a directory Claude can’t read.

How to spot it: ENOENT: no such file or directory or EACCES: permission denied in the logs.

4. OAuth token expired and the server didn’t refresh

Remote MCPs (the official Notion, Sentry, GitHub, Asana servers) authenticate with OAuth or a bearer token. When the token expires and the implementation doesn’t auto-refresh, the connection looks live but every tool call returns 401.

How to spot it: tool calls return unauthorized / 401; re-running the OAuth flow fixes it.

5. Node / Python version mismatch

MCP servers generally need Node 18+ (Node 22 LTS recommended as of 2026) or Python 3.10+, but the first node on your PATH is older — for example a stock system Node. Claude inherits PATH, so the subprocess fails to start.

How to spot it: Cannot find module, Unexpected token, or a syntax error on a modern-JS feature. Confirm with which node && node -v.

6. Corporate network cuts the connection

Remote MCP over HTTP/SSE rides on a long-lived connection. Enterprise proxies and firewalls drop idle long-lived connections on a fixed interval.

How to spot it: the drop interval is suspiciously regular (every 30s or 60s) and only remote servers are affected.

7. macOS firewall blocked the server’s first launch

The first time a new local server tries to open a socket, macOS prompts “allow incoming connections.” If you hit Deny by reflex, it silently fails from then on.

How to spot it: System Settings → Network → Firewall → Options shows Claude or the server explicitly blocked.

Shortest path to fix

Step 1: Read the logs first

Don’t guess — the disconnect line tells you which fix to run.

Claude Desktop:

macOS:   ~/Library/Logs/Claude/mcp*.log
Windows: %APPDATA%\Claude\logs\

To tail the macOS logs live while you reproduce the drop:

tail -n 50 -f ~/Library/Logs/Claude/mcp*.log

Claude Code:

claude --debug      # verbose MCP startup output
/mcp                # in-session: shows each server's status (connected / pending / failed)
/doctor             # environment + config sanity check

Find the MCP entry nearest the most recent disconnect timestamp and match it to the bucket table above.

Step 2: Use absolute paths in the config

In Claude Desktop, open the config via Settings → Developer → Edit Config (this opens claude_desktop_config.json — macOS: ~/Library/Application Support/Claude/claude_desktop_config.json, Windows: %APPDATA%\Claude\claude_desktop_config.json). For Claude Code, project config lives in .mcp.json at the project root; local/user-scoped servers live in ~/.claude.json.

A correct stdio entry:

{
  "mcpServers": {
    "filesystem": {
      "command": "/Users/you/.nvm/versions/node/v22.14.0/bin/node",
      "args": [
        "/Users/you/code/mcp-filesystem/dist/index.js",
        "/Users/you/Documents"
      ]
    }
  }
}

Rules that prevent most disconnects:

  • command is the absolute path from which node, never bare "node".
  • Every path in args is absolute — never ~ or ./.
  • Quote or escape any path that contains a space.
  • The JSON must be valid. A single trailing comma or missing brace anywhere in the file silently kills all servers, not just the one you edited. Paste the file into a JSON validator if /mcp (or the Desktop tool list) shows everything failing at once.

In Claude Code you can sidestep hand-editing entirely:

# stdio server (everything after -- runs the server untouched)
claude mcp add filesystem -- npx -y @modelcontextprotocol/server-filesystem /Users/you/Documents

claude mcp list          # status of every configured server
claude mcp get filesystem
claude mcp remove filesystem

Step 3: Run the server by hand to confirm it starts

Copy the exact command + args from the config into a terminal:

/Users/you/.nvm/versions/node/v22.14.0/bin/node \
  /Users/you/code/mcp-filesystem/dist/index.js \
  /Users/you/Documents

If it crashes in your terminal, Claude can’t run it either. Fix the runtime version or install dependencies first. To prove the protocol handshake itself works (rules out the “Claude closes the pipe” class of bug), pipe an initialize request in:

echo '{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"test","version":"1"}}}' \
  | /Users/you/.nvm/versions/node/v22.14.0/bin/node /Users/you/code/mcp-filesystem/dist/index.js /Users/you/Documents

A healthy server replies with a JSON result containing protocolVersion and capabilities. No reply means the server itself is broken; a clean reply means the problem is in how Claude launches it (path, env, or timeout).

Step 4: Fix the ~60s startup timeout

If the log shows Server transport closed about 60 seconds in with no real error, the server didn’t finish initializing in time.

  • Pre-install dependencies so launch isn’t a cold install. For an npx server, install it globally or pin it in package.json first; for a Puppeteer/Playwright server, download the browser binary ahead of time so it isn’t fetched at startup.
  • In Claude Code, raise the startup timeout with the MCP_TIMEOUT environment variable (milliseconds):
MCP_TIMEOUT=30000 claude     # give servers 30s to start instead of the default
  • For per-tool-call timeouts (a tool call that runs long, not startup), add a timeout field in milliseconds to that server’s .mcp.json entry, e.g. "timeout": 600000 for ten minutes. See Claude Code MCP call timeout for that case specifically.

Step 5: Re-authenticate remote MCPs

When tool calls return 401:

  • Claude Code: run /mcp, select the server, and complete the OAuth flow again.
  • Claude Desktop: Settings → Connectors (or the server’s entry) → Disconnect → Connect, then re-authorize.

After authorizing, the tool should be usable immediately. If it still fails, check whether the upstream platform (Slack/Linear/GitHub/etc.) admin revoked the app authorization, or whether your bearer token (in a --header "Authorization: Bearer …" config) was rotated.

Step 6: Network and firewall

If the drop is on a regular clock and only hits remote servers, a proxy is cutting the connection. Ask IT to allowlist anthropic.com and your MCP’s specific domain (for example mcp.notion.com, mcp.sentry.dev), and to stop closing idle long-lived connections to those hosts. Note that the SSE transport is deprecated as of 2026 — if you control the server, prefer the HTTP (streamable-http) transport, which is more proxy-friendly.

For a blocked local server on macOS:

# is Claude blocked by the application firewall?
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --listapps | grep -i claude

# reset, then relaunch Claude and click Allow when prompted
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --remove /Applications/Claude.app

Step 7: Align runtime versions

node -v        # need >= 18; Node 22 LTS recommended
python3 -V     # need >= 3.10
which node     # confirm which binary Claude will inherit

If you have multiple versions installed, hardcode the absolute path in command, or pin PATH in the server’s env:

{
  "command": "node",
  "args": ["/Users/you/code/mcp-filesystem/dist/index.js"],
  "env": {
    "PATH": "/Users/you/.nvm/versions/node/v22.14.0/bin:/usr/bin:/bin"
  }
}

How to confirm it’s fixed

  1. Fully quit and relaunch Claude Desktop (Cmd+Q, not just close the window), or restart your Claude Code session — config and PATH are read at launch.
  2. In Claude Code run /mcp (or claude mcp list) and confirm the server reads connected, not pending or failed. In Desktop, confirm the tool shows in the tools list.
  3. Actually call a tool from the server and watch it return a result.
  4. Leave the session idle for 3-5 minutes, then call the tool again. If it survives the idle window, the disconnect is genuinely fixed rather than masked by a fresh reconnect.

Prevention

  • Always absolute paths in the config — never ~ or ./.
  • Pin your Node version (nvm + .nvmrc) so an OS or Homebrew update doesn’t swap the binary out from under Claude.
  • Pre-install MCP dependencies instead of relying on a cold npx install at launch, so you stay inside the startup window.
  • After any config change, validate the JSON before relaunching — one bad comma takes down every server.
  • Track .mcp.json / claude_desktop_config.json in git so you can roll back a bad edit instantly.
  • For remote MCPs, note the token’s expiry somewhere and re-auth before it lapses.

FAQ

Every MCP server fails the instant it connects — even official ones. What’s wrong? When all servers fail right after initialize (logs show Server transport closed then Server disconnected. For troubleshooting guidance, please visit our debugging documentation within tens of milliseconds), it’s almost never your server. The usual triggers are malformed JSON in the config (one syntax error disables everything) or a Claude Desktop / OS-level launch bug — a regression like this was reported on the macOS 26.2 Tahoe beta, where Desktop closed the pipe ~33ms after initialize. Validate the JSON first; if that’s clean, update Claude Desktop to the latest version and check the anthropics/claude-code issues for your OS.

Why does my remote MCP reconnect on its own but my local one doesn’t? By design. HTTP and SSE servers auto-reconnect with exponential backoff (Claude Code retries up to five times). Stdio (local subprocess) servers are not auto-reconnected, so a local crash is permanent until you relaunch or reconnect. If you need resilience, prefer a remote HTTP server where one exists.

The server connects but a tool call hangs forever, then errors out. That’s a per-call timeout, not a connection drop. Add a timeout field (in milliseconds) to that server’s .mcp.json entry, or set MCP_TOOL_TIMEOUT. See Claude Code MCP call timeout.

Where exactly are the config and log files? Desktop config: macOS ~/Library/Application Support/Claude/claude_desktop_config.json, Windows %APPDATA%\Claude\claude_desktop_config.json (open it via Settings → Developer → Edit Config). Desktop logs: ~/Library/Logs/Claude/mcp*.log. Claude Code: project config in .mcp.json, local/user servers in ~/.claude.json.

Should I use the HTTP or SSE transport for a remote server? HTTP (the spec calls it streamable-http). SSE is deprecated as of 2026 — it still works but supports neither OAuth nor the claude mcp add --transport flag the same way, and proxies cut it more aggressively.

Tags: #Claude #Troubleshooting