[BUG] MCP client shows "token expired" for a 403 insufficient_scope response
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/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:
- No 401 was ever returned. Only two 403s. The client reported an expiry for a response that never claimed one.
- No refresh was attempted. Zero
POST /oauth/tokenwithgrant_type=refresh_token. The only token call was theauthorization_codeexchange after manual re-auth. - The token was valid. Access-token TTL 3600s, token issued ~5 minutes before the failure.
- Re-auth "fixed" it by widening scopes, not by refreshing. The second
/authorizerequestedscope=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-authorizeerror="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
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.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗