anthropics / anthropics/claude-ai-mcp
Custom connector: mcp_token_exchange_failed against Entra ID, while the identical exchange succeeds manually
- 主要語言
- 沒有語言資料
- 星號
- 471
- 分支
- 76
- PR 合併指標
- 30 天內沒有已合併 PR
描述
## Summary
An organization-level custom connector (individual sign-in) against a self-hosted MCP
server protected by Microsoft Entra ID consistently fails at the token exchange. The
authorization leg completes; the exchange never yields a token and the browser ends on
`/new?error_code=mcp_token_exchange_failed`.
The identical exchange — same client ID, client secret, redirect URI, scope, and the
RFC 8707 `resource` parameter — **succeeds when performed by hand** against the same
Entra tenant, and the resulting token is accepted by the MCP server.
## Reference IDs
- Latest attempt: `ofid_5f0a1ff30010f6aa`
- Earlier attempts: `ofid_bab1fa6ed1fc22f3`, `ofid_874c902c7f8af90b`
- Entra trace IDs shown in the connector error banner:
`963315dd-eae0-4fb4-b8e4-88de75480300`, `697696c1-5c84-4395-838c-39491e6a0f00`
- Support conversation ID: `215475359536447`
## Environment
- claude.ai, organization-level custom connector, *Individual sign-in* enabled
- MCP server: self-hosted on Azure Container Apps, Streamable HTTP, public HTTPS with a
managed certificate (URL available on request)
- Authorization server: Microsoft Entra ID, single-tenant app registration
- Edge on Windows 11
## What the server logs show during a Connect attempt
```
POST /mcp 401 Unauthorized
GET /.well-known/oauth-protected-resource 200 OK
POST /mcp 401 Unauthorized
… nothing further — no request ever arrives carrying a token
```
The 401 responses carry
`WWW-Authenticate: Bearer error="missing_token", …, resource_metadata="/.well-known/oauth-protected-resource"`.
`/.well-known/oauth-protected-resource` returns 200 with:
```json
{
"resource": "",
"authorization_servers": ["https://login.microsoftonline.com//v2.0"],
"bearer_methods_supported": ["header"],
"scopes_supported": ["api:///access_as_user"]
}
```
## The identical exchange succeeds manually
```
POST https://login.microsoftonline.com//oauth2/v2.0/token
client_id=
client_secret=
grant_type=authorization_code
code=
redirect_uri=
scope=api:///access_as_user
resource=/mcp
```
→ HTTP 200 with an access token. Claims: `aud=`,
`iss=https://login.microsoftonline.com//v2.0`, `scp=access_as_user`.
The MCP server accepts that token — `initialize` returns `serverInfo`.
Also verified to succeed with `offline_access` added to the scope alongside `resource`.
## App registration state
- Platform **Web** only — no SPA redirect URIs, no public-client redirect URIs,
`isFallbackPublicClient` unset
- `requestedAccessTokenVersion: 2`
- Two Application ID URIs: `api://` and the full MCP endpoint URL ending in
`/mcp`, no trailing slash
- The client is pre-authorized for its own `access_as_user` scope, so no interactive
consent is required
- All redirect URIs registered, including `https://claude.ai/api/mcp/auth_callback`
## What we already tried
- Deleted and recreated the connector from scratch with a freshly created client secret
- Rotated the client secret
- Changed `requestedAccessTokenVersion` from `null` to `2`. This was a real bug on our
side: v1 tokens carry `iss=https://sts.windows.net//`, which our server
rejects. Fixed, but it did not change the connector symptom.
- Added the full MCP URL as an additional Application ID URI, on support's advice. This
fixed `AADSTS9010010 invalid_target` for the *manual* exchange with `resource`, but
did not change the connector symptom.
The symptom is unchanged in every case.
## What would help
The verbatim response Entra returned to the connector's token request for the trace IDs
above, or the exact parameter set the connector sends on the token request. Every
parameter combination we can construct by hand succeeds, so we cannot reproduce the
failure outside the connector.
Happy to supply the server URL, tenant ID and client ID privately if that helps the
server-side trace.
貢獻指南
這個儲存庫沒有索引到貢獻指南
評估
這個 Issue 還沒有評估資料。