Context
The MCP 2026-07-28 scope-selection strategy says clients SHOULD use the 401 challenge's scope, otherwise all PRM scopes_supported values. It expects the PRM list to be the minimal set for basic functionality. The Ruby SDK follows that default and may append offline_access when the authorization server supports it. The default should remain unchanged.
Gap
A hosted client may apply a narrower per-user policy: omit a client-requested scope even when PRM advertises a basic set, or request only user-approved scopes. authorization_request_validator can accept or refuse a proposed authorization, but cannot replace its scopes. An empty scope passed to Flow#run! selects PRM defaults, so the caller cannot make the client omit the URL's scope parameter without taking over the SDK's security-critical flow. Even when that parameter is omitted, the authorization server may apply default scopes or reject the request (RFC 6749 §3.3); the application must inspect what was granted.
Proposal
Add optional Provider.new(scope_selector: ->(candidate_scopes) { ... }) for the authorization-code flow:
- Run it after normal challenge/PRM/provider scope selection and automatic
offline_access augmentation, but before request validation and client registration.
- Pass a read-only array of candidate OAuth scope tokens. Return valid tokens to replace it, or
nil / [] to omit the authorization URL's scope parameter, including any prefilled endpoint query scope. With no selector, keep today's endpoint-query and scope-selection behavior exactly.
- Preserve the SDK's safeguard against sending
offline_access when the authorization server does not advertise it, including when the selector returns that token.
- Document that filtering scopes required by a challenge may leave the current operation unauthorized.
C# ScopeSelector provides a post-selection hook; Go ScopeFilter provides a pre-offline_access hook plus a separate refresh-token option. A post-selection hook lets one Ruby callback also omit an automatically added offline_access scope.
Context
The MCP 2026-07-28 scope-selection strategy says clients SHOULD use the 401 challenge's
scope, otherwise all PRMscopes_supportedvalues. It expects the PRM list to be the minimal set for basic functionality. The Ruby SDK follows that default and may appendoffline_accesswhen the authorization server supports it. The default should remain unchanged.Gap
A hosted client may apply a narrower per-user policy: omit a client-requested
scopeeven when PRM advertises a basic set, or request only user-approved scopes.authorization_request_validatorcan accept or refuse a proposed authorization, but cannot replace its scopes. An emptyscopepassed toFlow#run!selects PRM defaults, so the caller cannot make the client omit the URL'sscopeparameter without taking over the SDK's security-critical flow. Even when that parameter is omitted, the authorization server may apply default scopes or reject the request (RFC 6749 §3.3); the application must inspect what was granted.Proposal
Add optional
Provider.new(scope_selector: ->(candidate_scopes) { ... })for the authorization-code flow:offline_accessaugmentation, but before request validation and client registration.nil/[]to omit the authorization URL'sscopeparameter, including any prefilled endpoint query scope. With no selector, keep today's endpoint-query and scope-selection behavior exactly.offline_accesswhen the authorization server does not advertise it, including when the selector returns that token.C#
ScopeSelectorprovides a post-selection hook; GoScopeFilterprovides a pre-offline_accesshook plus a separate refresh-token option. A post-selection hook lets one Ruby callback also omit an automatically addedoffline_accessscope.