[Bug] stdio MCP server disappears ~53s after reconnect — no exit code, no signal, no exception (related to #40207/#86711)
Summary
A stdio MCP server (a third-party desktop app's mcp subcommand, spawned directly by Claude Code as a child process) disappeared roughly 53 seconds after a successful reconnect, with no exit code, no signal captured, and no exception logged from inside the process itself. I don't have proof of what terminated it, but I've ruled out one large category of cause and want to flag this alongside two existing, related reports: #40207 (closed by a stale-bot; a collaborator confirmed the core "shrinking 60s→30s→10s SIGTERM to healthy stdio servers" mechanism was never actually addressed) and #86711 (open, a faster ~3s variant of what looks like the same class of bug).
Environment
- Claude Code 2.1.239 at the time of the captured death (auto-updated to 2.1.241 shortly after; haven't yet reproduced on 2.1.241 specifically since the disconnect is intermittent)
- macOS 15.x (Darwin 25.4.0), Apple Silicon
- MCP server: stdio transport, spawned via a
command/argsentry in the user's MCP config, running on Electron 41.3.0's bundled Node 24.15.0 (ELECTRON_RUN_AS_NODE=1) ps -o ppidconfirms the MCP server's parent PID is the runningclaudeprocess — this shows Claude Code spawned it, not that Claude Code is what later terminates it; I don't have independent proof of the actor
What I instrumented and what it does/doesn't show
I added global handlers to the top of the MCP server's entrypoint, before any of its own code runs:
process.on("uncaughtException", (err) => log("uncaughtException", err));
process.on("unhandledRejection", (err) => log("unhandledRejection", err));
(log appends synchronously via fs.appendFileSync.) A reconnect (triggered via /mcp after a prior disconnect) spawned the server at 2026-08-22T19:00:34.961Z UTC; the process was gone roughly 53 seconds later with nothing written by either handler.
This rules out an ordinary uncaught exception or unhandled promise rejection reaching Node's global handlers in that process — including a rejection from a top-level await, which I separately confirmed under the same Node/Electron runtime still surfaces as uncaughtException rather than escaping undetected. It does not rule out a signal (SIGTERM/SIGKILL), the process's stdin being closed, an explicit process.exit() call somewhere in its dependency chain, a native/V8 crash, or OOM — none of those were instrumented in that first pass. I've since added SIGTERM/SIGHUP/SIGINT/SIGQUIT/SIGPIPE, process.on('exit'), and stdin end/close/error handlers to the same entrypoint and am waiting to catch a live occurrence with that in place; will update this issue if/when it fires.
Why I think this is worth a look now rather than waiting for my own repro
- The pattern (healthy server, no local error, disappears anyway) matches what multiple independent reporters described in #40207 across unrelated MCP server implementations and platforms (macOS, Linux/systemd), with a reported 10–60s window that my ~53s observation sits inside.
- #40207 was closed by a stale-bot, not by a confirmed fix — a collaborator (@localden) explicitly separated a narrow fix (a headless/SDK
mcp_set_serversreconcile false-positive) from the core shrinking-timeout mechanism, which they said was still open. - Separately, and maybe relevant to the impact here: stdio MCP servers are excluded from Claude Code's automatic reconnect logic (
configType !== 'stdio'per the root-cause writeup in #43177), so whatever the exact cause turns out to be, recovery today is always manual.
Ask
- If there's a known internal timeout/heartbeat mechanism (beyond the per-request tool-call timeout) that can terminate a stdio MCP child independent of its health, documenting when/why it fires would help MCP server authors distinguish "the host recycled me" from "I have a bug."
- If #40207's shrinking-timeout mechanism is still live in some form, it'd help to know whether it's considered resolved, still tracked elsewhere, or genuinely open.
Happy to share the exact instrumented entrypoint or run further targeted tests if that's useful — I don't yet have a minimal, host-independent repro.