Subagent Resource Management#
When Claude Code spawns a subagent via the Agent tool, each subagent initializes its own full set of MCP server child processes from the current configuration. When the subagent's claude process terminates, those MCP child processes are not reliably cleaned up — they become orphans that accumulate across sessions .
This is an ongoing, cross-platform bug (tracked in issue #1935) with multiple partial fixes across versions. The problem is not limited to subagents: the main Claude Code process itself has repeatedly failed to clean up MCP servers on exit .
Why Orphans Accumulate#
Unix (macOS/Linux): When the parent claude process exits without explicitly terminating its stdio-MCP children, those children are reparented. On macOS they reparent to launchd (PPID=1); on Linux to systemd --user . Neither of those reapers terminates them.
Windows: Child process trees (cmd.exe → node.exe/bun.exe) are not automatically killed on parent exit. The canonical fix is to use Win32 Job Objects with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, which Claude Code does not currently apply to MCP children. Each short-lived subagent run can leave 5–10 orphan processes (one per configured MCP server) .
--print / headless mode: In non-interactive --print mode, Claude Code closes stdin without sending SIGINT/SIGTERM to MCP servers, leaving processes alive if they have other active handles .
Desktop app (Windows): Closing the window via the X button is not equivalent to quitting the app — the backend process remains alive, and spawned MCP children survive. Subsequent window opens may fail to re-acquire those processes and silently skip them from the MCP roster .
Observed Severity#
| Platform | Observed accumulation | Impact |
|---|---|---|
| macOS | 40+ orphaned Docker/Node/Python MCP processes from multiple sessions | Resource drain; stale Docker containers |
| Linux | 80 orphaned lark-mcp processes (~1 GB RSS each), 32 GB RAM consumed on a 92 GB workstation | OOM kills on concurrent builds |
| Windows | 27 cmd.exe + 20 node.exe + 6 bun.exe orphans from a few subagent runs; 5 MCP servers × N subagents = N×5 orphan burst | Rapid process count explosion |
| Desktop app | 156 accumulated claude CLI subprocess instances, ~31 GB RAM | Unbounded memory growth |
Version History of Fixes (Partial)#
The following fixes have landed but the issue persists as of v2.1.128+:
| Version | Fix |
|---|---|
| 1.0.21 | Stdio MCP server processes linger after quit — first fix attempt |
| 1.0.36 | Stdio MCP servers not terminating properly on exit |
| 2.1.15 | MCP stdio server timeout not killing child process, causing UI freezes |
| 2.1.19 | Dangling Claude Code processes on terminal close — EIO/SIGKILL fallback added |
| 2.1.24 | Stdio MCP server processes linger after quit — second fix pass |
| 2.1.73 | Background bash processes spawned by subagents not cleaned up on agent exit |
| 2.1.132 | External SIGINT (IDE stop button, kill -INT) not triggering graceful shutdown |
Workarounds#
Session-end hook (macOS/Linux)#
cc-reaper implements a Stop hook that fires when a session ends and kills orphan MCP processes, plus a proc-janitor daemon for crash scenarios. Uses PPID=1 detection to target only true orphans .
Periodic daemon (macOS/Linux)#
mcp-orphan-monitor runs every 10 minutes via launchd (macOS) or cron (Linux), detects orphans by PPID=1 and sends SIGKILL . Complements the hook approach: covers crash/force-quit cases where no Stop hook fires.
Subagent-cleanup plugin (cross-platform)#
PR #47830 (open as of 2026-05) proposes a SessionStart hook plugin that walks the current process's parent PID chain, identifies unprotected claude --resume orphans from prior subagent runs, and sends SIGTERM .
MCP gateway (Docker)#
airis-mcp-gateway wraps all MCP servers behind a single long-lived Docker container that lazily starts servers on first tool call and idle-kills them. docker compose down guarantees cleanup regardless of Claude Code exit behavior .
MCP server self-defense (server authors)#
Servers can self-terminate on stdin EOF — the canonical signal that the parent dropped the connection — in addition to SIGTERM/SIGINT/SIGHUP. On Windows, handle SIGBREAK as well .
Related Issues#
- #1935 — Primary tracking issue (MCP servers not terminated on exit)
- #48649 — Subagents multiply MCP server processes (N×M kernel resource consumption)
- #54554 —
preview_stopleaves orphaned descendant processes - #53134 — MCP servers spawned twice at startup (
directMcpHostvsLocalMcpServerManager) - PR #61750 (open) — Desktop app subprocess accumulation troubleshooting docs