Skip to content

fix: close servlet streamable HTTP transports on async lifecycle events#1039

Closed
neerajbhatt wants to merge 1 commit into
modelcontextprotocol:mainfrom
neerajbhatt:fix/1027-close-streamable-transports-on-async-lifecycle
Closed

fix: close servlet streamable HTTP transports on async lifecycle events#1039
neerajbhatt wants to merge 1 commit into
modelcontextprotocol:mainfrom
neerajbhatt:fix/1027-close-streamable-transports-on-async-lifecycle

Conversation

@neerajbhatt

Copy link
Copy Markdown

Summary

Fixes #1021 — server sockets left in CLOSE-WAIT state when clients disconnect from SSE streams.

  • Register AsyncListener on all three async paths in HttpServletStreamableServerTransportProvider (GET replay, GET listening stream, POST streaming response) so transports are properly closed on client disconnect, async timeout, or error
  • Introduce a registerAsyncLifecycle helper to consolidate the listener boilerplate across all three paths
  • Route SSE write failures in sendMessage() through transport.close() instead of directly removing the session from the session registry — transport failures should not evict the logical MCP session, which may be resumable via a new connection

Test plan

  • HttpServletStreamableAsyncServerTests — 35 tests pass
  • HttpServletStreamableIntegrationTests — 36 tests pass
  • HttpServletStreamableSyncServerTests — 34 tests pass

Register AsyncListener on all three async paths in
HttpServletStreamableServerTransportProvider (GET replay, GET listening
stream, POST streaming response) so that transports are properly closed
when clients disconnect, the async context times out, or an error occurs.
Without these listeners, server sockets were left in CLOSE-WAIT state,
exhausting Tomcat thread/connection resources.

Also route SSE write failures in sendMessage() through the transport close()
method instead of directly removing the session from the registry.
Transport-level failures should not evict the logical MCP session, which
may still be resumable via a new connection.

Fixes modelcontextprotocol#1021
@neerajbhatt

Copy link
Copy Markdown
Author

Closing in favor of #1027 which addresses the same issue.

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.

[BUG] McpStreamableServerSession does not close server-side socket when client disconnects, causing CLOSE-WAIT leak and thread pool exhaustion

1 participant