Claude Desktop local-agent (Cowork) sessions leak claude-code node processes (never exit at session end) — GBs of RAM + MCP port exhaustion
Summary
On macOS, local Claude Code sessions launched by the Claude Desktop app (the "Cowork" / local-agent mode, where the Desktop app spawns claude-code/<version>/claude.app/Contents/MacOS/claude node processes) are not reaped when the session ends. The node process keeps running indefinitely after the conversation is over, and it keeps its child MCP-server processes alive with it. Over hours/days these accumulate into dozens of multi-hundred-MB processes, and the surviving MCP children keep holding the OS resources they own — notably TCP ports — which eventually breaks new sessions.
Environment
- Claude Desktop (macOS) launching local Claude Code sessions and scheduled tasks
- Claude Code version 2.1.181
- Per-session process lineage:
/Applications/Claude.app/Contents/MacOS/Claude→…/Contents/Helpers/disclaimer …→…/claude-code/<ver>/claude.app/Contents/MacOS/claude(the node) → MCP-server children
Observed behavior
- Every local session (and every scheduled-task run) spawns a
claude-codenode process under the Desktop app. - When the session/conversation ends, that node process does not exit. SessionEnd hooks do fire (so the session logically ends), but the process keeps running.
- Lingering nodes accumulate without bound until the Desktop app is restarted. Observed dozens at once (50+), including processes from sessions started 1–3 days earlier still running. In a fresh snapshot after a restart: ~5 nodes from a single morning's scheduled-task burst, each ~230–380 MB RSS (~1.2 GB total); the count climbs as more sessions run.
- The lingering node keeps its child MCP servers alive too. Concretely, a stdio MCP server it spawned (in our case the Google Workspace MCP,
workspace-mcp) keeps running and keeps holding the local TCP port it bound (we saw 17workspace-mcpprocesses alive in one snapshot). - The per-session registry files at
~/.claude/sessions/<node_pid>.jsonare also not cleaned up — they persist after the session ends and carry no heartbeat (mtime is frozen at session start), so they can't be used to tell a live session from a leaked one.
Impact
- Unbounded memory leak: dozens of multi-hundred-MB node processes (>1 GB quickly) plus their MCP-server children, until the Desktop app is restarted.
- Concrete downstream failure (how we found it): each leaked node's
workspace-mcpchild keeps holding its OAuth-callback TCP port.workspace-mcpbinds within a small fixed port range per account (e.g. 8001–8005). Once leaked instances fill the range, a new session's Google Workspace MCP can't bind and exits withNo available port in range→ the connector shows "Failed to connect." This presents as an intermittent, confusing auth-looking failure that is actually port exhaustion caused by the process leak. - The only remediation is quitting and reopening the Desktop app.
Steps to reproduce
- On macOS, use Claude Desktop's local-agent / Cowork mode (and/or scheduled tasks) to run several Claude Code sessions over time. Have each connect at least one stdio MCP server that binds a local socket (e.g. a Google Workspace MCP).
- End each session normally.
ps -ax | grep 'claude-code/.*MacOS/claude'— node processes from ended sessions remain running indefinitely; their MCP-server children remain too. The count grows with each session and never decreases until the Desktop app restarts.
Expected behavior
When a local session ends, its claude-code node process and the MCP-server children it spawned should be terminated, and its ~/.claude/sessions/<pid>.json cleaned up.
Notes / suggested investigation
- Node process not exiting at session teardown (an open libuv handle / unref'd timer / lingering socket keeping the event loop alive?).
- MCP child processes not being killed when their owning session ends (and, relatedly, stdio MCP servers that don't exit on stdin EOF can outlive even a dead parent).
- The session-registry file lacking an end marker / heartbeat leaves external cleanup tooling unable to distinguish active vs ended sessions.
Severity: Medium-high — silent multi-GB memory growth on long-running Desktop installs, plus intermittent MCP failures that look like auth bugs.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗