Skip to content

Retire caller-supplied numeric request ids against future mints - #3367

Closed
Parker-Fawcett wants to merge 1 commit into
modelcontextprotocol:mainfrom
Parker-Fawcett:fix/3126-no-request-id-reuse-after-completion
Closed

Retire caller-supplied numeric request ids against future mints#3367
Parker-Fawcett wants to merge 1 commit into
modelcontextprotocol:mainfrom
Parker-Fawcett:fix/3126-no-request-id-reuse-after-completion

Conversation

@Parker-Fawcett

Copy link
Copy Markdown

Retire caller-supplied numeric request ids against future mints

Fixes #3126

What

A caller-supplied CallOptions["request_id"] left the dispatcher's in-flight tracking once its request completed, so the minted-id sequence eventually landed on that same id again — two different requests with one id on the wire, which the spec forbids:

The request ID MUST NOT have been previously used by the requestor within the same session.

Reproduced on main: supply id 1, let it complete, mint three requests → wire ids [1, 1, 2, 3].

How

Accepted numeric supplied ids are added to a small retired set on both dispatchers; minting skips in-flight ∪ retired and prunes retired entries as the monotonic counter passes them (so the set stays bounded by ids the counter hasn't reached yet).

Deliberate deviation from the fix sketched on the issue

The issue proposed advancing the counter at accept time (max(self._next_id, pending_key)). That variant also burns every id below a supplied one whenever it is accepted while still in flight, flipping the documented contract in test_minted_ids_skip_a_caller_supplied_id_still_in_flight from mints [1, 2, 4] to [4, 5, 6]. The retire-set fixes reuse with zero change to existing behavior:

Scenario Before After
Supplied 1 completes → mints [1, 1, 2] [2, 3, 4]
Supplied "7" completes → mints walk 9 [1..9] reuses 7 ❌ [1..6, 8, 9, 10]
Supplied "3" in flight → mints [1, 2, 4] unchanged

If maintainers prefer the simpler accept-time advancement and adjusting the in-flight expectation instead, that tradeoff is yours to call — happy to rework.

Tests

Both regression tests run through the shared pair_factory, so each covers JSONRPCDispatcher and DirectDispatcher:

  • completed numeric supplied id is never revisited ([2, 3, 4])
  • completed numeric-string supplied id retires its coerced twin ([1..6, 8, 9, 10])

Full gate green locally: ./scripts/test, ruff format/check, pyright.

(AI-assisted implementation, prepared with a coding agent and reviewed by me.)

A caller-supplied id left the dispatcher's in-flight set once its
request completed, so the minted-id sequence eventually landed on the
same id again - the spec forbids reusing an id within a session.

Accepted numeric supplied ids are now retired until the monotonic
counter passes them, on both JSONRPCDispatcher and DirectDispatcher.
Minting skips retired keys alongside in-flight ones and prunes them as
the counter advances, preserving the existing behavior where mints
keep using low ids around a still-in-flight supplied id.

Fixes modelcontextprotocol#3126
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for the contribution. This repository only keeps pull requests open when they're linked to an issue that a maintainer has assigned to the author — CONTRIBUTING.md explains why and how we work. This PR has been closed for now because you aren't currently assigned to #3126.

If a maintainer would like this change as a PR from you, they'll assign you to #3126 and this PR will reopen automatically — there's nothing more you need to do. (If you opened the issue, this PR already shows up on its timeline.)

There's no need to open a new PR — this one will be reopened. While it's closed, please push any updates as new commits rather than force-pushing, since GitHub can't reopen a PR whose branch has been rewritten.

Maintainers: reopening this PR, removing the missing-issue-link label, or adding bypass-issue-check bypasses the check.

@github-actions github-actions Bot added the missing-issue-link Auto-closed: PR needs a linked issue assigned to its author (see CONTRIBUTING.md) label Aug 23, 2026
@github-actions github-actions Bot closed this Aug 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

missing-issue-link Auto-closed: PR needs a linked issue assigned to its author (see CONTRIBUTING.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dispatcher mints a request id already used by a completed caller-supplied request (spec: ids MUST NOT be reused in a session)

1 participant