Repository navigation
The resource URL path is ignored when building the protected resource metadata URL #1052
Description
Initial Checks
- I confirm that I'm using the latest version of MCP Python SDK
- I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening this issue
Description
The current MCP Server implementation appears to use a fixed URL pattern [domain]/.well-known/oauth-protected-resource for the protected resource URL. After reviewing RFC9728, I believe this doesn't fully align with the specification's requirements.
Expected behavior:
If the resource URL is https://resource.example.com/resource1, the protected resource metadata URL to be https://resource.example.com/.well-known/oauth-protected-resource/resource1
Current behavior:
If the resource URL is https://resource.example.com/resource1, the protected resource metadata URL to be https://resource.example.com/.well-known/oauth-protected-resource
Link to the source code:
python-sdk/src/mcp/server/auth/routes.py
Line 219 in 7942184
| "/.well-known/oauth-protected-resource", |
return [
Route(
"/.well-known/oauth-protected-resource",
endpoint=cors_middleware(handler.handle, ["GET", "OPTIONS"]),
methods=["GET", "OPTIONS"],
)
]
RFC 9728
Protected resources supporting metadata MUST make a JSON document containing metadata as specified in Section 2 available at a URL formed by inserting a well-known URI string into the protected resource's resource identifier between the host component and the path and/or query components, if any.
...
The consumer of the metadata would make the following request when the resource identifier is https://resource.example.com/resource1 and the well-known URI path suffix is oauth-protected-resource to obtain the metadata, since the resource identifier contains a path component:GET /.well-known/oauth-protected-resource/resource1 HTTP/1.1
Host: resource.example.com
As the RFC correctly states:
Using path components enables supporting multiple resources per host. This is required in some multi-tenant hosting configurations.
which is difficult to achieve with the current implementation.
Example Code
Python & MCP Python SDK
Latest version
Activity
pcarleton commentedon Jul 4, 2025
Hi @yurikunash thanks for opening this, I agree with you that we don't implement the more involved path discovery flow currently, and think we should add it like you've described.
One somewhat finicky nuance is the definition of "resource identifier" that I've had explained to me:
The server can define the resource identifier to be different than the initial request path. For example, the request might be to
https://mcp.example.com/v1/mcp, but the resource identifier could behttps://mcp.example.com/v1orhttps://mcp.example.com/if that's how the server organizes things. The resource identifier is meant to be resource being protected, which might be broader than just the MCP endpoint.Since we're doing this all dynamically, we can only rely on what the server gives us to determine the resource identifier, and then fallback to defaults. The server can provide context in the
WWW-Authenticateheader. If it's not there though, we're stuck guessing. The way it is currently is implicitly always assuming it's the base URL, but we should instead check the request URL first, and then check the base URL. (We recently added this behavior for the AS metadata as well, so we can likely re-use some of that.)yurikunash commentedon Jul 16, 2025
Hi @pcarleton, thank you for your comments. I want to share my simple thoughts on that.
The FastMCP class exposes a setting
settings.auth.resource_server_url. So, why should we guess about the resource identifier and the path, instead of sticking to the value that the server developer has provided through that setting?I hope you can either confirm or help find the gap.
maxisbey commentedon Jun 5, 2026
Both halves of this are implemented and released:
build_resource_metadata_url(), which inserts/.well-known/oauth-protected-resourcebetween the host and the resource path per RFC 9728 §3.1, and the metadata route is now registered at that path-based URL (theWWW-Authenticateresource_metadatahint uses it too). The URL is built directly from theresource_server_urlyou configure, so the server-provided resource identifier is used as-is rather than guessed. Released in v1.17.0.resource_metadataURL from theWWW-Authenticateheader first, then the path-based well-known URI, then fall back to the root-based one. Released in v1.21.0.Both changes are also on
main(v2), and the current v1.x release (v1.27.2) carries them. Using the example from this issue: a server configured withresource_server_url=https://resource.example.com/resource1now serves metadata athttps://resource.example.com/.well-known/oauth-protected-resource/resource1.The remaining sharp edge — configurations where
resource_server_urlomits the transport path, making the metadataresourcefield mismatch what strict clients resolve — is tracked separately in #1264.Closing as resolved.
AI Disclaimer