Skip to content

24h MCP session cleanup can be outpaced by high-churn ChatGPT reconnects #256

Description

@whitesarum

Summary

The 24-hour idle-session cleanup added in #71 is working, but it is not a deterministic memory bound when ChatGPT initializes/reconnects at a high rate. In one long-running production-equivalent run, session creation substantially outpaced 24h cleanup and the DevSpace process grew into multi-GB memory usage.

This is not a claim that MCP session retention is the sole cause of every ChatGPT timeout/disconnect. It is a narrower finding: the current 24h/5m policy can still allow thousands of retained session/server graphs under high churn.

Environment / scope

  • macOS
  • Node v24.18.0
  • ChatGPT as the MCP host
  • Observed on a production-equivalent DevSpace v1.0.7-based build with additive read-only runtime observability
  • I have not installed v1.0.8 to reproduce this exact run. However, current v1.0.8/main still appears to use the same 24h idle timeout, 5-minute cleanup sweep, and no hard session-capacity bound.

Production evidence

Collector baseline:

  • retained MCP sessions: 144
  • heapUsed: 155,141,692 B
  • physical footprint: 229,591,480 B

After about 2h12m:

  • retained MCP sessions: 586
  • heapUsed: 442,791,944 B
  • a +256 MiB heap safety threshold was reached

Longer advisory observation before restart:

  • current sessions: 3,904
  • peak sessions: 4,134
  • heapUsed: 2,855,774,792 B
  • physical footprint: 3,269,620,040 B

The 24h cleanup was actually functioning:

  • idle_timeout removals: 3,301
  • matching close_completed: 3,301
  • close_failed: 0

But sustained creation continued faster than removal. Observed creation rate was roughly 2.5–3.4 sessions/minute. Session count and heapUsed were strongly correlated (~0.998 in the focused collector window and ~0.993 over the longer observation). Restart returned the process footprint to roughly 169 MB.

Interpretation

This supports the original motivation in #71, but suggests the intentionally conservative 24h timeout is insufficient for some ChatGPT workloads. It bounds session age, not registry size or retained-memory exposure.

A paused conversation vs. memory-safety tradeoff remains: simply shortening the idle timeout can invalidate legitimate paused sessions, while leaving it long permits large accumulation.

Related upstream work

I added the detailed operational evidence to #71, and a separate bounded-stateful validation data point to #89/#209.

Independent bounded-stateful validation

To test whether a deterministic stateful bound is viable, I separately exercised a prototype with:

  • hard capacity: 256 sessions
  • active-request and live-SSE protection
  • idle-only capacity eviction
  • bounded HTTP 503 + Retry-After: 5 when no eligible idle slot exists
  • close-failure slots remaining capacity-counted

Using Node 24.18.0, MCP SDK 1.30.0, and Express 5.2.1 on the real server path:

  • 1,024 / 1,024 initialize + initialized + DELETE cycles succeeded
  • final registry/permit/protection occupancy: 0
  • in a 256-session capacity run, one live GET SSE and one disconnected-but-running tool operation remained protected
  • 254 eligible idle sessions were evicted/replaced
  • when only protected/non-eligible capacity remained, the next initialize returned the expected 503
  • maximum occupancy: 256
  • active-session evictions: 0
  • duplicate removal/terminal lifecycle events: 0
  • equal-occupancy post-GC heap delta after the eviction wave: about -2.08 MB
  • after complete cleanup, post-GC heap was about +1.12 MB above startup

This does not prove a bounded-stateful design is preferable to #209 stateless handling; it only shows it is a viable mitigation shape under this test.

Desired outcome

It would be useful to get maintainer guidance on the intended upstream direction:

  1. keep stateful sessions but add a deterministic capacity + active-work protection, or
  2. move to request-scoped/stateless Streamable HTTP as in fix(server): use stateless Streamable HTTP #209.

Either way, I think the current 24h cleanup should be treated as an age-based mitigation rather than a deterministic memory bound for high-churn ChatGPT clients.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions