[FEATURE] .mcp.json oauth: allow overriding or omitting the RFC 8707 `resource` parameter (Entra ID AADSTS9010010)
Problem
MCP servers whose OAuth authorization server is Microsoft Entra ID are currently impossible to connect to with Claude Code's native MCP OAuth when the server's canonical URL differs from the Entra app's identifier URI — which is always the case for servers hosted on cloud infrastructure (e.g. AWS Bedrock AgentCore Gateway at https://<id>.gateway.bedrock-agentcore.<region>.amazonaws.com/mcp).
Per the MCP 2025-06-18 auth spec, Claude Code sends the RFC 8707 resource parameter in authorization/token requests, using the resource value from the server's protected-resource metadata. Entra now hard-enforces (rollout ~March 2026, observed on both login.microsoftonline.com and login.microsoftonline.us) that resource must byte-match the identifier URI of the app that owns the requested scopes (api://<app-id>). Since the MCP server URL can never equal the api:// URI, every sign-in fails at the authorize step:
invalid_target: AADSTS9010010: The resource parameter provided in the request
doesn't match with the requested scopes.
Evidence: no scope configuration can fix this
Probed Entra's authorize endpoint directly (validation errors return in the 302 redirect before login):
| scope | resource | Result |
|---|---|---|
| api://<app>/my.scope (pinned via oauth.scopes) | <MCP server URL> | ❌ AADSTS9010010 |
| bare my.scope (from scopes_supported discovery) | <MCP server URL> | ❌ AADSTS9010010 |
| api://<app>/my.scope | api://<app> | ✅ accepted |
| api://<app>/my.scope | (omitted) | ✅ accepted |
The resource value is the problem, and nothing in the current oauth config block (clientId, callbackPort, scopes, authServerMetadataUrl) can change it. Nor can the other layers help:
- Entra rejects arbitrary
https://identifier URIs on app registrations (verified-domain requirement), so the cloud hostname can't be registered to make them match. - Managed MCP hosts (e.g. AgentCore Gateway) don't allow customizing the advertised
resourcein their protected-resource metadata.
Proposed solution
Add a resource key to the .mcp.json oauth block that takes precedence over the protected-resource metadata value, mirroring how scopes already overrides scopes_supported:
{
"mcpServers": {
"my-server": {
"type": "http",
"url": "https://<id>.gateway.bedrock-agentcore.us-east-1.amazonaws.com/mcp",
"oauth": {
"clientId": "<entra-app-client-id>",
"scopes": "api://<entra-app-client-id>/my.scope offline_access",
"resource": "api://<entra-app-client-id>" // override; or false/null to omit the parameter
}
}
}
}
Either capability unblocks Entra:
- Override: send the configured value instead of the metadata value (
resource=api://<app>passes validation). - Omit:
resource: false(or similar) suppresses the parameter entirely — Entra accepts plain v2 scope-only requests.
An explicit user-configured escape hatch seems justified here: the server metadata is spec-compliant, Claude Code is spec-compliant, but the authorization server (Entra) implements only a degenerate form of RFC 8707, and neither end is likely to change soon. Microsoft's own MCP servers (Azure DevOps, Business Central) trip over the same enforcement.
Related issues
- #52871 — trailing-slash normalization of
resourcebreaking Entra (that case is fixable by byte-exact matching; this case is not, because the server URL can never match theapi://URI) - #55993 — Azure DevOps remote MCP, same AADSTS9010010 class (closed)
- #26675 — pre-configured OAuth client credentials (the
oauthblock this would extend)
Environment
- Claude Code 2.1.198, macOS (darwin arm64)
- MCP server: AWS Bedrock AgentCore Gateway (streamable HTTP), custom JWT authorizer
- Authorization server: Microsoft Entra ID (Azure Government,
login.microsoftonline.us— but reproduces identically on commercial)
🤖 Filed with Claude Code