Skip to content

fix(core): preserve MCP OAuth scope when omitted - #58699

Open
yiaany wants to merge 1 commit into
anomalyco:devfrom
yiaany:mcp-oauth-scope
Open

yiaany wants to merge 1 commit into
anomalyco:devfrom
yiaany:mcp-oauth-scope

Conversation

@yiaany

@yiaany yiaany commented Oct 24, 2026 •

Copy link
Copy Markdown

Issue for this PR

Fixes #58319

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Preserves the requested scope when an OAuth provider omits scope from its token response, as specified by RFC 6749 §5.1. Without it, the MCP SDK treats an insufficient_scope challenge as a scope expansion and skips the stored refresh token.

The fallback comes from the actual authorization URL, so it includes scopes selected from server metadata and any offline_access added by the SDK. Refresh responses without scope retain the previously granted scope. An explicitly returned scope, including an empty string, remains authoritative.

Adds regression coverage using a local OAuth/resource server and the real MCP HTTP transport. The tests cover configured, challenged and discovered scopes, repeated refreshes after expiry, explicit response scopes, and genuine scope expansion still requiring authorization.

How did you verify your code works?

  • Confirmed the new regression tests fail before the fix.
  • MCP and OAuth suites: 99 passed, 1 skipped.
  • OAuth suite repeated 10 times: 280 passed, no failures.
  • bun typecheck and bun run typecheck:tsc in packages/core passed.
  • Root bun run check passed with Bun 1.4.4. On Windows, I temporarily materialized the app's existing declaration-file symlink for this check; that setup change is not included in the PR.

I have not tested against a live Cognito deployment.

Screenshots / recordings

Not applicable; no UI changes.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Added by the opencode bot (AI-generated).

Related: #49773, #53942

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix works. I ran the #58319 reproduction (a mock OAuth/MCP server whose token responses leave out scope) against both checkouts from source. On the base, an expired token gets 403 insufficient_scope, no refresh follows, and the server shows needs authentication. With this change, the same 403 is followed by a refresh_token request and the server reconnects. The new tests fail on the base and pass with the fix; the OAuth suite passed 5 more runs in a row, and typecheck:tsc passes.

Public API: unchanged. The stored credential's metadata.scope is now filled in when the provider leaves scope out, using the existing field.

One limitation worth noting: credentials saved before this change have no stored scope, and a refresh only falls back to the previously stored one. Affected users will still hit the re-login once after upgrading; after that, the stored scope is kept. That's acceptable, but worth a line in the release notes.

The new table-driven test is long (about 160 lines) for what it checks, but it is deterministic: expiry is forced through the stored credential, with no sleeps.

Related: #49773, #53942

This branch has not been deployed

No deployments
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.

MCP OAuth: missing scope in token response causes repeated browser re-authentication

1 participant