Skip to content

Commit 3630558

Browse files
author
冯基魁
committed
fix: normalize OAuth redirect URI URL subtypes
1 parent ad81ca2 commit 3630558

2 files changed

Lines changed: 24 additions & 2 deletions

File tree

src/mcp/shared/auth.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,13 @@ class OAuthClientMetadata(BaseModel):
8484
software_id: str | None = None
8585
software_version: str | None = None
8686

87+
@field_validator("redirect_uris", mode="before")
88+
@classmethod
89+
def _coerce_redirect_uris_to_any_url(cls, v: object) -> object:
90+
if isinstance(v, list):
91+
return [str(item) if isinstance(item, AnyUrl) else item for item in v]
92+
return v
93+
8794
@field_validator(
8895
"client_uri",
8996
"logo_uri",

tests/shared/test_auth.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
"""Tests for OAuth 2.0 shared code."""
22

33
import pytest
4-
from pydantic import ValidationError
4+
from pydantic import AnyHttpUrl, AnyUrl, ValidationError
55

6-
from mcp.shared.auth import OAuthClientInformationFull, OAuthClientMetadata, OAuthMetadata
6+
from mcp.shared.auth import InvalidRedirectUriError, OAuthClientInformationFull, OAuthClientMetadata, OAuthMetadata
77

88

99
def test_oauth():
@@ -109,6 +109,21 @@ def test_valid_url_passes_through_unchanged():
109109
assert str(metadata.client_uri) == "https://udemy.com/"
110110

111111

112+
def test_redirect_uri_url_subtypes_are_normalized_for_validation():
113+
client = OAuthClientInformationFull(
114+
client_id="abc123",
115+
redirect_uris=[AnyHttpUrl("https://example.com/callback")],
116+
)
117+
118+
redirect_uri = AnyUrl("https://example.com/callback")
119+
assert redirect_uri in (client.redirect_uris or [])
120+
assert client.validate_redirect_uri(redirect_uri) == redirect_uri
121+
assert client.model_dump(mode="json")["redirect_uris"] == ["https://example.com/callback"]
122+
123+
with pytest.raises(InvalidRedirectUriError):
124+
client.validate_redirect_uri(AnyUrl("https://example.com/other"))
125+
126+
112127
def test_information_full_inherits_coercion():
113128
"""OAuthClientInformationFull subclasses OAuthClientMetadata, so the
114129
same coercion applies to DCR responses parsed via the full model."""

0 commit comments

Comments
 (0)