modelcontextprotocol / modelcontextprotocol/python-sdk

`OAuthClientInformationFull.redirect_uris`: pydantic strict-type-equality breaks `AnyUrl(x) != AnyHttpUrl(x)` round-trip

Đang mở
#2,687 3 bình luận 0 reaction 0 người được giao Xem trên GitHub

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

auth bug fix proposed P2 ready for work
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ả

Summary
When implementing a custom OAuth provider against the MCP Python SDK, callers must construct OAuthClientInformationFull instances. The SDK declares redirect_uris: list[AnyUrl] (where AnyUrl is pydantic's base URL type). Passing pydantic's stricter subtype AnyHttpUrl (or any other AnyUrl subtype) causes silent equality failures downstream: AnyUrl("https://...") == AnyHttpUrl("https://...") returns False in pydantic v2, even when the two URLs serialize identically. This breaks redirect_uri matching during the /authorize/token exchange.
Reproducer

from pydantic import AnyUrl, AnyHttpUrl
from mcp.server.auth.provider import OAuthClientInformationFull

# pydantic v2 strict-type equality
u1 = AnyUrl("https://example.com/callback")
u2 = AnyHttpUrl("https://example.com/callback")
assert str(u1) == str(u2)   # True (both render the same)
assert u1 == u2              # FAILS in pydantic v2 — different runtime types

# Concrete impact in OAuth flow:
client_info = OAuthClientInformationFull(
    client_id="test",
    redirect_uris=[AnyHttpUrl("https://example.com/cb")],
    # ...other required fields
)
# When the /authorize request arrives with redirect_uri parameter, the SDK
# constructs an AnyUrl from the query string and checks membership:
incoming = AnyUrl("https://example.com/cb")
assert incoming in client_info.redirect_uris   # FAILS — type mismatch

Expected behavior
OAuthClientInformationFull.redirect_uris should accept and compare-equal across AnyUrl and AnyUrl subtypes (AnyHttpUrl, AnyHttpsUrl, etc.) when the underlying URL is identical.
Actual behavior
Strict-type equality causes the membership check to fail. The OAuth flow returns a generic redirect-mismatch error to the client; the underlying cause (type vs URL mismatch) is invisible without instrumenting the SDK.
Suggested fix
Two options:
Coerce on assignment. Have OAuthClientInformationFull.redirect_uris field validator coerce all values to AnyUrl (the declared base type), regardless of what the caller passes. This is the cleanest fix and matches the field declaration.
Compare-by-string. Override __eq__ on the AnyUrl chain to compare-by-str() rather than by runtime type. Broader-impact change; probably not desirable.
Option 1 is preferred. A short field_validator with mode="before" converting to AnyUrl strings before pydantic instantiates would do it.
Workaround (current PolyBot mitigation)
Pass redirect_uris as raw list[str]; pydantic coerces to AnyUrl per the field declaration. This avoids the type mismatch:

client_info = OAuthClientInformationFull(
    client_id="test",
    redirect_uris=["https://example.com/cb"],   # raw strings, not AnyHttpUrl
    # ...
)

Works at runtime; loses some IDE type hints in the caller code.
Environment
mcp Python SDK version: 1.27.1
pydantic version: 2.x
Python: 3.11+
Related code locations
In the MCP SDK:
mcp/server/auth/provider.pyOAuthClientInformationFull definition with redirect_uris: list[AnyUrl]
mcp/server/auth/handlers/authorize.py — where the membership check happens
Severity
Medium — silently breaks OAuth flows in custom-provider setups; reproducer is simple; workaround is trivial once known but the failure mode is hard to diagnose from the user-facing error.

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 tại mcp/server/auth/provider.py, ở OAuthClientInformationFull, và theo dõi việc xác thực redirect_uris, sau đó kiểm tra phép kiểm tra membership trong mcp/server/auth/handlers/authorize.py. Tái hiện mismatch AnyUrl/AnyHttpUrl bằng ví dụ trong issue và bổ sung regression coverage cho các đầu vào subtype. Công việc được xem là hoàn tất khi các URL tương đương được so sánh thành công trong luồng authorize-to-token mà không yêu cầu caller truyền các raw string.

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
authentication, backend
Loại issue
Lỗi
Độ khó
3/5
Thời gian dự kiến
1-2 ngày
Mức độ hoạt động
Ít trao đổi
Độ rõ ràng
Đặc tả rõ ràng
Mức phù hợp với người mới
72/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.