Skip to content

feat(mcp): keep step-up grants when a refused refresh leads to a new authorization - #2698

Closed
mattzcarey wants to merge 5 commits into
feat/mcp-step-up-retry-limitfrom
test/sdk-2448-scope-retention
Closed

mattzcarey wants to merge 5 commits into
feat/mcp-step-up-retry-limitfrom
test/sdk-2448-scope-retention

Conversation

@mattzcarey

@mattzcarey mattzcarey commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

Opts DurableObjectOAuthClientProvider into includePreviouslyGrantedScopes from modelcontextprotocol/typescript-sdk#2448, and makes the "401 whose token refresh fails" test check the scope in the new authorization link. The repo pins the pkg.pr.new build of #2448 so this runs against it. Stacked on #2663.

Without it, a user grants workers_scripts:write through step-up, the refresh is later refused, the server answers 401 with its base scope, and the new link asks for account:read user:read only, so the write tools fail again and the user goes back through step-up. With the flag the link asks for all three. With the flag set to false, the same assertion fails:

  [
    "account:read",
    "user:read",
-   "workers_scripts:write",
  ]

Against the preview (9f7c248): the MCP suite (681 tests), all four client conformance lanes and pnpm run check pass.

Not for merging as is. The pnpm-workspace.yaml override points at a preview URL, and blockExoticSubdeps is off because the preview client depends on the preview core by URL. Once #2448 is in a release, drop both and bump @modelcontextprotocol/client; the flag and the test stay.

Behaviour changes

  • After a refused refresh (invalid_grant), the authorization link for an MCP server also asks for the scopes the dropped tokens held, minus offline_access and anything the authorization server does not list in scopes_supported. Asked for once: if the server refuses, the next link asks for the challenged scope alone.

…thorization

The "401 whose token refresh fails" test never checked the scope in the new
authorization link. On @modelcontextprotocol/client 2.3.1 that link asks for
the server's base scope only and drops the write scope the user granted
through step-up, so the write tools fail again and the user is sent back
through step-up (#2663).

Pin the pkg.pr.new build of modelcontextprotocol/typescript-sdk#2448 and
assert the link keeps the write scope. Not for merging as is: the override
and blockExoticSubdeps go away once #2448 is released.
@changeset-bot

changeset-bot Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 14b72ea

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@agent-think

agent-think Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

🔴 agents import sizes: 1 entry point over threshold

Entry point Exports Largest gzip change Size now
🔴 agents/mcp/client 5 resized up to +13 KiB (+20.42%) 76.4 KiB
Changed exports (5)
Import Gzip change Size now
🔴 agents/mcp/client#normalizeServerId +13 KiB (+20.42%) 76.4 KiB
🔴 agents/mcp/client#getNamespacedData +13 KiB (+20.43%) 76.4 KiB
🔴 agents/mcp/client#MCPConnectionNotFoundError +13 KiB (+20.42%) 76.4 KiB
🔴 agents/mcp/client#MCP_SERVER_ID_MAX_LENGTH +13 KiB (+20.44%) 76.3 KiB
🔴 agents/mcp/client#MCPAuthorizationRequiredError +12.9 KiB (+20.4%) 76.4 KiB
How this works

Each runtime export is bundled on its own, minified, and gzipped. Changes smaller than 100 B, or smaller than 1% and 1 KiB, are ignored. Growth over 10% or 5 KiB is marked 🔴. This report is informational and does not fail CI. The workflow artifact contains every measurement.

Compared cd5ce454 → 14b72ea3 · workflow run · reported by agent-think[bot]

@pkg-pr-new

pkg-pr-new Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

agents

npm i https://pkg.pr.new/agents@2698

@cloudflare/ai-chat

npm i https://pkg.pr.new/@cloudflare/ai-chat@2698

@cloudflare/codemode

npm i https://pkg.pr.new/@cloudflare/codemode@2698

hono-agents

npm i https://pkg.pr.new/hono-agents@2698

@cloudflare/shell

npm i https://pkg.pr.new/@cloudflare/shell@2698

@cloudflare/think

npm i https://pkg.pr.new/@cloudflare/think@2698

@cloudflare/voice

npm i https://pkg.pr.new/@cloudflare/voice@2698

@cloudflare/worker-bundler

npm i https://pkg.pr.new/@cloudflare/worker-bundler@2698

commit: 14b72ea

…authorization

Opt DurableObjectOAuthClientProvider into the SDK's
includePreviouslyGrantedScopes (typescript-sdk#2448, preview dfb8587). When a
refresh is refused, the new authorization link also asks for the scope the
dropped tokens held, so a write scope granted through step-up survives
instead of sending the user back through step-up (#2663).
@mattzcarey mattzcarey changed the title test(mcp): show typescript-sdk#2448 keeps granted scopes on 401 re-authorization feat(mcp): keep step-up grants when a refused refresh leads to a new authorization Oct 26, 2026
@mattzcarey mattzcarey closed this Oct 26, 2026
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