Skip to content

feat(mcp): limit step-up re-authorization rounds (MCP spec 2026-07-28) - #2663

Open
mattzcarey wants to merge 3 commits into
feat/mcp-durable-connection-jobsfrom
feat/mcp-step-up-retry-limit
Open

mattzcarey wants to merge 3 commits into
feat/mcp-durable-connection-jobsfrom
feat/mcp-step-up-retry-limit

Conversation

@mattzcarey

@mattzcarey mattzcarey commented Oct 22, 2026 •

Copy link
Copy Markdown
Member

Re-authorization now has a limit, as the MCP authorization spec requires. If the user has completed three authorizations for the same scopes within an hour and the server asks for them again, the client shows no fourth link. The server moves to failed with a recorded failure. auth/scope-retry-limit now passes, so it comes off the 2026-07-28 baseline and the 2025-11-25 lane runs with no baseline at all.

Stacked on #2662, and part of the same work on #2658. The 2026-07-28 spec says clients should retry step-up "no more than a few times and treat this as a permanent authorization failure". The SDK transport has a per-request step-up limit, but every OAuth round trip reconnects on a new transport and resets it. So a server that never gets the scope it asks for could send the user through OAuth forever, and the conformance referee saw four authorization requests where it allows three.

How rounds are counted, in authorization-rounds.ts:

  • per requested scope set, read from the authorization URL's scope parameter, so challenges that alternate between two scope sets each use up their own budget
  • a new round counts only after the previous round's callback exchanged a code, so two tool calls that hit the same step-up together count once
  • a scope set's count expires an hour after its last round. An explicit reconnect of the failed server resets every count, and ordinary OAuth round trips keep them.

Once the limit is hit, callTool(), readResource() and getPrompt() rethrow the SDK's UnauthorizedError instead of MCPAuthorizationRequiredError. connectToServer() returns failed with the reason.

pnpm run check, the agents workers suite and all client conformance lanes pass. A new test runs three real step-up rounds against an authorization server that never grants the write scope, and checks that the fourth fails, stays failed after a wake, and shows a link again after an explicit reconnect.

@changeset-bot

changeset-bot Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 6eba4f2

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
agents Patch
@cloudflare/agent-think Patch

Not sure what this means? Click here to learn what changesets are.

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

devin-ai-integration[bot]

This comment was marked as resolved.

@agent-think

agent-think Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

✅ agents import sizes: no significant changes (16a368b2 → 6eba4f2d, workflow run)

@pkg-pr-new

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

Copy link
Copy Markdown

Open in StackBlitz

agents

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

@cloudflare/ai-chat

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

@cloudflare/codemode

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

hono-agents

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

@cloudflare/shell

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

@cloudflare/think

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

@cloudflare/voice

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

@cloudflare/worker-bundler

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

commit: 6eba4f2

@mattzcarey
mattzcarey force-pushed the feat/mcp-step-up-retry-limit branch from 870fdba to 427a67d Compare October 22, 2026 14:25
@mattzcarey
mattzcarey force-pushed the feat/mcp-step-up-retry-limit branch from 427a67d to 8f56c51 Compare October 22, 2026 14:40
devin-ai-integration[bot]

This comment was marked as resolved.

mattzcarey added a commit that referenced this pull request Oct 26, 2026
…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 force-pushed the feat/mcp-step-up-retry-limit branch from cd5ce45 to d5a9732 Compare October 27, 2026 12:06
@mattzcarey
mattzcarey force-pushed the feat/mcp-step-up-retry-limit branch from d5a9732 to 0b90b04 Compare October 27, 2026 13:04
@mattzcarey
mattzcarey force-pushed the feat/mcp-step-up-retry-limit branch from 0b90b04 to 637d72c Compare October 27, 2026 13:49
@mattzcarey
mattzcarey added this pull request to stack #2750 October 27, 2026 18:20
@mattzcarey
mattzcarey force-pushed the feat/mcp-step-up-retry-limit branch from 637d72c to ea56f38 Compare October 27, 2026 20:30
@mattzcarey
mattzcarey force-pushed the feat/mcp-step-up-retry-limit branch from ea56f38 to 3c908c1 Compare October 27, 2026 22:41
- authorization rounds are counted per requested scope set; a round counts
  once its callback completed and the server asked for the same scopes
- a fourth round within an hour records an authorization-exhausted failure
  instead of showing another link
- auth/scope-retry-limit now passes; removed from both client baselines
… reconnect

- each requested scope set keeps its own round budget, so challenges that
  alternate between scope sets cannot loop forever
- connectToServer/establishConnection on a server with a recorded failure
  also clear an exhausted authorization budget
@mattzcarey
mattzcarey force-pushed the feat/mcp-step-up-retry-limit branch from 3c908c1 to 6eba4f2 Compare October 28, 2026 10:05
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