Skip to content

Commit d32f7c2

Browse files
committed
drop the PRM trailing-slash normalizer: superseded by #2925 (url_preserve_empty_path)
1 parent 1eef34d commit d32f7c2

2 files changed

Lines changed: 1 addition & 54 deletions

File tree

src/mcp/client/auth/oauth2.py

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -109,18 +109,6 @@ def check_registration_usable(client_info: OAuthClientInformationFull) -> None:
109109
)
110110

111111

112-
def _normalize_resource_url(resource: str) -> str:
113-
"""Undo the trailing slash URL parsers add to bare-domain URLs (e.g. pydantic's AnyHttpUrl).
114-
115-
RFC 9728 requires exact-string identity on the resource identifier, so only a root path
116-
with no query or fragment is stripped; trailing slashes on deeper paths are preserved.
117-
"""
118-
parsed = urlparse(resource)
119-
if parsed.path == "/" and not parsed.params and not parsed.query and not parsed.fragment:
120-
return f"{parsed.scheme}://{parsed.netloc}"
121-
return resource
122-
123-
124112
class PKCEParameters(BaseModel):
125113
"""PKCE (Proof Key for Code Exchange) parameters."""
126114

@@ -218,7 +206,7 @@ def get_resource_url(self) -> str:
218206

219207
# If PRM provides a resource that's a valid parent, use it
220208
if self.protected_resource_metadata and self.protected_resource_metadata.resource:
221-
prm_resource = _normalize_resource_url(str(self.protected_resource_metadata.resource))
209+
prm_resource = str(self.protected_resource_metadata.resource)
222210
if check_resource_allowed(requested_resource=resource, configured_resource=prm_resource):
223211
resource = prm_resource
224212

tests/client/test_auth.py

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -983,47 +983,6 @@ async def test_get_resource_url_uses_canonical_when_prm_mismatches(
983983
assert provider.context.get_resource_url() == snapshot("https://api.example.com/v1/mcp")
984984

985985

986-
@pytest.mark.anyio
987-
async def test_get_resource_url_removes_root_prm_trailing_slash(
988-
client_metadata: OAuthClientMetadata, mock_storage: MockTokenStorage
989-
) -> None:
990-
"""Bare-domain PRM resources should not pick up the trailing slash AnyHttpUrl adds."""
991-
provider = OAuthClientProvider(
992-
server_url="https://api.example.com",
993-
client_metadata=client_metadata,
994-
storage=mock_storage,
995-
)
996-
provider._initialized = True
997-
998-
# AnyHttpUrl normalizes "https://api.example.com" to "https://api.example.com/"
999-
provider.context.protected_resource_metadata = ProtectedResourceMetadata(
1000-
resource=AnyHttpUrl("https://api.example.com"),
1001-
authorization_servers=[AnyHttpUrl("https://auth.example.com")],
1002-
)
1003-
1004-
assert provider.context.get_resource_url() == snapshot("https://api.example.com")
1005-
1006-
1007-
@pytest.mark.anyio
1008-
async def test_get_resource_url_preserves_non_root_trailing_slash(
1009-
client_metadata: OAuthClientMetadata, mock_storage: MockTokenStorage
1010-
) -> None:
1011-
"""RFC 9728 requires exact-string identity, so intentional trailing slashes on deeper paths stay."""
1012-
provider = OAuthClientProvider(
1013-
server_url="https://api.example.com/v1/mcp/",
1014-
client_metadata=client_metadata,
1015-
storage=mock_storage,
1016-
)
1017-
provider._initialized = True
1018-
1019-
provider.context.protected_resource_metadata = ProtectedResourceMetadata(
1020-
resource=AnyHttpUrl("https://api.example.com/v1/mcp/"),
1021-
authorization_servers=[AnyHttpUrl("https://auth.example.com")],
1022-
)
1023-
1024-
assert provider.context.get_resource_url() == snapshot("https://api.example.com/v1/mcp/")
1025-
1026-
1027986
class TestRegistrationResponse:
1028987
"""Test client registration response handling."""
1029988

0 commit comments

Comments
 (0)