Incorrect call for resource_metadata_url
Describe the bug After a failed initial request MCP Inspector doesn't request the metadata from the supplied resource_metadata_url.
To Reproduce
- I have a development MCP server, HTTP Streamable configured at mydummymcp.com/mcp
- The initial request fails with a 401 as expected. We return a response header:
WWW-Authenticate: Bearer realm="mcp-server"
and a response body:
{
"error": {
"code": "AUTHENTICATION_REQUIRED",
"message": "Authentication required to access this MCP server"
},
"auth": {
"type": "oidc",
"client_id": "XXXXYYYYZZZ",
"resource_metadata_url": "https://mydummymcp.com/.well-known/oauth-protected-resource/",
"scope": "openid basic"
}
}
The next request from MCP Inspector is to https://mydummymcp.com/.well-known/oauth-protected-resource/mcp
After several failed requests (CORS requests returning 400) it tries https://mydummymcp.com/.well-known/oauth-protected-resource. We return a 301 to the because of the missing / which also leads to a CORS failure
Expected behavior After the 401 I would expect a request to "https://mydummymcp.com/.well-known/oauth-protected-resource/"
Not sure if this behaviour is actually supported yet. MCP Authorisation workflows seem in a state of flux
However if I change the WWW-Authenticate header to return Bearer realm="mcp-server" resource_metadata= "https://mydummymcp/.well-known/oauth-protected-resource/" it still fails in the same way with the next request being for https://mydummymcp/.well-known/oauth-protected-resource/mcp
linked: https://github.com/modelcontextprotocol/inspector/issues/675
@ocasta your experience the same as i, when mcp is running on "/mcp" it append mcp for some reason, not intended according to spec.
and step 3 of https://modelcontextprotocol.io/specification/draft/basic/authorization#server-metadata-discovery where it should go when the others dont work is never happening.
Also experiencing the same RFC 9728 non-compliance with a subdomain-based architecture (splitting MCP & auth servers by subdomain instead of route), e.g.
- MCP Server: mcp.my-app.com
- Auth Server: auth.my-app.com
Expected behaviour (per RFC 9728):
- GET https://mcp.my-app.com -> return 401 with WWW-Authenticate: Bearer resource_metadata="https://auth.my-app.com/.well-known/oauth-protected-resource"
- Inspector should fetch metadata from https://auth.my-app.com/.well-known/oauth-protected-resource and proceed with OAuth flow after discovering auth server
Actual behaviour:
- Inspector completely ignores the resource_metadata pointing to the auth subdomain well-known endpoint
- Instead, inspector makes OPTIONS + GET requests to https://mcp.my-app.com/.well-known/oauth-protected-resource (note the subdomain - the well-known path is correct, but the subdomain SHOULD be auth.my-app.com, NOT mcp.my-app.com)
My auth & mcp handlers are actually in the same place despite being on different subdomains, so for now I just add this hack which seems to "fix" the flow using the inspector. After it reads the well-known metadata, the oauth redirect flow kicks in.
// MCP subdomain - handles MCP protocol at root path
if (hostname === "mcp.my-app.com") {
// HACK for MCP non-compliant inspector
if (url.pathname === "/.well-known/oauth-protected-resource") {
return new Response(JSON.stringify({
resource: "https://mcp.my-app.com",
authorization_servers: ["https://auth.my-app.com"]
}), {
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}
});
}
}
As an aside, recently I also had issues getting a custom remote server working with claude.ai. Here, I used /v1/mcp as my canonical URL instead of a subdomain.
If Claude got "lost" after the initial expected 401, it would then - seemingly randomly - attempt to find endpoints itself by appending /v1/mcp to everything, e.g. my-app.com/.well-known/.../v1/mcp. Those paths clearly don't exist so it was very bizarre. Perhaps there's some logic embedded deep in the SDK to try various endpoint discovery heuristics in case of a 404.
Anyway, just sharing my 2 cents. I don't think I really know what I'm doing or talking about after this ordeal so take it all with a grain of salt.
Hi, wanted to check if this was still reproducible in the latest version? There were several updates related to auth recently so trying to nail down which of these should still be open. Thanks!
@olaservo Still problematic.
Seems related to https://github.com/modelcontextprotocol/inspector/issues/576.
Like @ptc-ccrabb mentioned, the RFC9728 is pretty clear that the first request made should be to the resource itself, which will explain how it is protected. Then it should acquire the protected resource metadata based on the URI from the WWW-Authenticate. This makes so much more sense then having a set of hardcoded rules and trying out different URI permutations.
I am also seeing this behaviour. FWIW I also saw this behaviour in VSCode. It seems you have to design the mcp server distribution to expect this to be ignored at the moment.