Dispose the POST response in SseClientSessionTransport to stop leaking a connection per message - #1841
Open
yalcinfu22 wants to merge 1 commit into
Open
Conversation
SendMessageAsync sends every message with HttpCompletionOption.ResponseHeadersRead (via McpHttpClient) but never disposed the returned HttpResponseMessage on the success path, so the underlying connection was never returned to the pool. Each JSON-RPC POST therefore opened and stranded a new connection, which was only reclaimed by GC or an idle timeout. Disposing the response returns the connection to the pool deterministically; subsequent POSTs reuse a single connection. Fixes modelcontextprotocol#1840 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1840
What
One-word change in
SseClientSessionTransport.SendMessageAsync: theHttpResponseMessagereturned for each POSTed JSON-RPC message is now wrapped in
using.Why
McpHttpClient.SendAsyncsends every request withHttpCompletionOption.ResponseHeadersRead,so the underlying connection stays checked out until the response is consumed or disposed.
The POST path never did either on the success path (a
202 Acceptedwhose body is unused),so every sent message stranded one ESTABLISHED connection — never returned to the pool,
never reused, reclaimed only by GC or an idle timeout. Measurements and the full analysis
are in #1840 (per client: 1 live SSE connection + one stranded connection per POST —
initialize,notifications/initialized,tools/list).The surrounding code already does this correctly: the SSE GET response is wrapped in
using var responsein the same file, and the failure path reads the body before throwing.Only the success path was missing the dispose.
Notes
usingscope unwinds.ModelContextProtocol.Corebuilds cleanly with the change.🤖 Generated with Claude Code