anthropics / anthropics/claude-ai-mcp

Custom connector ignores authorization_servers in RFC 9728 PRM and assumes the MCP server is its own authorization server

Open
#984 2 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
No language data
Stars
471
Forks
76
PR merge metrics
No merged PRs in 30d

Description

### What happened?

A spec-compliant MCP resource server (revision 2026-07-28) advertises Microsoft
Entra as its authorization server via RFC 9728 Protected Resource Metadata. The
connector parses the PRM but ignores `authorization_servers`, then probes
`/.well-known/oauth-authorization-server` and `/authorize` at the MCP server's
own origin — pre-RFC-9728 behaviour, where the MCP server is assumed to be its
own AS. No token is ever issued.

**The PRM is parsed, but only partially acted on.** The scope in the
authorization request is verbatim from our PRM:

https://agmcp.auroratech.it/authorize?response_type=code&client_id=dd0f1e72-feef-44bf-80d3-0db098769e10&redirect_uri=https%3A%2F%2Fclaude.ai%2Fapi%2Fmcp%2Fauth_callback&code_challenge=hzSq0A58g9gpJ01YrjC8jUmBPskUV6J6mf3KUxxlVUg&code_challenge_method=S256&state=j08hvv37C0OUSi3kiOtpyvBMdTOIdoP37Qp0WbZwg2k&scope=api%3A%2F%2Fagmcp.auroratech.it%2Fdata.read

To rule out a fetch failure we placed a unique sentinel string inside the
`authorization_servers` value. Across 12 connection attempts and 19 requests to
`/mcp`, **zero inbound requests referenced the sentinel.** The document is
consumed (the scope proves it) but `authorization_servers` is never
dereferenced.

`Authorization` header present on 0 of 19 requests. Our token validator has
never been exercised by a real token.

**Also observed:** no RFC 8707 `resource` parameter is sent, though the spec
requires it in both the authorization and token requests.

**No workaround exists on the server or IdP side.** The connector requests only
`/.well-known/oauth-authorization-server`. Entra serves no document under that
name in any path variant (all four 404); it serves `openid-configuration` only.
The sets do not intersect. The non-`/v2.0` variant additionally reports
`issuer: sts.windows.net/{tid}/`, which does not match the URL it is fetched
from — RFC 8414 §3.3 requires a conforming client to reject it.

### What did you expect to happen?

The connector should dereference `authorization_servers` from the PRM and run
the OAuth flow against the external authorization server, per the resource-server
model introduced in revision 2025-06-18 and RFC 9728. The MCP server validates
tokens; it never issues them.

Instead the authorization request is sent to the MCP server's own origin, which
has no `/authorize` endpoint by design.

### Steps to reproduce

1. Stand up a remote MCP server (streamable HTTP) that is an OAuth 2.1 resource
server only — no /authorize, /token or /register endpoints.
2. Serve RFC 9728 PRM at /.well-known/oauth-protected-resource:

{"resource":"api://agmcp.auroratech.it",
"authorization_servers":["https://login.microsoftonline.com//v2.0"],
"bearer_methods_supported":["header"],
"scopes_supported":["api://agmcp.auroratech.it/data.read"]}

3. Return 401 on /mcp with:
WWW-Authenticate: Bearer resource_metadata="https:///.well-known/oauth-protected-resource"
4. Register a multi-tenant Entra app; expose api:///data.read; add both
https://claude.ai/api/mcp/auth_callback and
https://claude.com/api/mcp/auth_callback as Web redirect URIs.
5. Add as a custom connector. Authentication shows "Always required — Detected",
confirming the 401 challenge is parsed. Select "Use your own OAuth client",
enter the Entra client ID and secret.
6. Press Connect.

Result: browser lands on https:///authorize?... and the MCP server
returns {"error":"not_found","path":"/authorize"}. The request never reaches
login.microsoftonline.com.

### Area

MCP Connector (adding/managing servers)

### MCP Server (if applicable)

https://agmcp.auroratech.it/mcp (private; purpose-built minimal resource server, whoami tool only)

### Error messages or logs

```shell
{"error":"not_found","path":"/authorize"}

401 challenge served correctly on /mcp:
www-authenticate: Bearer resource_metadata="https://agmcp.auroratech.it/.well-known/oauth-protected-resource",
error="invalid_request", error_description="authorization required"

Tenant discovery-endpoint status codes:
...//v2.0/.well-known/openid-configuration 200
...//v2.0/.well-known/oauth-authorization-server 404
...//.well-known/oauth-authorization-server 404
.../.well-known/oauth-authorization-server//v2.0 404

Server-side counters across 12 attempts: requests to /mcp 19, auth.token.present 0,
inbound requests referencing the authorization_servers sentinel 0.
```

### Additional context

Server was built specifically to test this and does nothing else — a single
whoami() tool returning token claims, no database. Full logs from three separate
runs are preserved and available on request.

Related open issues, all Entra-backed connectors failing to complete token
exchange: #506, #632, #427, #290, #496, #503, #520. This report differs in
providing positive evidence that the PRM is parsed while authorization_servers
is specifically ignored, via the sentinel test.

Entra is not an edge case — it is one of the two largest enterprise IdPs, and it
serves no oauth-authorization-server document in any path shape, so no
authorization_servers value can make this connector reach it.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.