You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Opt-in scope on OAuth token refresh via the SDK's scopeForRefresh (Entra ID AADSTS90009) #2805
Some authorization servers reject a refresh-token request that carries no scope. Microsoft Entra ID does when the client and the resource are the same app registration: it answers AADSTS90009 (upstream modelcontextprotocol/typescript-sdk#2718). The Inspector refreshes through the SDK's auth(), which by default sends no scope on a refresh. So against such a server, every token refresh fails and the user has to re-authorize from scratch.
What the SDK now offers
MCP TypeScript SDK 2.4.0 (adopted in #2784 / #2799, upstream typescript-sdk#3085) adds an opt-in:
OAuthClientProvider gains an optional scopeForRefresh(tokens). When it is implemented, auth() (and so the transports and withOAuth) sends the string it returns as scope on the refresh request.
refreshAuthorization() gains an optional scope.
When a scope is sent and the token response has none, the sent scope is kept on the returned tokens.
Without either option, the refresh request and the saved tokens are unchanged.
What to do
Implement scopeForRefresh on BaseOAuthClientProvider (core/auth/providers.ts), opt-in per server, so the default refresh request stays exactly as it is today:
Add a per-server setting (for example "Send scope on token refresh"), alongside the existing OAuth settings (oauthScopes, oauthOnInsufficientScope) in the server settings form and in the config file, and pass it through to the provider.
When the setting is on, decide which scope to return and record why: the granted scope stored with the tokens, the configured scope (configuredScope / grantedScope in core/auth/types.ts), or the scope of the original authorization request. Keep this consistent with the rule in scopeForDeclinedRefreshGrant and with the step-up scope handling in core/auth/mcpAuth.ts.
Check the EMA wrapper (core/auth/ema/transportProvider.ts, which implements OAuthClientProvider by delegating to the base provider) forwards the new method.
When a refresh fails with an error naming a missing scope, consider pointing the user at the setting.
Out of scope
Changing the default refresh request for everyone. The SDK keeps its default unchanged on purpose, because sending scope on refresh can narrow or alter the grant on other authorization servers.
Activity
cliffhall commentedon Oct 25, 2026
Triage: Priority Low (total 5)
Milestone
v2.14.0:v2.13.0is due 2026-10-28.fix(auth): keep the refresh-scope fallback within the recorded grant (#…
cliffhall commentedon Oct 25, 2026
Shipped in #2809.