Skip to content

[v1.x] fix: make request responder completion idempotent#2949

Open
fengjikui wants to merge 1 commit into
modelcontextprotocol:v1.xfrom
fengjikui:codex/request-responder-cancel-race
Open

[v1.x] fix: make request responder completion idempotent#2949
fengjikui wants to merge 1 commit into
modelcontextprotocol:v1.xfrom
fengjikui:codex/request-responder-cancel-race

Conversation

@fengjikui

Copy link
Copy Markdown
Contributor

Fixes #2416.

Summary

  • make RequestResponder.respond() return without sending a second response when the responder has already completed
  • make RequestResponder.cancel() cancel the active scope but skip the cancellation error response if a normal response already completed the request
  • add focused regression coverage for both respond-after-cancel and cancel-after-respond orderings

Root cause

A cancellation notification can complete a responder and send the cancellation error before a late respond() call reaches RequestResponder.respond(). The existing assertion then raises AssertionError: Request already responded to, which can break the session even though one JSON-RPC response has already won the race.

Validation

  • uv run --frozen pytest tests/shared/test_session.py -q --tb=short --maxfail=1
  • uv run --frozen pyright src/mcp/shared/session.py tests/shared/test_session.py
  • uv run --frozen ruff check src/mcp/shared/session.py tests/shared/test_session.py
  • uv run --frozen ruff format --check src/mcp/shared/session.py tests/shared/test_session.py
  • git diff --check
  • local repro script now prints PASS: no AssertionError; responses=1

AI assistance was used to prepare this change; I reviewed and validated the final diff.

@fengjikui fengjikui marked this pull request as ready for review June 22, 2026 16:16
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