Skip to content

Implement SEP-2350: Clarify client-side scope accumulation (step-up auth) #877

@alexhancock

Description

@alexhancock

SEP-2350: Clarify client-side scope accumulation in step-up authorization — rust-sdk implementation

Spec PR: modelcontextprotocol/modelcontextprotocol#2350
Track: Specification · Stage: accepted · Priority: P0 · Theme: Enterprise Readiness
Needs code changes: Yes (Small)

Summary

Clarifies step-up authorization scope handling:

  • Servers report scopes needed for the current operation in 403 / insufficient-scope errors (RFC 6750 §3.1), not the union of previously granted scopes.
  • Clients accumulate scopes: during re-authorization the client requests the union of previously requested scopes and the newly challenged scopes.
  • "Authoritative" in Protected Resource Metadata means scopes required for the current operation, not the exclusive set the client should request.

Why this needs code changes in rust-sdk

The OAuth client's scope logic lives in crates/rmcp/src/transport/auth.rs on
AuthorizationManager:

  • select_scopes(www_authenticate_scope, default_scopes) → calls select_base_scopes(..) then add_offline_access_if_supported(..).
  • select_base_scopes(..) currently returns early with a single source in priority order (WWW-Authenticate scope → stored www_auth_scopesresource_scopes (RFC 9728) → AS scopes_supported → defaults). It replaces rather than unions — so on a step-up 403 it returns only the freshly challenged scope and drops previously granted ones.
  • Supporting state: current_scopes: RwLock<Vec<String>>, scope_upgrade_attempts, ScopeUpgradeConfig, can_attempt_scope_upgrade(), get_current_scopes(), WWWAuthenticateParams::is_insufficient_scope().

Conformance currently reports auth/scope-step-up FAIL (13/14) — consistent with the
replace-not-union behavior above.

Proposed work

  • In select_base_scopes (or a new wrapper), when a step-up challenge arrives, union the newly challenged scopes with current_scopes (the previously requested/granted set) rather than returning a single source early.
  • Persist the accumulated union back into current_scopes after a successful re-authorization so subsequent rounds keep growing the set.
  • Treat the server's reported scopes as "needed for the current operation," not authoritative/exclusive (per the SEP) — merge, don't overwrite.
  • De-duplicate and keep ordering stable for testability.
  • Re-run auth/scope-step-up to green; add unit tests covering multiple step-up rounds accumulating scopes.

Affected areas

crates/rmcp/src/transport/auth.rs (AuthorizationManager::select_scopes / select_base_scopes, current_scopes).

Notes / risks

  • Directly fixes a known failing conformance scenario. Good candidate to bundle with SEP-2351/2352/2468 auth work.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High: significant functionality gap or spec violationT-bugBug fixes and error correctionsT-securitySecurity-related changesT-transportTransport layer changes

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions