Skip to content

fix(server): settle in-flight JSON-mode requests and release their stream mappings (v1.x) - #2747

Open
lvyanyan wants to merge 1 commit into
modelcontextprotocol:v1.xfrom
lvyanyan:fix-2559-json-lifecycle-v1x
Open

fix(server): settle in-flight JSON-mode requests and release their stream mappings (v1.x)#2747
lvyanyan wants to merge 1 commit into
modelcontextprotocol:v1.xfrom
lvyanyan:fix-2559-json-lifecycle-v1x

Conversation

@lvyanyan

@lvyanyan lvyanyan commented Sep 2, 2026

Copy link
Copy Markdown

Fixes #2559 (v1.x half — the main-branch close-settle half is drafted in #2584)

What

On v1.x, JSON response mode has two lifecycle gaps:

  1. Leak: when all responses are ready, send() resolves the pending HTTP response but never runs the stream mapping's cleanup, so every completed POST leaves one _streamMapping entry behind until close(). Long-lived sessions accumulate one entry per request. (main got the equivalent fix in Implement MCP 2026-07-28 #2286; it was never carried to v1.x — as noted on the issue, this is what currently ships as 1.30.0.)
  2. Hang: conversely, cleanup() only deleted the map entry without settling the Promise<Response> returned by handleRequest(). close() runs every mapping's cleanup, but for a JSON-mode POST still waiting on its handler that cleanup settled nothing — so the HTTP request hung until the client timed out.

Fix

  • The JSON-ready branch of send() now calls stream.cleanup() right after resolving, mirroring main's Implement MCP 2026-07-28 #2286.
  • The JSON-mode mapping's cleanup() now settles the pending POST with a 503 JSON-RPC error (-32000), aligned with the approach drafted for main in fix(server): settle in-flight JSON-mode requests on transport close #2584. On the success path send() has already resolved before cleanup() runs, and re-resolving a settled promise is a no-op, so the new resolve only fires when nothing was ever sent.

Tests

  • settles an in-flight JSON-mode request when the transport closes mid-handler — the tool handler signals it has started, close() lands while it is genuinely parked, and the POST must resolve 503 with the JSON-RPC error payload instead of hanging.
  • releases the JSON-mode stream mapping once the response has been sent_streamMapping.size must be 0 after a completed JSON-mode POST (on unpatched v1.x this fails with 2: the request's mapping plus initialize's).

Both tests fail on unpatched v1.x and pass with the fix. Full suite: 1647 passed (the two unhandled stdio SyntaxErrors reproduce on pristine v1.x and are unrelated).

…ream mappings

Two lifecycle bugs in JSON response mode on v1.x, tracked in modelcontextprotocol#2559:

- send() resolved the pending HTTP response but never ran the mapping's
  cleanup, so every completed POST left one _streamMapping entry behind
  until close() (main got the equivalent of this in modelcontextprotocol#2286).
- conversely, cleanup() only deleted the map entry without settling the
  Promise<Response> returned by handleRequest(), so close() during an
  in-flight JSON-mode POST left the HTTP request hanging until the client
  timed out. cleanup() now resolves it with a 503 JSON-RPC error; on the
  success path send() has already resolved, and re-resolving is a no-op.

Fix modelcontextprotocol#2559 (v1.x half; the main-branch close-settle half is drafted in modelcontextprotocol#2584)
@lvyanyan
lvyanyan requested a review from a team as a code owner September 2, 2026 15:26
@changeset-bot

changeset-bot Bot commented Sep 2, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 24eae34

The changes in this PR will be included in the next version bump.

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

@pkg-pr-new

pkg-pr-new Bot commented Sep 2, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@modelcontextprotocol/sdk@2747

commit: 24eae34

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.

1 participant