anthropics / anthropics/claude-ai-mcp
Interactive OAuth never launched when MCP server challenges on POST (GET returns 405) — regression in 1.21459.0
- Langage dominant
- Aucune donnée de langage
- Étoiles
- 471
- Forks
- 76
- Métriques de merge des PR
- Aucune PR mergée en 30 j
Description
### MCP server URL or name
`https://mcp.granola.ai/mcp` (managed connector, `oauth: true`, Streamable HTTP)
### How are you connecting to this server?
Managed/enterprise deployment via `managedMcpServers` (`transport: http`, `oauth: true`), connected through the direct MCP host (`custom3p-mcp` / `directMcpHost`).
### Where does the issue occur?
Claude Desktop **1.21459.0** on macOS 15.6 (Darwin 24.6.0). Interactive OAuth (Connect button).
### When did you last reproduce this?
2026-07-15
### Browser and OS
Claude Desktop 1.21459.0 (Electron), macOS 15.6 / Darwin 24.6.0
### Describe the issue
After updating to **1.21459.0**, a managed MCP connector that returns its `401` OAuth challenge on the **POST** (JSON-RPC `initialize`) — while its **GET** (stream open) returns **`405 Method Not Allowed`** rather than a `401` — can no longer be authorized. On (re)connect the app decides no authorization is required ("server accepted an unauthenticated connect"), **never opens the OAuth browser flow**, then hard-fails on the first authenticated POST with `401 Unauthorized`. Clicking "try again" repeats the identical loop; there is no path to obtain a token.
This connector worked before the update (cached tokens refreshed successfully); the failure surfaces on fresh interactive auth after the token is cleared.
**Control (same build):** Slack and Intercom, which present a `401` challenge at connect time, open the browser and authorize normally in the same session. The distinguishing factor is purely the transport method that carries the 401.
### Error details
`~/Library/Logs/Claude/main.log`, on every attempt — note the **absence** of any `opening authorize URL` / `waiting for OAuth callback` line:
```
LocalAgentModeSessions.authorizeDirectMcpServer: Granola — reconnecting (http)
[custom3p-mcp] oauth configured but server accepted an unauthenticated connect — proceeding without credentials { server: 'Granola' }
LocalAgentModeSessions.authorizeDirectMcpServer: Granola — failed: Streamable HTTP error: Error POSTing to endpoint: {"message":"Unauthorized"}
```
**Server behaviour (verified out-of-band with curl) — the challenge is well-formed:**
```
GET https://mcp.granola.ai/mcp → HTTP 405 (no auth challenge on GET)
POST https://mcp.granola.ai/mcp (initialize) → HTTP 401
www-authenticate: Bearer error="invalid_token",
error_description="Authorization needed",
resource_metadata="https://mcp.granola.ai/.well-known/oauth-protected-resource"
```
`.well-known/oauth-protected-resource` and the authorization-server metadata are present and advertise DCR — a standard, authorizable server. This is **not** a missing-DCR / confidential-client case; the client has everything it needs to start OAuth but never does.
### Expected behavior
The app initiates the OAuth browser flow (the POST `401` carries a valid `resource_metadata` discovery pointer), the user signs in, tokens are saved, and the connector connects — as before 1.21459.0.
### Additional context
**Root cause hypothesis:** 1.21459.0's decision to launch interactive OAuth appears to be driven by the response to the connect-time probe (the `GET`/stream-open), not by a `401` on the subsequent `POST`. When the connect probe is anything other than a `401` challenge (here `405`), the client concludes "no auth required, proceed unauthenticated" (as logged), skips the browser flow, and then fails on the first authenticated `POST`. The `401 + WWW-Authenticate` on the POST is never used to (re)trigger authorization.
**Impact:** any OAuth MCP server that challenges on the JSON-RPC POST but not on the GET stream-open is unauthorizable after the update.
**Suggested fix:** trigger the interactive OAuth flow on **any** `401 + WWW-Authenticate: Bearer resource_metadata=…` encountered during connect/initialize (including on the POST), not only on a connect-probe `401`. Do not treat a non-401 connect-probe response (e.g. `405`) as proof the server accepts unauthenticated use.
**Workarounds:** none acceptable — a static `headers` bearer bypasses the browser flow but forfeits per-user auth and would ship one shared credential to all users. No managed-config / version-pin workaround.
Guide de contribution
Aucun guide de contribution indexé pour ce dépôt
Évaluation
Cette issue n'a pas encore été évaluée.