SEP-2207: Refresh token guidance#1523
Draft
wdawson wants to merge 1 commit intomodelcontextprotocol:mainfrom
Draft
SEP-2207: Refresh token guidance#1523wdawson wants to merge 1 commit intomodelcontextprotocol:mainfrom
wdawson wants to merge 1 commit intomodelcontextprotocol:mainfrom
Conversation
|
9 tasks
@modelcontextprotocol/client
@modelcontextprotocol/server
@modelcontextprotocol/express
@modelcontextprotocol/hono
@modelcontextprotocol/node
commit: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implement OIDC-flavored refresh token guidance (modelcontextprotocol/modelcontextprotocol#2207) in the Python SDK client.
Motivation and Context
MCP clients interacting with OIDC-flavored Authorization Servers often don't receive refresh tokens because they aren't requesting
offline_access. This leads to poor UX (frequent re-authentication). SEP-2207 provides guidance for how MCP clients should handle this.The SDK currently expects the caller to supply the supported
grant_typesfor the client. The example already shows providingrefresh_token, and callers are encouraged to do so as well.This PR:
determineScope()helper that follows the MCP Scope Selection Strategyoffline_accessto the authorization request scope when the AS advertises it inscopes_supportedand the client'sgrant_typesincludesrefresh_tokenNo changes are needed on the server side — the SDK's example AS already includes
offline_accessin itsscopes_supported, and the example middleware already omits it fromWWW-Authenticate(both compliant with the SEP).How Has This Been Tested?
determineScope()covering:scopes_supported,clientMetadata.scopefallback, omit)offline_accesswhen conditions met)clientMetadata.scopeor non-compliant PRM, whengrant_typesomitsrefresh_token, whengrant_typesis undefined, when no scopes are present)Breaking Changes
None. The
offline_accessaugmentation only activates when:offline_accessinscopes_supportedgrant_typesincludesrefresh_tokenClients that don't set
grant_typesor don't includerefresh_tokenare unaffected. Authorization Servers that don't recognizeoffline_accesswill simply ignore it per OAuth 2.1. The newly exporteddetermineScope()function is additive.Types of changes
Checklist
Additional context
determineScope()now encodes the MCP Scope Selection Strategy as a testable, exported function. It acceptsrequestedScope,resourceMetadata,authServerMetadata, andclientMetadata, and returns the effective scope string (orundefinedto omit the parameter).startAuthorization()already handles addingprompt=consentwhenoffline_accessis in scope, per the OIDC Core spec. No changes were needed there.grant_typesdefaulting was intentionally not added at the SDK level. TheOAuthClientMetadatatype is shared between client creation (DCR) and server-side parsing (CIMD), so schema-level defaults would violate OAuth spec defaults for CIMD. The example clients already includerefresh_tokeningrant_types.insufficient_scopehandler instreamableHttp.tsalready passes scope through toauth(), which now delegates todetermineScope()— no additional changes needed for step-up authorization flows.