[BUG] claude.ai connector: reconnecting after a 403 insufficient_scope doesn't request the challenged scope

Status Open
Maintainer reply None cached
Activity 3 comments · opened Sep 29, 2026

What happens

A claude.ai connector (remote MCP server with OAuth) is used from the Claude desktop app, Code tab. A tool call needs a scope the connector's token lacks. The server answers 403 with WWW-Authenticate: Bearer error="insufficient_scope", scope="<held scopes> <required scope>", per the MCP authorization spec.

Claude shows:

This connector requires additional permissions. The user needs to reconnect it from connector settings with the appropriate access.

The user reconnects from the claude.ai connector settings. The authorization request does not include the challenged scope: the consent page only offers the scopes the connector already held. The required scope never appears, so it can't be granted.

Reproduced twice in a row. The second time, the failing call was made again right before reconnecting, so the challenge was fresh.

Server side

Metabase MCP v2 (self-hosted OSS v0.64.0.6-beta). A write tool needs agent:content:write. The connector held agent:resource:read agent:content:read agent:query:run agent:sql:run. The server builds the 403 challenge as held + required (step-up-scopes in src/metabase/mcp/v2/api.clj). The consent page shows exactly the scopes in the authorization request. It offered only the four held scopes, never agent:content:write.

agent:sql:run had been granted through a step-up earlier. So step-up works on some path, but not for a 403 raised while the connector is used from the Code tab.

Expected

After a 403 insufficient_scope, the next authorization of that connector requests the challenged scope, whichever surface raised the 403 and wherever the user reconnects from (automatic prompt or connector settings).

Related

#92518 and #73712 cover step-up for MCP servers configured in Claude Code itself. This report is about claude.ai connectors used from the desktop app.

View original on GitHub ↗

3 Comments

guillaumewrobel · 16 days ago

Correction after checking the server's access logs: the reconnections that followed the agent:content:write 403s did not request the held scopes either. The authorization requests carried only the three baseline scopes (agent:content:read agent:query:run agent:resource:read), so the new token even lost agent:sql:run, which an earlier step-up had granted. Workaround on the server side: adding agent:content:write and agent:sql:run to the 401 challenge and to scopes_supported makes the connector request them on reconnect, and the consent page then shows them.

stonianua · 16 days ago

Useful server-side correction in the follow-up — especially that reconnect after the Code-tab 403 insufficient_scope not only skipped agent:content:write, it also dropped back to the three baseline scopes and lost the earlier agent:sql:run step-up.

Two client-side fingerprints that usually split "consent UI never saw the challenge" from "challenge never left the tool-call path":

  1. Where the challenged scope= is consumed

After a tool-call 403 with WWW-Authenticate: Bearer error="insufficient_scope", scope="…", check whether the next /authorize (or AS authorize URL) includes that challenged scope list, or only the connector's stored / baseline set. Your access-log note already shows baseline-only on reconnect from connector settings — that points at the Code-tab / claude.ai-connector path not forwarding the challenge into the next auth request (as opposed to Metabase omitting it from scopes_supported).

  1. Settings reconnect vs in-flow step-up

You already saw step-up work earlier for agent:sql:run. Worth one controlled compare: trigger the same write tool so the 403 is fresh, then (a) use whatever in-product "additional permissions" affordance appears on the tool error (if any) before opening connector settings, vs (b) only Settings → Reconnect. If (a) requests held+required and (b) requests baseline-only, that pins the bug to the Settings reconnect entrypoint not reading the latest challenge.

Server workaround (put required scopes on the 401 / scopes_supported) is a solid interim; the client still ought to honor the 403 challenge scope on the next authorize regardless of which surface started the reconnect.

Happy to compare authorize query strings if anyone else hits step-up from a claude.ai connector on the Code tab.

guillaumewrobel · 16 days ago

Thanks, the access logs already answer part of that compare:

  • In-flow step-up works on claude.ai web: a 403 insufficient_scope naming agent:sql:run at 08:49:09 UTC was followed 20 seconds later by an /oauth/authorize requesting the three baseline scopes plus agent:sql:run, consistent with an in-flow prompt.
  • From the Code tab there is no in-flow affordance: the tool error only says to reconnect from connector settings. The two Settings → Reconnect attempts that followed agent:content:write 403s (08:39 and 08:41 UTC) requested the baseline only.

So the Settings reconnect entry point seems to ignore the latest challenge, and the Code tab offers no other way in. We can't rerun a clean compare now: the server-side workaround puts both scopes in the baseline request.