anthropics / anthropics/claude-ai-mcp

Interactive OAuth never launched when MCP server challenges on POST (GET returns 405) — regression in 1.21459.0

Ouverte
#619 0 commentaires 1 réaction 0 personnes assignées Voir sur GitHub
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.

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.