Skip to content

fix: preserve response ID and progress token types - #3071

Open
po-et wants to merge 3 commits into
modelcontextprotocol:mainfrom
po-et:fix/strict-request-id-matching
Open

po-et wants to merge 3 commits into
modelcontextprotocol:mainfrom
po-et:fix/strict-request-id-matching

Conversation

@po-et

@po-et po-et commented Oct 22, 2026 •

Copy link
Copy Markdown

Protocol converts incoming response IDs and progress tokens with Number(). A reply with id: "0" can therefore complete a pending request with numeric ID 0; string progress tokens can also reach a callback registered under numeric token 0.

Keep the original values for handler and timeout lookups. Unmatched messages follow the existing error path while the request remains available for its matching reply. A peer that previously answered numeric request 0 with string "0" must now preserve the numeric type. This removes the previous leniency; the changeset labels it as a patch.

This revisits the type-preserving changes proposed in #1775, which was closed over its large-number precision premise. These public-client tests demonstrate incorrect request correlation; JSON number parsing remains unchanged.

Validation after merging main 951fe560, using its frozen lockfile with Node 24.22.1 and pnpm 10.26.1 on macOS arm64:

  • All 25 request-identifier tests pass. With the original protocol module, earlier validation produced 15 failures and 10 passing controls. The explicit id: null case is a control: the existing message schema rejects it before correlation.
  • Core-internal: 1,836 tests pass; client: 1,086; server: 646. Six filesystem-cleanup or build-dependent test files were excluded. These 3,568 tests include the 25 identifier cases.
  • Core-internal, client and server type checks and package lint pass. The three changed files pass formatting.
  • A separate Codex review verified that the merge retains the upstream tree and the original three-file patch. Four independent controls pass, covering two concurrent public-client requests with out-of-order numeric/string IDs and progress, plus the newly merged OAuth refresh-scope behavior.

Full monorepo checks and production builds were not run. Tests use source aliases rather than existing distribution files. The client HTTP/SSE tests require localhost binding; the initial sandbox run was interrupted after an EPERM probe, then the same suite passed with local port access.

AI assistance: Codex assisted with implementation, tests and automated review.

@po-et
po-et requested a review from a team as a code owner October 22, 2026 17:08
@changeset-bot

changeset-bot Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 9a57629

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

This PR includes changesets to release 6 packages
Name Type
@modelcontextprotocol/client Patch
@modelcontextprotocol/server Patch
@modelcontextprotocol/codemod Patch
@modelcontextprotocol/core Patch
@modelcontextprotocol/server-legacy Patch
@modelcontextprotocol/core-internal Patch

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 Oct 22, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/@modelcontextprotocol/client@3071

@modelcontextprotocol/codemod

npm i https://pkg.pr.new/@modelcontextprotocol/codemod@3071

@modelcontextprotocol/core

npm i https://pkg.pr.new/@modelcontextprotocol/core@3071

@modelcontextprotocol/server

npm i https://pkg.pr.new/@modelcontextprotocol/server@3071

@modelcontextprotocol/server-legacy

npm i https://pkg.pr.new/@modelcontextprotocol/server-legacy@3071

@modelcontextprotocol/express

npm i https://pkg.pr.new/@modelcontextprotocol/express@3071

@modelcontextprotocol/fastify

npm i https://pkg.pr.new/@modelcontextprotocol/fastify@3071

@modelcontextprotocol/hono

npm i https://pkg.pr.new/@modelcontextprotocol/hono@3071

@modelcontextprotocol/node

npm i https://pkg.pr.new/@modelcontextprotocol/node@3071

commit: 9a57629

@claude claude Bot added the v2 Ideas, requests and plans for v2 of the SDK which will incorporate major changes and fixes label Oct 23, 2026
@arhancanli

Copy link
Copy Markdown

Read the diff (suite not run). Dropping Number(...) also closes a path the new tests do not name: the old Number(response.id) turned id: null into 0, so a JSON-RPC error response with a null id (what a peer sends for a parse error, per the spec) could settle the first outstanding request, which has id 0 and is usually initialize. With this change Map.get(null) misses and it lands in _onerror, which looks right. The "error response without an identifier" test omits id instead of sending id: null, so it exercises the undefined branch only. A case with id: null next to it would pin the behaviour that actually changed. Second, { id: "0" } replies from a peer that echoes numeric ids as strings used to work and now error; the changeset says so, which is fair, but the maintainers may want that called out as behaviour-breaking for lenient servers rather than a patch.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v2 Ideas, requests and plans for v2 of the SDK which will incorporate major changes and fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants