MCP stdio servers never auto-reconnect after disconnect

Status Closed — not planned
Maintainer reply None cached
Activity 10 comments · opened Apr 3, 2026 · closed Jun 13, 2026

Bug

When a stdio-type MCP server process dies or disconnects, Claude Code marks it as failed and never attempts reconnection. HTTP/SSE/WebSocket servers get automatic reconnection with exponential backoff (5 attempts), but stdio servers are explicitly excluded. Users must manually run /mcp to reconnect.

Root Cause

File: src/services/mcp/useManageMCPConnections.ts
Lines: 354-356

// Handle automatic reconnection for remote transports
// Skip stdio (local process) and sdk (internal) - they don't support reconnection
if (configType !== 'stdio' && configType !== 'sdk') {

The comment says "they don't support reconnection" but this is incorrect. reconnectMcpServerImpl() in src/services/mcp/client.ts:2137 works for ALL transport types — it calls connectToServer() which handles stdio by spawning a new subprocess. Reconnecting a stdio server just means respawning the process.

On the else branch (line 466), stdio servers are simply marked as failed with no retry:

} else {
    updateServer({ ...client, type: 'failed' })
}

The Fix

One-line change at line 356 of useManageMCPConnections.ts:

Before:

if (configType !== 'stdio' && configType !== 'sdk') {

After:

if (configType !== 'sdk') {

The existing exponential backoff logic (5 attempts, 1s → 2s → 4s → 8s → 16s) and reconnectMcpServerImpl() already handle stdio correctly. They just need to be allowed to run.

Impact

This primarily affects Playwright MCP (npx @playwright/mcp@latest), the most common stdio MCP server. The subprocess frequently dies due to browser tab crashes, timeout errors, idle timeouts, or macOS sleep/wake cycles. Every disconnect requires manual /mcp intervention, which breaks workflow — especially during multi-step automated tasks.

Any custom stdio MCP server is equally affected.

Environment

  • Claude Code 2.1.x (CLI and VS Code extension)
  • macOS (Darwin 25.3.0)
  • Playwright MCP configured as stdio type

View original on GitHub ↗

10 Comments

github-actions[bot] · 4 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/36308
  2. https://github.com/anthropics/claude-code/issues/31646
  3. https://github.com/anthropics/claude-code/issues/39793

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

chrisxthe · 4 months ago

+1 — Confirmed this bug independently on v2.1.92 (Linux/WSL2, Opus 4.6 1M context).

Repro: context-mode plugin MCP server (stdio) dies after exactly 1 tool call, every time. ctx_fetch_and_index succeeds, immediate follow-up ctx_search fails with -32000: Connection closed. /mcp reconnect fixes it, but only for the next single call.

Verified the server is not at fault: Spawned the context-mode MCP server standalone, sent 4 sequential JSON-RPC calls (initialize, listTools, ctx_stats, ctx_stats) — all succeeded, no crash, no exit. The server is perfectly stable; Claude Code's MCP client is dropping the pipe.

Source confirmation: Found the exact line in the leaked source at src/services/mcp/useManageMCPConnections.ts:356:

if (configType !== 'stdio' && configType !== 'sdk') {

The else branch (line 466) just does updateServer({ ...client, type: 'failed' }) with no retry. The proposed fix (configType !== 'sdk') is correct — reconnectMcpServerImpl() already handles stdio by respawning the process.

This effectively breaks all stdio MCP plugins that need more than one tool call per session.

RedhatEnt · 4 months ago

@chrisxthe thanks for confirming — good to see independent verification on a completely different MCP server (context-mode vs Playwright). That rules out any server-side cause.

This is not a duplicate of the linked issues. Those issues describe symptoms (MCP disconnects, tools fail) without identifying root cause. This issue pinpoints the exact code path: useManageMCPConnections.ts:356 explicitly excludes stdio from reconnection, while reconnectMcpServerImpl() already supports it. The fix is one line.

The auto-close bot found "similar" issues but similarity ≠ duplicate. The other issues don't have the root cause or fix identified.

vinistoisr · 4 months ago

Telegram channel plugin is broken -- 65+ open issues, no fix in sight

The Telegram channel plugin was the main reason I subscribed to the Max plan (20x tier). It's never worked reliably. I spend more time restarting it and killing zombie processes than actually using it.

What actually happens

The bun process running server.ts dies. No error, no warning, nothing. The claude --channels parent just keeps running with nothing feeding it messages.

Orphaned bun processes from previous sessions hang around with .orphaned_at markers, eating 120+ MB each. My workflow is: start session, send a message, notice it's dead, ps aux | grep telegram, kill stale PIDs, restart. Repeat.

Environment

  • Claude Code latest, Max plan (20x usage)
  • Telegram plugin v0.0.4
  • Happens across platforms (Linux, WSL2, macOS, Windows -- see linked issues)

This isn't a niche problem

I went through the issue tracker. There are 65+ open issues about the Telegram plugin. Same bugs, reported over and over, across every platform:

Inbound messages never reach the session (outbound works fine):
#36411 #36429 #36771 #36895 #37189 #37229 #37301 #37498 #38477 #38508 #38988 #39776 #40800 #41275 #42138 #43049 #43088 #43627 #43653 #45189 #45548 #46016 #46125 #46356 #46744

MCP server disconnects/crashes:
#36427 #36615 #36644 #36834 #36964 #45852 #45985 #46502

Stops processing after idle/activity:
#36477 #36988 #38259 #44380 #45408 #45521

Zombie processes and 409 conflicts:
#36800 #37624 #38204 #39876 #45590 #45651 #46504 #46637

Spawn/config failures:
#36841 #38098 #38600 #42221 #42641 #43939 #46334 #46617

General MCP stability (all channel plugins):
#33947 #36786 #37259 #39486 #40207 #43177 #43895 #45146 #45880 #46004 #46203

On top of that, there are ~100 closed Telegram issues -- 74 closed as duplicates, and core bugs like #40525 and #40440 closed as NOT_PLANNED with no explanation. Zero open PRs with fixes.

What needs to happen

The MCP connection between Claude Code and channel plugins needs to not drop. That's the fix. The bun subprocess dies or the stdio pipe breaks, and the session doesn't notice or recover. Whatever is causing the child process to crash needs to be found and fixed, and the connection needs to be resilient to transient failures.

In the meantime, auto-reconnect, orphan cleanup, and a health indicator would at least make it usable while the root cause is tracked down. But those are workarounds, not the fix.

Most importantly: consolidate these 65+ issues into one tracking issue, assign an owner, and communicate a timeline.

This isn't solved by Remote Control

Remote Control requires the Claude app. Channels meet you where you already are -- Telegram, Discord, group chats, bots, webhooks. They integrate into existing workflows in ways a dedicated app never will. And Remote Control already has auto-reconnect when the network drops. Channels need the same resilience.

Credit where it's due

Being able to message Claude Code from your phone while it works on your local codebase is genuinely transformational. The team has done incredible work on Claude Code overall, and this feature -- when it works -- is a glimpse of what the future of development looks like. The fact that 165+ issues have been filed about it isn't just frustration, it's demand. People want this to work because they can see how powerful it is.

But right now it doesn't work, and there's no visible progress toward fixing it. This feature was publicly announced, has official documentation, and is listed as a key capability of Claude Code plugins. It's part of what people are paying for on the Max plan. It deserves the same level of engineering attention as the rest of the product.

cc @bcherny @ThariqS @felixrieseberg @chrislloyd @dicksontsai @ashwin-ant @natemcmaster @domdomegg

wangweide80 · 4 months ago

+1, reproducing on macOS with a FastMCP Python stdio server.

Pattern:

  • Tool calls work for first ~60-70s
  • After chat idle ~60s, Desktop closes transport

(log: "Server transport closed unexpectedly")

  • Server Python process remains alive and healthy

(verified by direct stdio test — returns in 2s)

  • Next tool call from chat goes into dead pipe,

waits 4min before failing

  • No way to reconnect from chat side; only fix is

Cmd+Q + reopen Desktop

Use case broken: any multi-step workflow with natural
thinking pauses (batch analysis, data audits) becomes
unusable.

Workaround tried: wrapper script with pkill before spawn
— handles startup zombies but can't fix mid-session
transport close.

Would love either (a) auto-reconnect on next call, or
(b) expose a /reconnect slash command for the chat.

amiramm · 3 months ago

+1 — independently confirmed on Claude Code 2.1.x with a custom stdio MCP server (Meko) using a rotating bearer token.

Setup: a thin local wrapper between Claude Code and mcp-remote talking to the Meko MCP endpoint. The wrapper re-reads the token from ~/.mcp-tokens/meko.json on every spawn, so a background rotator (launchd agent, every 50 min) keeps the token fresh on disk.

Observed behavior aligns exactly with this issue:

  • Wrapper+mcp-remote receives a 401 when the server-side session is rotated (verified: curl with the old token → 401, with the fresh on-disk token → 200 on initialize).
  • Claude Code marks meko as ✗ failed and never respawns the stdio child, even though the on-disk token is already valid.
  • /mcp → disable/enable is the only way to recover without a Claude Code process restart; doing so respawns the wrapper, which reads the now-fresh token, and the server comes back with ✓ connected and the full tool catalog.

The proposed one-line fix (removing && configType !== 'stdio' at useManageMCPConnections.ts:356) would let this scenario self-heal, since the wrapper respawn is exactly the "reconnect" behavior needed. Subprocess-side auth refresh patterns like ours fundamentally require stdio reconnect to work.

ottopichlhoefer · 3 months ago

Adding a resume-time variant of this same root cause that I observed on Windows. Filed separately as #57794, closing that one in favor of this issue.

Trigger: not a runtime disconnect but a session resume.

  1. claude in a project with a healthy stdio MCP server, use its tools.
  2. /exit.
  3. claude --continue.
  4. /mcp → "Failed to reconnect to <server>", no mcp__<server>__* tools registered.
  5. claude mcp list (separate process) → ✓ Connected.

Evidence: my stdio bridge logs every spawn. After /exit + claude --continue + /mcp Reconnect, zero bridge spawns are recorded — i.e. neither the harness on resume nor /mcp's manual reconnect attempts to launch the child process. A subsequent claude mcp list does spawn it (out-of-band probe, separate code path) and reports ✓ Connected.

[12:51:47] bridge starting   ← manual probe before /exit
[12:51:48] bridge exiting
                              ← /exit, then `claude --continue`, then /mcp Reconnect
                              ← no bridge spawn at all
[12:54:34] bridge starting   ← `claude mcp list` (separate process)

This appears consistent with the useManageMCPConnections.ts:354-356 guard you identified — the resume path treats the stdio server as a failed connection that should not be reconnected. The proposed one-line fix (allowing stdio through the reconnect branch) would presumably address resume-time reconnects too.

Notable wrinkles for the Windows + bash-bridge case:

  • /mcp's manual "Reconnect" button also does not spawn the child in the resume context. So the workaround "users must manually run /mcp" from the original report does not apply here.
  • MCP_TIMEOUT env had no effect.
  • claude --continue --fork-session reportedly works (untested by me yet).

Environment: Claude Code 2.1.138, Windows 11 Pro 26200, stdio server defined as {type:"stdio", command:"bash", args:["…/bridge.sh"]}.

vaibhav11123 · 3 months ago

Hit this same pattern with stdio servers on both VS Code and Cursor. Built a watchdog extension as a stopgap while native reconnect gets fixed — periodic pings, exponential backoff reconnects, and a focus-regain check after sleep/wake. Works on both editors: https://marketplace.visualstudio.com/items?itemName=mcp-watchdog.mcp-watchdog — source at https://github.com/vaibhav11123/mcp-watchdog

github-actions[bot] · 2 months ago

Closing for now — inactive for too long. Please open a new issue if this is still relevant.

kkuczek · 2 months ago

Corroborating on macOS with the built-in Filesystem connector, plus one caught instance that may point at a distinct mode.

Setup: Claude Desktop 1.17377.x, macOS. The Filesystem connector here runs as the built-in extension on the app's bundled Node (a UtilityProcess, appConfig.isUsingBuiltInNodeForMcp = true), not an external npx process. Same user-visible failure this issue's family describes: a tool call hangs ~4 min ("No result received from the Claude Desktop app after waiting 4 minutes..."), recoverable only by Cmd+Q + reopen (which per #54136 kills every session).

From the logs on a caught instance:

  • Server is healthy when reached. Delivered tools/calls answer in 1–4 ms, including after an ~11-hour idle gap in the same server session with no restart. So idle duration alone doesn't predict it — an 11h gap survived, while a ~2-minute gap in another session hung.
  • The hung call left no trace anywhere. The last delivered call was id=9; the hung call would have been id=10 and never appears — no "Message from client: method=tools/call" line for it in mcp.log. Since that line is written when the app forwards a request to the server, its absence means the request stalled upstream of the app-side dispatch, not lost in transit past it.
  • No "transport closed" line preceded the hang (only a clean "intentional shutdown" on the manual restart). So in this instance there was no observed disconnect to reconnect from.

Flagging that last point because the fix here (let stdio servers auto-reconnect after disconnect) targets the post-disconnect case, but at least one macOS instance shows a single call silently failing to dispatch with the connection apparently still live and no disconnect logged. If that's a separate mode, auto-reconnect wouldn't recover it — worth checking whether the app-side routing can wedge one call without tearing down the transport. Happy to share sanitized log slices.