MCP stdio servers never auto-reconnect after disconnect
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
10 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
+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_indexsucceeds, immediate follow-upctx_searchfails with-32000: Connection closed./mcpreconnect 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:The
elsebranch (line 466) just doesupdateServer({ ...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.
@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:356explicitly excludes stdio from reconnection, whilereconnectMcpServerImpl()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.
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 --channelsparent just keeps running with nothing feeding it messages.Orphaned bun processes from previous sessions hang around with
.orphaned_atmarkers, 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
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
+1, reproducing on macOS with a FastMCP Python stdio server.
Pattern:
(log: "Server transport closed unexpectedly")
(verified by direct stdio test — returns in 2s)
waits 4min before failing
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.
+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-remotetalking to the Meko MCP endpoint. The wrapper re-reads the token from~/.mcp-tokens/meko.jsonon every spawn, so a background rotator (launchd agent, every 50 min) keeps the token fresh on disk.Observed behavior aligns exactly with this issue:
curlwith the old token → 401, with the fresh on-disk token → 200 oninitialize).mekoas✗ failedand 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✓ connectedand the full tool catalog.The proposed one-line fix (removing
&& configType !== 'stdio'atuseManageMCPConnections.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.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.
claudein a project with a healthy stdio MCP server, use its tools./exit.claude --continue./mcp→ "Failed to reconnect to <server>", nomcp__<server>__*tools registered.claude mcp list(separate process) → ✓ Connected.Evidence: my stdio bridge logs every spawn. After
/exit+claude --continue+/mcpReconnect, zero bridge spawns are recorded — i.e. neither the harness on resume nor/mcp's manual reconnect attempts to launch the child process. A subsequentclaude mcp listdoes spawn it (out-of-band probe, separate code path) and reports ✓ Connected.This appears consistent with the
useManageMCPConnections.ts:354-356guard you identified — the resume path treats the stdio server as afailedconnection 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_TIMEOUTenv had no effect.claude --continue --fork-sessionreportedly 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"]}.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
Closing for now — inactive for too long. Please open a new issue if this is still relevant.
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:
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.