Skip to content

fix(http): bound Streamable HTTP session lifecycle - #63

Open
Seger85 wants to merge 3 commits into
codefuturist:mainfrom
Seger85:fix/http-session-lifecycle
Open

fix(http): bound Streamable HTTP session lifecycle#63
Seger85 wants to merge 3 commits into
codefuturist:mainfrom
Seger85:fix/http-session-lifecycle

Conversation

@Seger85

@Seger85 Seger85 commented Aug 13, 2026

Copy link
Copy Markdown

Summary

Bound the lifetime and count of Streamable HTTP MCP sessions so abandoned client sessions cannot accumulate indefinitely in a long-running HTTP process.

What changes

  • track session activity and active requests in a small session registry
  • expire idle sessions after 30 minutes
  • cap retained sessions at 32
  • evict the least-recently-used inactive session when capacity is exceeded
  • never evict a session while a request is active
  • guard against stale transport onclose callbacks deleting a newer session entry
  • close retained transports during server shutdown
  • add focused lifecycle tests for TTL cleanup, capacity eviction, active-session protection and stale-close handling

Why

The HTTP server stores every initialized StreamableHTTPServerTransport in a process-level map and previously removed it only when the transport's onclose callback fired. Clients that disappear without a clean close can therefore leave sessions retained for the lifetime of the Node process. In a long-running MCP endpoint this can grow heap usage over time.

This PR fixes that lifecycle issue directly instead of relying on a larger V8 heap or periodic process restarts.

Validation

Validated from the repository base 99ce431aa81dd4cafc2879bd35b6ee3acd0f2d74 on Node 24:

  • full test suite: 157/157 tests passed in the combined production candidate
  • tsc --noEmit: passed
  • Biome check across src: passed
  • production build: passed
  • Docker image build with --pull=false: passed

Runtime validation against the built HTTP server:

  • created 40 distinct Streamable HTTP MCP sessions
  • after exceeding the 32-session limit, the oldest inactive session returned HTTP 400 as expected
  • the newest session remained valid and tools/list returned HTTP 200
  • the process did not restart or hit an OOM during the stress run
  • after a clean recreate, the normal MCP health path remained fully functional

No upstream GitHub Actions result is claimed here; the above validation was run directly against the repository and the production candidate.

Related to the long-running memory report in #55.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant