Repository navigation
Protected Resource Metadata resource erroneous when setting up authentication on server #1264
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
I am getting the following error when I try to enable MCP server authentication and configure it in VSCODE copilot:
Error Error sending message to http://localhost:8000/mcp: Error: Protected Resource Metadata resource "http://localhost:8000/" does not match MCP server resolved resource "http://localhost:8000/mcp". The MCP server must follow OAuth spec https://datatracker.ietf.org/doc/html/rfc9728#PRConfigurationValidation
From what I have seen, the error is caused because the metada that is returned in the endpoint "/.well-known/oauth-protected-resource" in the resource field does not match the url of the MCP server to be configured to use copilot and what is specified in the definition if they should match. You can see here https://datatracker.ietf.org/doc/html/rfc9728#PRConfigurationValidation
I have made a small snippet of code available here https://github.com/carlosemart/python-mcp-oauth-example in which you can see that the well-know answer is:
{
"resource": "http://localhost:8000/",
"authorization_servers": [
"https://auth.example.com/"
],
"scopes_supported": [
"user"
],
"bearer_methods_supported": [
"header"
]
}and in the resource field you should see "http://localhost:8000/mcp" which is the url that is configured in VSCODE.
Example Code
from mcp.server.auth.provider import AccessToken, TokenVerifier
from mcp.server.auth.settings import AuthSettings
from mcp.server.fastmcp import FastMCP
from pydantic import AnyHttpUrl
class SimpleTokenVerifier(TokenVerifier):
"""Simple token verifier for demonstration."""
async def verify_token(self, token: str) -> AccessToken | None:
return AccessToken(
token=token,
scopes=["user"],
)
# Create an MCP server
mcp = FastMCP(
"Demo",
stateless_http=True,
# Token verifier for authentication
token_verifier=SimpleTokenVerifier(),
# Auth settings for RFC 9728 Protected Resource Metadata
auth=AuthSettings(
issuer_url=AnyHttpUrl("https://auth.example.com"), # Authorization Server URL
resource_server_url=AnyHttpUrl("http://localhost:8000"), # This server's URL
required_scopes=["user"],
),
)
# Add an addition tool
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
# Add a dynamic greeting resource
@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
"""Get a personalized greeting"""
return f"Hello, {name}!"
# Add a prompt
@mcp.prompt()
def greet_user(name: str, style: str = "friendly") -> str:
"""Generate a greeting prompt"""
styles = {
"friendly": "Please write a warm, friendly greeting",
"formal": "Please write a formal, professional greeting",
"casual": "Please write a casual, relaxed greeting",
}
return f"{styles.get(style, styles['friendly'])} for someone named {name}."
def main():
"""Entry point for the direct execution server."""
mcp.run(transport="streamable-http")
if __name__ == "__main__":
main()
Python & MCP Python SDK
Tested with python version 3.11.9 and 3.12.5, and MCP Python SDK 1.12.4 version
Activity
seanhoughton commentedon Aug 12, 2025
I ran into the same problem. The workaround I'm using is to define my own well known endpoint and replace the generated one. Not ideal, but I think this is the simplest and least intrusive workaround until the problem is fixed.
And then add it to the routes
JoseIbanez commentedon Sep 10, 2025
Hi @carlosemart same issue here
I think the issue is in this code:
python-sdk/src/mcp/server/fastmcp/server.py
Lines 934 to 938 in 47d35f0
We could fix with:
My workarround is define a child class of FastMCP:
I got VSCODE to work
francisco-perez-sorrosal commentedon Oct 28, 2025
I had the same problem; I applied the same FastMCP-wrapper, implementing the routing workaround as @JoseIbanez / @seanhoughton and also got my authentication code working.
Br1an67 commentedon Mar 1, 2026
I'd like to work on this. The
resourcefield in Protected Resource Metadata was set to the baseresource_server_urlwithout the transport path—appending the path (e.g.,/mcpor/sse) fixes the RFC 9728 validation mismatch.PR: #2189
0809android commentedon Aug 9, 2026
I would like to take the docs/example follow-up described in the review of #2189.
I verified on current
mainthat:examples/snippets/servers/oauth_server.pystill configuresresource_server_urlwithout/mcp.AuthSettings.resource_server_urldoes not say that it must be the complete public MCP resource URL, including the transport path.--transport=ssewhile its default resource URL is fixed to/mcp.I will not append an internal Starlette route in library code; that would break mounted apps and reverse proxies. The proposed PR will update the examples and API documentation so the configured resource identifier matches the public endpoint for the selected transport, with focused tests for the example configuration.
If that scope is still wanted, please assign this issue to me.
AI assistance disclosure: I used Codex to inspect current
main, the closed #2189 review, and the affected examples. I verified the file locations and proposed scope in the local checkout.Ecocitizenz commentedon Aug 9, 2026
slowe89 commentedon Sep 9, 2026
+1 — this is the classic Inspector-green / real-client-red seam: PRM
resourcevs endpoint path mismatch (and trailing-slash identity) passes loose checks then fails strict RFC 9728 clients.We've been cataloguing those OAuth/PRM/needs-auth client gaps as a Compat Blind Spot Scorecard: https://compatlab-waitlist.vercel.app — permission-only. Happy to share other client-specific failure shapes back here if useful.