Skip to content

fix: tolerate unregistered listening stream for server-initiated messages - #1115

Closed
slachiewicz wants to merge 1 commit into
modelcontextprotocol:mainfrom
slachiewicz:fix/streamable-server-initiated-push-grace
Closed

fix: tolerate unregistered listening stream for server-initiated messages#1115
slachiewicz wants to merge 1 commit into
modelcontextprotocol:mainfrom
slachiewicz:fix/streamable-server-initiated-push-grace

Conversation

@slachiewicz

@slachiewicz slachiewicz commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Right after initialize, the server may push a server-initiated request (e.g. roots/list when the client declared the roots capability) before the client has opened its GET /mcp stream; the session then failed with Stream unavailable for session (intermittent -32603/500, seen in HttpServletStreamableIntegrationTests CI). sendRequest/sendNotification now retry missing-stream failures with bounded backoff (~5s) and accept(notification) routes handler-initiated pushes through the retrying session facade. Related: #952, #1061. New unit tests cover buffer-until-register, correlation, grace exhaustion, and the handler-push path. Happy to adapt the approach per maintainer guidance.

Fixes #1114

@CryoThrust CryoThrust left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bounded retry/backoff and coverage for buffer-until-register, exhaustion, and handler-initiated pushes look aligned with the race described in #1114. I especially appreciate keeping the logical session alive while tolerating a not-yet-registered stream. I will watch for any maintainer feedback on the retry bound and lifecycle semantics.

…d messages

Right after initialize, the server may push a server-initiated request (e.g. roots/list when the client declared the roots capability) before the client has opened its GET /mcp stream. The session previously delegated to a MissingMcpTransportSession that failed immediately with Stream unavailable for session <id>, surfacing as an intermittent -32603/500 on the clients POST (seen in CI HttpServletStreamableIntegrationTests.testRootsNotificationWithEmptyRootsList).

Changes: introduce package-private MissingListeningStreamException (subclass of IllegalStateException, same message) thrown by MissingMcpTransportSession; McpStreamableServerSession.sendRequest/sendNotification retry missing-stream failures with exponential backoff capped at 12 attempts (~5s); accept(notification) falls back to the retrying session facade when no stream is registered yet so handler-initiated pushes are covered too.

Related: modelcontextprotocol#952, modelcontextprotocol#1061
@slachiewicz
slachiewicz force-pushed the fix/streamable-server-initiated-push-grace branch from 3ccb4ec to 9ddc5de Compare August 31, 2026 13:09
@Kehrlann

Copy link
Copy Markdown
Contributor

As mentioned in #1114 , we don't plan on handling retry on missing handlers.

@Kehrlann Kehrlann closed this Aug 31, 2026
@slachiewicz
slachiewicz deleted the fix/streamable-server-initiated-push-grace branch August 31, 2026 18:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

3 participants