Repository navigation
fix(server): settle the POST for a cancelled request - #3107
Open
Sanath91009 wants to merge 2 commits into
Open
Sanath91009 wants to merge 2 commits into
Sanath91009 wants to merge 2 commits into
Conversation
A cancelled request kept its stream mapping forever because Protocol drops the result and the error for an aborted request, so send() never runs and the transport never resolves the POST or closes the per-request SSE stream. Settle the request in the transport when notifications/cancelled arrives: retire both mappings and either resolve the JSON response with the existing empty 202 or clean up the SSE stream. An unresponded sibling that shares the stream keeps it open.
🦋 Changeset detectedLatest commit: d9d5d82 The changes in this PR will be included in the next version bump. This PR includes changesets to release 6 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
@modelcontextprotocol/client
@modelcontextprotocol/codemod
@modelcontextprotocol/core
@modelcontextprotocol/server
@modelcontextprotocol/server-legacy
@modelcontextprotocol/express
@modelcontextprotocol/fastify
@modelcontextprotocol/hono
@modelcontextprotocol/node
commit: |
|
Verified on this branch at
Also ran |
This branch has not been deployed
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 #3053
After
notifications/cancelled,WebStandardStreamableHTTPServerTransportnever settles the original POST.Reproduction on
mainMcpServerwith one tool that waits for its request to be aborted,enableJsonResponse: true, POSTtools/call, then cancel 50ms later:Cause
Protocol._oncancelaborts the handler's controller._onrequestthen drops both the result and the error for that id when the signal is aborted, sosend()never runs for it. The transport only clears_requestToStreamMapping, resolvesresolveJsonand closes the per-request SSE stream fromsend(). A cancelled request therefore keeps its stream mapping forever, and anything that counts in-flight work, expires idle sessions or caps concurrent sessions sees the session as permanently busy. Long agent runs cancel constantly, so the leak accumulates.Fix
Transport local, no change to the
Transportinterface. Cancellation reaches the transport throughonmessage, so the transport can settle the request itself when it seesnotifications/cancelled._deliverMessagewrapper callsonmessage, then settles the cancelled request.onmessagedispatch sites inhandlePostRequestroute through it, so a cancel sent in the same batch as its request is covered._settleCancelledRequestretires the id from both mappings. If an unresponded sibling still shares the stream, it leaves the stream open. Otherwise it resolves a JSON-mode POST with an empty 202, or cleans up the per-request SSE stream.After the fix, the same reproduction gives:
and the SSE variant ends the stream with
read done=true bytes=0.Tests
Three cases in
packages/server/test/server/streamableHttp.test.ts:All three fail on
main(each times out waiting for a POST that never settles) and pass with the change. The wholepackages/serversuite is green: 55 files, 677 tests. Typecheck, ESLint and Prettier are clean.No new dependencies.