Skip to content

SEP: MCP Client Silent Refresh on 401 Invalid Token#2702

Open
waddah12alhajar wants to merge 2 commits into
modelcontextprotocol:mainfrom
waddah12alhajar:sep-silent-refresh-on-401
Open

SEP: MCP Client Silent Refresh on 401 Invalid Token#2702
waddah12alhajar wants to merge 2 commits into
modelcontextprotocol:mainfrom
waddah12alhajar:sep-silent-refresh-on-401

Conversation

@waddah12alhajar
Copy link
Copy Markdown

Summary

Adds a draft SEP that specifies expected MCP HTTP client behavior when receiving HTTP 401 Bearer error="invalid_token" from a remote MCP server while a refresh token is available locally. Builds directly on SEP-2207 (OIDC-Flavored Refresh Token Guidance).

Motivation

SEP-2207 closed the issuance side of refresh tokens (offline_access request, AS metadata, capability advertising). It deliberately did not specify what clients should do with refresh tokens when an access token expires mid-session. As a result, current MCP clients (Cursor, Claude Code/Desktop, VS Code) handle 401 inconsistently — some refresh transparently, some surface the error to the model, some prompt the user.

I maintain a remote MCP connector for Power BI / Azure Data Factory analytics. The connector is fully spec-compliant on the resource-server side (RFC 6750 §3 challenge, RFC 9728 metadata, SEP-2207 offline_access request). Despite this, in some Claude client sessions the 401 surfaces to the model as a tool error, even though the prerequisites for silent refresh are all met. Manual reauthentication mid-session is the only recovery, which is jarring for B2B / multi-hour analytics workflows.

This SEP makes the silent-refresh-on-401 client behavior normative and clarifies the failure-to-needs_reauth fallback when the refresh token itself is invalid.

Highlights

  • Normative when the four prerequisites hold (server returns 401 + WWW-Authenticate, RFC 9728 metadata published, offline_access requested at sign-in). SHOULD rather than MUST — leaves room for clients with legitimate reasons to opt out (e.g. step-up-on-every-request security policies).
  • Single-retry cap (no infinite loops on persistent rejection).
  • Preserves original tool_use_id so the model sees a coherent retry, not a synthetic side-effect.
  • Structured needs_reauth failure path when refresh fails — clients route to UI prompts, not silent failures.
  • Backward-compatible — additive guidance, no schema/header changes, no server-side burden beyond existing RFC 6750 / RFC 9728 / SEP-2207 compliance.
  • Security implications are net-positive: enables shorter access-token TTLs without UX penalty, retains AS authority via Conditional Access on the refresh-token grant, doesn't store user refresh tokens server-side.

Filename

Used placeholder seps/0000-mcp-client-silent-refresh-on-401.md per SEP-1850 (PR-based SEP workflow). Happy to rename to the assigned PR number once you confirm.

Sponsor

Looking for a sponsor. SEP-2207 was sponsored by @pcarleton with @wdawson as author — given the topical overlap they're the natural asks. Tagging both for visibility.

Cross-references

Asks of reviewers

  1. Is the scope right? Should the SEP also normatively cover proactive expiry checks (Add Peder Holdgaard Pedersen to Financial Services Interest Group #1954-style) or is that better left as SDK guidance only?
  2. Sponsorship — willing to volunteer?
  3. Filename / number — happy to rename when assigned.
  4. Anything spec-style-wise I should adjust before review (RFC 2119 keyword usage, structure)?

Builds on SEP-2207 (OIDC-Flavored Refresh Token Guidance) which standardized
how clients request refresh tokens via offline_access. SEP-2207 stops at
issuance; this proposal specifies how clients should USE the refresh token
when receiving 401 invalid_token from a remote MCP server — silent refresh +
single retry, structured needs_reauth fallback when the refresh token is
itself invalid.

Filed alongside typescript-sdk#2031 which tracks the SDK-side reference
implementation. The two are complementary: SDK fix lands transparently for
TS SDK consumers; this SEP makes the behavior normative across MCP clients.

Filename uses placeholder 0000 — to be renamed to the assigned PR number
per SEP-1850.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant