anthropics / anthropics/claude-ai-mcp

OAuth completes (POST /token 200) but claude.ai never sends the authenticated MCP call — only for endpoint paths other than exactly /mcp

Aberta
#878 0 comentários 0 reações 0 responsáveis Ver no GitHub
Linguagem predominante
Sem dados de linguagem
Estrelas
471
Forks
76
Métricas de merge de PRs
Nenhum PR com merge em 30d

Descrição

## Summary

claude.ai completes the **entire OAuth flow** for a custom connector (discovery → DCR → `/authorize` → callback → `POST /token` **200**) and then **never sends any request to the MCP server again** — no `initialize`, not even an unauthenticated probe. The UI reports:

> Your account was authorized, but the integration rejected the credentials it just issued. Reconnecting may not help; if it keeps happening, contact whoever manages this integration.

The server never "rejected" anything: **zero post-token traffic reaches the origin** (verified with an ASGI shim logging every inbound POST and whether it carried an `Authorization` header — nothing arrives after `/token`).

The decisive pattern: this happens **only for MCP endpoints whose URL path is anything other than exactly `/mcp`**. A connector at the root `…/mcp` on the *same server, same OAuth AS, same GitHub identity* connects fine every time. Endpoints at `…/quinn/mcp` or `…/quinn-mcp` fail 12+ consecutive times.

Likely same family as #100, #196, #240, #690.

## Setup

- Server: FastMCP **3.4.7** `OAuthProxy`/`GitHubProvider` (GitHub OAuth upstream), one authorization server at the domain root, multiple MCP resource endpoints told apart by path.
- Transport: Cloudflare named tunnel → `https://mcp.quinnfrederick.com` (`:443` only), streamable HTTP.
- Endpoints: `/mcp` (works in claude.ai), `/quinn-mcp`, `/seealso-mcp`, `/promethean-mcp` (all fail in claude.ai, all work everywhere else).
- Discovery metadata is spec-correct per endpoint: `401` carries `WWW-Authenticate: Bearer resource_metadata="…/.well-known/oauth-protected-resource/"`; each PRM returns the exact `resource` and `authorization_servers`; AS metadata at root.

## What the origin sees for a failing connect (from the access log)

```
POST /quinn-mcp 401 ← pre-auth probe (expected)
GET /.well-known/oauth-protected-resource/quinn-mcp 200
GET /.well-known/oauth-authorization-server 200
GET /authorize?...&resource=https%3A%2F%2Fmcp.quinnfrederick.com%2Fquinn-mcp 302
GET /auth/callback?code=… 302
POST /token 200 ← token issued
(silence — no further request from claude.ai, ever)
```

For the working `/mcp` connector the same sequence is followed **immediately** by authenticated `POST /mcp` calls (200/202) and the connector shows Connected with the full tool list.

## Proof the failing endpoint itself is healthy

1. **Independent OAuth client** (fresh DCR registration, PKCE, real GitHub auth, `resource=…/quinn-mcp`): token issued with `aud` = exact resource, then authenticated `initialize` on `/quinn-mcp` → **HTTP 200, `mcp-session-id` issued, full MCP result in 0.12–0.93 s**.
2. **ChatGPT** (developer-mode connector) connects to the identical `…/quinn-mcp` URL and lists/uses all 13 tools without issue.

## Variables eliminated (each tested explicitly, failure identical)

- **CIMD vs DCR client**: fails with the shared CIMD client id (`https://claude.ai/oauth/mcp-oauth-client-metadata`) *and* with per-connector DCR UUID clients (server advertises no CIMD support → claude.ai registered via `/register`, 201).
- **Token audience**: server mints `aud` = the exact RFC 8707 `resource` claude.ai sends (verified by decoding issued JWTs). Also tried `aud = issuer`. No difference.
- **Path shape**: multi-segment `/quinn/mcp` and single-segment `/quinn-mcp` both fail; only the literal root `/mcp` connects.
- **Connector record state**: brand-new connectors (fresh UUID, never-seen URL) fail on first Connect.
- **Whether the working `/mcp` connector is connected or disconnected at the time**: no difference.
- **GitHub health / sudo-mode**: reproduced with GitHub API fully healthy and an active sudo session; the GitHub grant is authorized (`/auth/callback` fires with a valid code and the upstream exchange succeeds server-side).
- **Refresh vs first connect, Cowork vs web settings surface**: identical.

## Recent flow IDs (all this failure, 2026-08-17, account xxi@quinnmagick.com / GitHub QuinnFrederick)

`ofid_33082ae8391cb7b5`, `ofid_4477320f29f62599`, `ofid_f561b93ff00d98f8`, `ofid_d5c453d666b37a61`, `ofid_8e47f0471a8781d8`, `ofid_c29d9ed05089b800`, `ofid_a6f821ab94f36387`, `ofid_4dbb8cb3b3723b7a`, `ofid_5efac3af5f2043e9`, `ofid_7e8a0a67e0570c98`

(Working root-path connects for contrast, same server/day: the "Quinn Personal" connector at `…/mcp`, multiple `step=success` flows.)

## Expected

After `POST /token` succeeds, claude.ai's backend should call the MCP endpoint (the connector's URL / the `resource` it itself requested) with the issued Bearer token — as it does for root-path `/mcp` connectors, and as ChatGPT and spec-compliant clients do for the non-root endpoints.

## Actual

For any connector whose endpoint path ≠ `/mcp`, the backend abandons the flow after token issuance without contacting the server, and surfaces "the integration rejected the credentials it just issued".

Happy to provide server-side logs, run test connects on demand, or try candidate fixes — the server is live and instrumented.

Guia de contribuição

Nenhum guia de contribuição indexado para este repositório

Avaliação

Esta issue ainda não foi avaliada.

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.