Skip to content

fix(lifecycle): bound the session-id probe and release its response body - #455

Open
aviseth wants to merge 1 commit into
modelcontextprotocol:mainfrom
aviseth:fix/lifecycle-session-id-probe-bound
Open

fix(lifecycle): bound the session-id probe and release its response body#455
aviseth wants to merge 1 commit into
modelcontextprotocol:mainfrom
aviseth:fix/lifecycle-session-id-probe-bound

Conversation

@aviseth

@aviseth aviseth commented Aug 13, 2026

Copy link
Copy Markdown

Closes #428.

The visible-ASCII session-id check sends its own initialize POST, outside the SDK transport, because the transport doesn't expose the MCP-Session-Id header. That fetch had no abort signal and nothing ever read or cancelled the body.

So a server that accepts and never answers hung the scenario before teardown, which meant the DELETE bound from #316 never got a chance to run. And since the probe sends Accept: application/json, text/event-stream, a server answering with an open stream left the body dangling for the rest of the run.

5s to match SESSION_TERMINATE_TIMEOUT_MS, plus response.body?.cancel() once the header has been read.

Branched off main rather than stacking on the #427 branch, since you noted this is worth having on its own even after the runner-level bound lands. Two tests, both fail against the unmodified probe. Full suite passes.

The visible-ASCII session-id check sends a raw initialize POST outside the
SDK transport, because the transport does not expose the MCP-Session-Id
response header. That fetch carried no abort signal and its body was never
read or cancelled.

A server that accepts the connection and never responds hung the scenario
here, before teardown, so the DELETE bound added in modelcontextprotocol#316 never came into
play. And since the probe's `Accept` includes `text/event-stream`, a server
answering with an open SSE stream left the body unconsumed and leaked the
connection for the rest of the run.

Bounding the probe at 5s matches the existing session-termination bound.
modelcontextprotocol#427 is the structural fix for the hang class; this is still worth having
for fast failure and for attributing the failure to this check rather than
to whatever the runner-level timeout happens to interrupt.

Fixes modelcontextprotocol#428
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.

lifecycle.ts session-id probe: raw initialize fetch is unbounded and never consumes the response body

1 participant