Skip to content

fix: remove JSON-RPC ID type coercion for spec-compliant strict matching - #2428

Closed
KeWang0622 wants to merge 1 commit into
modelcontextprotocol:mainfrom
KeWang0622:fix/remove-jsonrpc-id-type-coercion
Closed

KeWang0622 wants to merge 1 commit into
modelcontextprotocol:mainfrom
KeWang0622:fix/remove-jsonrpc-id-type-coercion

Conversation

@KeWang0622

Copy link
Copy Markdown

Summary

Remove the _normalize_request_id method that coerces string response IDs to integers. This restores spec-compliant strict ID matching as requested in #1795.

Problem

PR #1720 introduced automatic type coercion for JSON-RPC response IDs, allowing string IDs like "0" to match integer request IDs like 0. While this made the client more tolerant of non-compliant servers, it violates the JSON-RPC 2.0 and MCP specifications:

  • JSON-RPC 2.0: Response ID "MUST be the same as the value of the id member in the Request Object"
  • MCP Spec: Result/error responses "MUST include the same ID as the request they correspond to"

As @Kludex noted in #1795: "#1720 is not compliant" and "This should not be configurable!"

The coercion made request ID 1 and "1" interchangeable, which are semantically different values per the spec. Servers that echo back IDs in a different type are non-compliant and should not be worked around in the SDK.

Changes

src/mcp/shared/session.py:

  • Remove the _normalize_request_id method entirely
  • Use the response ID directly from the message without normalization

tests/shared/test_session.py:

  • Update test_response_id_type_mismatch_string_to_int and test_error_response_id_type_mismatch_string_to_int to verify that type-mismatched IDs are now correctly rejected (request times out) rather than silently coerced
  • The test_response_id_non_numeric_string_no_match test is unchanged since it already expected rejection

Verification

  • uv run --frozen ruff format . — no changes needed
  • uv run --frozen ruff check . — all checks passed
  • uv run --frozen pyright src/mcp/shared/session.py — 0 errors
  • uv run --frozen pytest tests/shared/test_session.py — 8/8 passed
  • strict-no-cover — no pragma issues

Closes #1795

Remove the _normalize_request_id method that was introduced in PR modelcontextprotocol#1720
to coerce string response IDs to integers. Per JSON-RPC 2.0 spec, the
response ID MUST be the same as the value of the id member in the
Request Object, which implies exact matching including type.

The type coercion made request ID 1 and "1" interchangeable, which
violates the spec. Servers that echo back IDs in a different type are
non-compliant and should not be worked around in the SDK.

Update tests to verify that type-mismatched IDs are correctly rejected
rather than silently coerced.

Github-Issue: modelcontextprotocol#1795
@maxisbey

maxisbey commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Thanks for the PR, and sorry it sat here without a proper review.

We're closing most of the open PR backlog. v2 is out and changed a lot of the SDK, so many older PRs no longer apply as written, and we're a small team that realistically doesn't have the capacity to work through the rest.

If this still matters to you on v2, the most useful thing you can do is open an issue (or comment on the existing one) with your use case and a repro. Hearing why it matters to you is what we use to decide what to prioritise.

AI Disclaimer

@maxisbey maxisbey closed this Oct 5, 2026
@maxisbey maxisbey added the missing-issue-link Auto-closed: PR needs a linked issue assigned to its author (see CONTRIBUTING.md) label Oct 5, 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.

Make JSON-RPC ID type coercion configurable

3 participants