CliGovernor hard cap (21 warm sessions) causes MCP reconnect churn and contributed to an OOM crash
Bug: CliGovernor hard cap (21 warm sessions) causes MCP reconnect churn and contributed to an OOM crash
Summary
Claude Desktop's internal CliGovernor component enforces a hardcoded cap of 21
concurrent "warm" (actively MCP-connected) CLI sessions. When more sessions are open than
the cap allows — a normal state for a poweruser workflow with many pinned/background
conversations — the governor repeatedly attempts to evict idle sessions to free slots.
In practice this produces two distinct failure modes, both reproduced tonight with log
evidence:
- Eviction thrashing / live-lock. The governor can get stuck repeatedly targeting the
same session for eviction and failing (yielding warm spawn) instead of completing,
for minutes at a time. 256 evict-attempt/yield cycles were logged in one log rotation,
all against the same session, which sat at the LRU boundary (frequently refocused,
idle briefly between touches).
- Mass MCP fleet respawn after a crash, causing a memory spike severe enough to
contribute to — or directly cause — a second crash. After a Desktop crash, ~67-120
conversation tabs each triggered a near-simultaneous MCP server respawn (all processes
timestamped within the same ~6-minute window), spiking Python-based MCP server
processes from a normal baseline of ~10-13 to 269, node.exe from a normal ~100-150
to 330, and system memory from a normal ~85-90% to 97.6% (62.2 GB / 63.7 GB).
User-visible symptom
Multiple independent agent sessions, working on unrelated tasks, separately reported a
specific MCP server (Gmail, in this case) as persistently "down" — recommending
re-authorization or a connector reconnect. Direct testing of the same server moments later
(from a different session) showed it responding normally with no auth issue. The "outage"
was real from the reporting session's point of view (its own session had lost its warm MCP
connection) but nothing was actually broken — the underlying OAuth/API connectivity was
fine the entire time. This is confusing and wastes time: agents escalate a governor-internal
resource contention issue as an external service outage.
Evidence
Grep %APPDATA%\Claude\logs\main.log (and main1.log/main2.log for older activity) forCliGovernor. Sample of the thrashing pattern (repeats every few seconds for minutes,
targeting the same session UUID):
[CliGovernor] at cap=21; would evict local_<uuid> (idle 317s) for warm spawn
[CliGovernor] at cap; yielding warm spawn
[CliGovernor] at cap=21; would evict local_<uuid> (idle 325s) for warm spawn
[CliGovernor] at cap; yielding warm spawn
... (repeats, idle time climbing, same target session, eviction never completes)
Process counts before/after the crash-triggered mass respawn:
| Metric | Normal baseline | During incident |
|---|---|---|
| python.exe (MCP servers) | 10-13 | 269 |
| node.exe (MCP servers) | ~100-150 | 330 |
| System memory | ~85-90% | 97.6% (62.2 GB / 63.7 GB) |
All spiked processes were confirmed to be duplicate MCP server spawns (same command line,
multiple copies) or genuine child-process leaks — not distinct legitimate connections.
What we checked (ruling out a local misconfiguration)
- No cap/concurrency setting exists in
~/.claude/settings.json. - No such setting in Claude Desktop's own
%APPDATA%\Claude\config.json. - No such setting in
claude_desktop_config.json. - The cap value (21) is not present or documented in any user-facing config — it appears
to be hardcoded in the application.
Requested fix / ask
- Either raise the hardcoded cap, make it user-configurable, or (ideally) fix the eviction
logic so it doesn't thrash/live-lock against a single target session — it should pick a
different eviction candidate on repeated yield rather than retrying the same one
indefinitely.
- On crash recovery, stagger/rate-limit MCP server respawn across sessions instead of
spawning all of them near-simultaneously — this is what turned a recoverable crash into
a near-repeat-OOM situation.
- Consider surfacing "session evicted due to governor cap" as a distinct, identifiable
state (in logs or to the agent itself) rather than presenting as a generic MCP
disconnect — this would let agents correctly distinguish "transient internal resource
contention, will self-heal" from "the external service/auth is actually broken."
Environment
- Windows 11, Claude Desktop (build referenced in logs: 1.24012.9 / claude-code 2.1.219)
- Workflow: heavy poweruser usage with many long-running pinned conversations (~40-120
concurrent tabs is a normal working state for this account)