modelcontextprotocol / modelcontextprotocol/python-sdk

coerce_request_id() folds non-canonical numeric strings, conflating wire-distinct JSON-RPC ids

Đang mở Phù hợp với người mới
#3,432 4 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

v1 v2
Ngôn ngữ chính
Python
Star
24.3k
Fork
4k
Merge trung bình
1 ngày 1 giờ
Pull request đã merge (30 ngày)
31

Mô tả

Initial Checks
Release line

2.x (current stable)

Description

On current main, coerce_request_id() in src/mcp/shared/dispatcher.py folds a stringified id to int with a bare int(request_id). That accepts a lot more than a canonical integer string, so ids that are distinct on the JSON-RPC wire collapse onto one correlation key:

coerce_request_id('007')   -> 7
coerce_request_id('+7')    -> 7
coerce_request_id('1_000') -> 1000
coerce_request_id(' 7 ')   -> 7
coerce_request_id('٧')     -> 7

This shared key backs _pending (response correlation), _in_flight (cancellation), and progress-token routing. So a peer, or a caller using CallOptions["request_id"], that uses e.g. 10 and "1_0" as two ids has them merged. A notifications/cancelled for one hits the other, and the first can't be cancelled. It's the same cross-wiring class as #3060, but between ids that are genuinely different on the wire.

JSON-RPC 2.0 treats String and Number ids as distinct value types, and the function's own intent (and its test, "7" -> 7) is the canonical "peer stringified an int" case. The forms above aren't that. They're an artifact of Python's int(). The docstring says "matches the TS SDK", but JS Number("1_000") is NaN and Number("0x10") is 16, so today's behavior matches neither.

The narrow fix is to fold only when the string equals str(int(s)), which keeps the intended "7" -> 7 and "-3" -> -3 behavior and leaves every other string a distinct id. I have a patch and a regression test for it (both dispatchers share the function) and I'm happy to open a PR once this is triaged and assigned.

Disclosure: I used an AI coding assistant to help explore the code and draft this. I verified the reproduction and understand the fix myself.

Example Code
from mcp.shared.dispatcher import coerce_request_id

for raw in ("007", "+7", "1_000", " 7 ", "٧"):
    print(repr(raw), "->", repr(coerce_request_id(raw)))
# every line prints an int, so all five distinct wire ids share one key
Python & MCP Python SDK

Python 3.11.14, python-sdk main @ 5bc9e07, macOS

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Bắt đầu trong src/mcp/shared/dispatcher.py tại coerce_request_id() và đọc test hiện có của nó để hiểu hành vi dự kiến khi chuyển "7" thành 7. Thêm coverage hồi quy cho các chuỗi số không canonical và xác minh rằng các wire id khác nhau vẫn khác nhau trong các response đang chờ, việc hủy và định tuyến progress-token.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
python
Lĩnh vực
api, backend
Loại issue
Lỗi
Độ khó
2/5
Thời gian dự kiến
1-3 giờ
Mức độ hoạt động
Sôi nổi
Độ rõ ràng
Đặc tả rõ ràng
Mức phù hợp với người mới
84/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.