Repository navigation
fix(mcp): re-authorization and connection failures for the MCP client - #2782
Open
mattzcarey wants to merge 3 commits into
Open
mattzcarey wants to merge 3 commits into
mattzcarey wants to merge 3 commits into
Conversation
Fixes #2658. Re-authorization: a request that needs the user again (scope step-up, or a 401 whose refresh fails) throws MCPAuthorizationRequiredError with a link and moves the server to authenticating. OAuth flows take turns per connection, re-authorization stops after three rounds for the same scopes (MCP spec step-up limit), a declined step-up keeps the session on its current grant, and a request made before the first authorization gets the pending link. Connection failures: each connect makes the server's quick attempts (connect plus discovery), then records the failure. A failed server stays failed across wakes until reconnectMcpServer(id); refused authorization skips the attempts. addMcpServer() for a registered server reports its state as is; a waiting server keeps its link until reconnected. The manager is split into a facade and controllers (servers, authorization, status), with per-server lanes for connection work. Integration tests run an Agent against an OAuth MCP server served through msw.
🦋 Changeset detectedLatest commit: d1be052 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
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 |
This was referenced Oct 30, 2026
agents
@cloudflare/ai-chat
@cloudflare/codemode
hono-agents
@cloudflare/shell
@cloudflare/think
@cloudflare/voice
@cloudflare/worker-bundler
commit: |
Contributor
🟡 agents import sizes: 4 entry points grew
Changed exports (26)
How this worksEach 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 |
…; stale-session recovery keeps its link; a declined step-up survives a wake - Work for a server added again waits for the removed server's running work, so a late code exchange cannot delete the new flow's discovery state, and it clears only its own tokens. - Recovering a forgotten session records what discovery found, including a link when only the catalog needs OAuth. - A declined step-up on a server that still holds tokens reconnects on that grant when the session it ran on is gone.
…er a wake resumes only a step-up The flag is stored with the link (pending_step_up), so a fresh sign-in that the user declines is still recorded, whatever tokens are stored. The resume starts from the callback handling itself, so standalone callers of handleCallbackRequest() get it too.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #2658. When an MCP server needs the user to authorize again partway through a session, the agent now says so. The request throws
MCPAuthorizationRequiredErrorwith a link, the server moves toauthenticating, and clients see the link throughgetMcpServers(). Connection failures are recorded and stay put, the same as in Claude Code. A connect makes a few quick attempts, then the server isfailed, across wakes too, until someone calls the newreconnectMcpServer(id).Before this, a step-up (
403 insufficient_scope) or a401whose refresh failed surfaced as a plainUnauthorizedError. The SDK had built a new authorization link that nobody saw, and its callback was ignored because the server was stillready. Failures weren't recorded, so every wake tried a failed server again, andaddMcpServer()sometimes replaced a pending link without being asked.Re-authorization:
401s share one refresh or one link.ready, reconnecting on the grant it holds if the agent has woken since.MCPAuthorizationRequiredErrorwith the pending link.callbackHostthat needs OAuth now says so, and says how to fix it.Failures:
retryoptions (3 attempts by default).403, OAuth errors such asinvalid_target, a revoked static key, rejected registration) skips the quick attempts and is recorded as refused. A denied callback is recorded too, so a wake doesn't start a flow the user just declined.addMcpServer()for a registered server reports its state as is:ready, the pending link, or the recorded failure. A waiting server keeps its link until the user completes it or reconnects. Whether an old link still works is up to the authorization server.Internally,
MCPClientManageris now a thin facade over controllers for servers, authorization and shared status. Connection work runs in per-server lanes, so connect, discovery, callbacks and restore never interleave on one server. A server removed and added again under the same id waits for the old server's running work, so a late code exchange can't overwrite the new flow. The public API only gainsreconnectMcpServer()andMCPAuthorizationRequiredError.The integration tests run an
Agentwith its default transport against an OAuth-protected MCP server served through msw. Callbacks go through the worker, and the object restarts between steps. They cover the happy path, step-ups and the round limit, outages, refusals, removal and re-add races, and users who click old links, reopen callbacks, decline, or press Reconnect at odd times.pnpm run buildandpnpm run checkpass, and so do the MCP tests (713). This replaces stack #2660, #2661, #2662, #2663, #2751, #2758, #2759, #2760, #2761 and #2778. The example apps are in the PR stacked on this one.