anthropics / anthropics/claude-code

[BUG] MCP client shows "token expired" for a 403 insufficient_scope response

Đang mở
#92,518 0 bình luận 0 reaction 0 người được giao Xem trên GitHub
area:mcp bug has repro
Ngôn ngữ chính
Python
Star
145k
Fork
23.1k
Chỉ số merge pull request
Chỉ số pull request đang chờ

Mô tả

### What happens

An MCP server returns `403` with `WWW-Authenticate: Bearer error="insufficient_scope"` when a token lacks the scope for a tool. Claude Code shows the user:

```
MCP server "..." requires re-authorization (token expired)
```

The token was **not** expired. It had ~55 minutes of its 1-hour lifetime remaining. The real problem was a missing scope on the grant.

### Why it matters

The message sends you to debug the wrong thing. We spent a full session investigating token lifetimes and refresh handling before reading server logs and finding a 403, not a 401.

### Server response

Read tools need `events:read`, write tools need `events:write`. The grant only carried `events:read`.

```
POST /api/mcp (tools/call: events_list) -> 200
POST /api/mcp (tools/call: events_get) -> 200
POST /api/mcp (tools/call: events_delete) -> 403
```

The 403 carries:

```http
HTTP/1.1 403 Forbidden
WWW-Authenticate: Bearer error="insufficient_scope",
scope="events:write",
resource_metadata="https://example.com/.well-known/oauth-protected-resource/api/mcp"

{"jsonrpc":"2.0","id":null,
"error":{"code":-32600,"message":"Insufficient scope: events:write required"}}
```

### What we tested

Server-side logs for the whole session confirm:

1. **No 401 was ever returned.** Only two 403s. The client reported an expiry for a response that never claimed one.
2. **No refresh was attempted.** Zero `POST /oauth/token` with `grant_type=refresh_token`. The only token call was the `authorization_code` exchange *after* manual re-auth.
3. **The token was valid.** Access-token TTL 3600s, token issued ~5 minutes before the failure.
4. **Re-auth "fixed" it by widening scopes, not by refreshing.** The second `/authorize` requested `scope=events:read events:write`; the first had not. The same delete then succeeded.

### Expected

Distinguish the two `WWW-Authenticate` error codes:

- `error="invalid_token"` (401) -> "token expired", re-authorize
- `error="insufficient_scope"` (403) -> say the scope is missing, and name it

Ideally, perform step-up authorization using the `scope` from the challenge. At minimum, don't call it an expiry.

### Environment

- Claude Code 2.1.258
- MCP spec 2026-07-28, OAuth 2.1 AS, TypeScript SDK v2
- Server returns the challenge per [spec §authorization](https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization)

### Related

Previously reported and closed without a fix: #19066, #28258, #44652. #28258 got "resolved in the next release" (2026-03); #44652 reported the same behavior six weeks later on 2.1.92, and a commenter confirmed it on 2.1.121. All three are locked, so this is a fresh report. Still reproducing on **2.1.258**.

Hướng dẫn đóng góp

Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này

Hướng nghiên cứu

No source file or test is named. Start by locating the MCP client's handling of HTTP 401/403 responses and WWW-Authenticate challenges, then compare invalid_token with insufficient_scope using the provided response. Done means a 403 insufficient_scope response reports the missing scope instead of token expiry, while 401 invalid_token retains the expiry behavior.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
typescript
Lĩnh vực
api, authentication
Loại issue
Lỗi
Độ khó
3/5
Thời gian dự kiến
1-2 ngày
Mức độ hoạt động
Sôi nổi
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
52/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.