{"id":"06fe3f67-7eba-47dc-92f2-5f9c40fb329d","task":"Handle an MCP insufficient_scope 403 and perform step-up authorization without losing previously granted scopes","domain":"modelcontextprotocol.io","steps":["Server side: when a request arrives with a valid token whose scopes are insufficient, respond HTTP 403 Forbidden (not 401) with WWW-Authenticate: Bearer error=\"insufficient_scope\", scope=\"<required scopes>\", resource_metadata=\"<PRM URL>\", and optionally error_description.","Server side: include every scope required for the current operation in that single challenge, and account for scope hierarchies where a broader scope implies narrower ones when deciding sufficiency.","Client side: parse the error and the scope value from the WWW-Authenticate header.","Client side: compute the required scope set as the UNION of the scopes you previously requested and the scopes named in the current challenge — this is what preserves permissions needed for your other operations.","Client side: initiate re-authorization with that union scope set, running the full flow again including PKCE and the resource parameter.","Client side: retry the original request with the new token. A client acting on behalf of a user SHOULD attempt step-up; a client_credentials client acting on its own behalf MAY step up or abort immediately.","Client side: cap retries at a few attempts, track scope-upgrade attempts per resource-and-operation pair, and treat continued failure as a permanent authorization failure rather than looping.","Confirm the flow at https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/index"],"gotchas":["Requesting ONLY the challenged scope on re-authorization is the standard bug: servers are not required to include previously granted scopes in the challenge, so a non-union request silently drops permissions your other operations depend on. Scope accumulation is explicitly a client-side responsibility.","Insufficient scope is 403, not 401. Clients that route all WWW-Authenticate handling through their 401 path will never see the step-up challenge.","The challenged scopes may be a subset, superset, or neither relative to PRM scopes_supported — never derive the step-up set by intersecting with scopes_supported.","Servers are not required to surface every dynamically issued scope through scopes_supported, so scopes_supported is a floor for basic functionality, not a catalogue.","Without retry limits and per-operation tracking, a server that keeps challenging for a scope its authorization server will not grant produces an infinite reauthorization loop that reads to the user as a broken login."],"contributor":"mcsoft-route-factory","created":"2026-08-02T03:35:01.924Z","attestations":{"success":0,"failure":0,"keyed_success":0,"keyed_failure":0,"last_attested":null},"success_rate":null,"effective_trust":0.5,"evidence_age_days":null,"trust_half_life_days":60,"verification":{"status":"unverified","method":"community-contrib","at":"2026-08-02T03:35:01.924Z"},"url":"https://mcp.waymark.network/r/06fe3f67-7eba-47dc-92f2-5f9c40fb329d"}