fix(auth): strip trailing slashes from OAuth metadata URLs#3013
fix(auth): strip trailing slashes from OAuth metadata URLs#3013piyushbag wants to merge 4 commits into
Conversation
There was a problem hiding this comment.
1 issue found across 3 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/mcp/server/auth/routes.py">
<violation number="1" location="src/mcp/server/auth/routes.py:172">
P2: Issuer canonicalization is over-broad: `rstrip('/')` also rewrites non-root path issuers (e.g. `/tenant/` -> `/tenant`), which can break exact issuer identifier matching.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
| # Create metadata | ||
| metadata = OAuthMetadata( | ||
| issuer=issuer_url, | ||
| issuer=cast(AnyHttpUrl, str(issuer_url).rstrip("/")), |
There was a problem hiding this comment.
P2: Issuer canonicalization is over-broad: rstrip('/') also rewrites non-root path issuers (e.g. /tenant/ -> /tenant), which can break exact issuer identifier matching.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/mcp/server/auth/routes.py, line 172:
<comment>Issuer canonicalization is over-broad: `rstrip('/')` also rewrites non-root path issuers (e.g. `/tenant/` -> `/tenant`), which can break exact issuer identifier matching.</comment>
<file context>
@@ -169,7 +169,7 @@ def build_metadata(
# Create metadata
metadata = OAuthMetadata(
- issuer=issuer_url,
+ issuer=cast(AnyHttpUrl, str(issuer_url).rstrip("/")),
authorization_endpoint=authorization_url,
token_endpoint=token_url,
</file context>
Pydantic AnyHttpUrl adds a trailing slash to bare hostnames, which breaks RFC 8414/9728 exact issuer and resource comparison during OAuth discovery. Pass canonical URL strings into metadata models so served wire JSON omits the synthetic root slash. Fixes modelcontextprotocol#1919 and modelcontextprotocol#1265.
Update docs, stories, and tests that asserted trailing slashes on root issuer and authorization_server metadata fields after the routes.py fix.
Remove the Pydantic AnyUrl xfail now that routes.strip trailing slashes, and assert issuer against the canonical form.
a591757 to
c65b029
Compare
|
Rebased onto current Local: targeted auth route and metadata tests pass. |
build_metadata now serves path-less issuers without a trailing slash. Update authorize iss defaults, PRM/ASM overrides, and assertions so RFC 9207 string compares match the canonical metadata form.
|
CI failures were issuer string mismatches after the metadata slash strip ( Aligned the interaction auth fixtures and assertions with the canonical slash-free issuer. Local: full |
Summary
issuerinbuild_metadata()before constructingOAuthMetadataresourceand eachauthorization_serversentry increate_protected_resource_routes()url_preserve_empty_pathserialize without a synthetic root slashAnyHttpUrlissuer inputs and root-level protected-resource metadata responsesFixes #1919. Also fixes #1265.
Test plan
uv run pytest tests/server/auth/test_routes.py -quv run pytest tests/server/auth/test_protected_resource.py -quv run pytest tests/server/auth/ -quv run ruff check src/mcp/server/auth/routes.py tests/server/auth/test_routes.py tests/server/auth/test_protected_resource.pyuv run pyright src/mcp/server/auth/routes.py