anthropics / anthropics/claude-ai-mcp

Web UI never binds connector after fully successful OAuth flow (server-side trace attached; Claude Code works against the same server)

Aperta
#574 1 commento 1 reazione 0 assegnatari Vedi su GitHub
Lingua principale
Nessun dato sulla lingua
Stelle
471
Fork
76
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Descrizione

## Summary

Web UI (claude.ai) custom connector never completes/binds after a **fully successful** OAuth 2.1 flow — while **Claude Code connects to the exact same server + authorization server end-to-end and works**. This matches #155 (closed unresolved) / #100, and the upstream report modelcontextprotocol/modelcontextprotocol#2157 (which likewise notes Claude Code/Desktop are unaffected). Filing with a complete server-side trace to help pinpoint the web-UI leg.

## Environment

- MCP server: `https://dev.descix.net/mcp` (Streamable HTTP; OAuth 2.1 AS at `https://dev.descix.net/oauth`)
- Spec surfaces implemented: RFC 9728 protected-resource metadata, RFC 8414 AS metadata, RFC 7591 DCR (public client, `token_endpoint_auth_method: none`), PKCE S256, RFC 8707 resource indicators, refresh-token rotation
- Client: claude.ai web UI, custom connector; Chrome on macOS
- Counter-test: **Claude Code with the identical server URL: full flow (real WebAuthn ceremony inside our authorize step included) completes and the connection WORKS**

## What the server observed (three consecutive web-UI attempts, ~20–40s apart)

Every hop succeeded, per request logs + datastore records:

1. Unauthenticated `POST /mcp` probe → `401` + `WWW-Authenticate: Bearer resource_metadata=...` (expected discovery kick-off; UA `python-httpx/0.28.1`)
2. `GET /.well-known/oauth-protected-resource` → 200; `GET /.well-known/oauth-authorization-server/oauth` → 200
3. `POST /oauth/register` (DCR) → **201** (client_name "Claude", `redirect_uris: ["https://claude.ai/api/mcp/auth_callback"]`)
4. `GET /oauth/authorize?...` → **302** into our sign-in ceremony (browser UA — the real popup; PKCE S256 + `state` + `resource` all present, scope `mcp:read mcp:tools mcp:write mcp:admin` — the full advertised vocabulary)
5. Ceremony completed; single-use authorization code minted and bound to the authenticated user (datastore record per attempt: `status: complete`)
6. Browser delivered `code`+`state` (state echoed byte-exact) to `https://claude.ai/api/mcp/auth_callback`, and the claude.ai backend redeemed it: `POST /oauth/token` → **200** on **all three attempts** (UA `python-httpx/0.28.1`). Zero un-redeemed codes remain server-side. Token response shape: `{ access_token (JWT), token_type: "Bearer", expires_in: 3600, refresh_token, scope }`
7. claude.ai then made **three authenticated verification calls per attempt** (UA `Claude-User`): `initialize` → **200** (echoes `protocolVersion: 2025-11-25`; object-typed capabilities), `notifications/initialized` → **204**, `tools/list` → **200** (9 tools, strict-valid JSON-Schema `inputSchema`s, `type:"object"` roots)
8. **Then: zero subsequent `/mcp` traffic.** The connector never appears connected in the web UI. A later `Claude-User` request arrived with **no Authorization header at all** (the UI used the connector without the token it had just obtained and verified), then the whole probe→DCR→authorize cycle restarted.

Also verified server-side (eliminated as causes): no COOP/COEP headers anywhere on our surfaces (popup `window.opener` chain intact from our side); `prompts/list` / `resources/list` → 200 (capabilities advertise them); `ping` → 200; `GET /mcp` SSE → 200 keep-alive; exact-match `redirect_uri`/`client_id`/PKCE at token exchange (they redeemed successfully, so all passed); auth-code single-use + TTL not in play; token verified fine on subsequent harness calls.

We also probed the callback shape: `GET https://claude.ai/api/mcp/auth_callback?code=x&state=y` → `307` to `https://claude.ai/settings/connectors?step=end_error&flow_id=...` — so the web UI's final `step=` disposition exists; we can supply a fresh `flow_id` from a new attempt on request to correlate with your internal logs.

## Expected

After `initialize`/`tools/list` verification succeeds (which your backend performed, three times), the web UI should bind the token and show the connector as connected — as Claude Code does against the same server.

## Actual

Web UI never binds the token; connector unusable from claude.ai web despite the AS + resource server observing a complete, spec-clean flow.

## Notes

- Happy to run live attempts on demand — the server is a dev environment and we can correlate timestamps/`flow_id` within minutes.
- Related: #155, #100, modelcontextprotocol/modelcontextprotocol#2157.

Guida per i contributori

Nessuna guida per i contributori indicizzata per questo repository

Valutazione

Questa issue non è ancora stata valutata.

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.