From 5b41567b2e6c324434a1523bb9b8f71edd081eca Mon Sep 17 00:00:00 2001 From: Mrutunjay Kinagi Date: Tue, 17 Feb 2026 22:16:59 +0530 Subject: [PATCH 1/2] fix(auth): normalize empty optional client metadata URIs --- src/mcp/shared/auth.py | 7 +++++++ tests/client/test_auth.py | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/mcp/shared/auth.py b/src/mcp/shared/auth.py index bf03a8b8d..eba4ca0e3 100644 --- a/src/mcp/shared/auth.py +++ b/src/mcp/shared/auth.py @@ -68,6 +68,13 @@ class OAuthClientMetadata(BaseModel): software_id: str | None = None software_version: str | None = None + @field_validator("client_uri", "logo_uri", "tos_uri", "policy_uri", "jwks_uri", mode="before") + @classmethod + def normalize_empty_optional_uris(cls, v: Any) -> Any: + if v == "": + return None + return v + def validate_scope(self, requested_scope: str | None) -> list[str] | None: if requested_scope is None: return None diff --git a/tests/client/test_auth.py b/tests/client/test_auth.py index 5aa985e36..a3a24bc10 100644 --- a/tests/client/test_auth.py +++ b/tests/client/test_auth.py @@ -83,6 +83,23 @@ def valid_tokens(): ) +def test_oauth_client_metadata_treats_empty_optional_uris_as_none(): + metadata = OAuthClientMetadata( + redirect_uris=[AnyUrl("http://localhost:3030/callback")], + client_uri="", + logo_uri="", + tos_uri="", + policy_uri="", + jwks_uri="", + ) + + assert metadata.client_uri is None + assert metadata.logo_uri is None + assert metadata.tos_uri is None + assert metadata.policy_uri is None + assert metadata.jwks_uri is None + + @pytest.fixture def oauth_provider(client_metadata: OAuthClientMetadata, mock_storage: MockTokenStorage): async def redirect_handler(url: str) -> None: From e9a78ec5099ac71e7c7a9f36beabdbb5e9a4e23d Mon Sep 17 00:00:00 2001 From: Mrutunjay Kinagi Date: Wed, 18 Feb 2026 00:02:42 +0530 Subject: [PATCH 2/2] test(auth): avoid pyright arg-type errors in empty-uri regression --- tests/client/test_auth.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tests/client/test_auth.py b/tests/client/test_auth.py index a3a24bc10..c85df032b 100644 --- a/tests/client/test_auth.py +++ b/tests/client/test_auth.py @@ -84,13 +84,15 @@ def valid_tokens(): def test_oauth_client_metadata_treats_empty_optional_uris_as_none(): - metadata = OAuthClientMetadata( - redirect_uris=[AnyUrl("http://localhost:3030/callback")], - client_uri="", - logo_uri="", - tos_uri="", - policy_uri="", - jwks_uri="", + metadata = OAuthClientMetadata.model_validate( + { + "redirect_uris": ["http://localhost:3030/callback"], + "client_uri": "", + "logo_uri": "", + "tos_uri": "", + "policy_uri": "", + "jwks_uri": "", + } ) assert metadata.client_uri is None