Repository navigation
feat(mcp): durable reconnect and authorization-expiry jobs - #2662
mattzcarey wants to merge 6 commits into
Conversation
🟡 agents import sizes: 4 entry points grew
Changed exports (24)
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 |
agents
@cloudflare/ai-chat
@cloudflare/codemode
hono-agents
@cloudflare/shell
@cloudflare/think
@cloudflare/voice
@cloudflare/worker-bundler
commit: |
e253db0 to
e9d494e
Compare
|
5515fea to
d3544e0
Compare
d3544e0 to
26a4adc
Compare
26a4adc to
075a26b
Compare
075a26b to
b888291
Compare
b888291 to
f4e4a5f
Compare
f4e4a5f to
833e3b6
Compare
833e3b6 to
16a368b
Compare
16a368b to
8a3b141
Compare
There was a problem hiding this comment.
Devin Review found 1 new potential issue.
⚠️ 1 issue in files not directly in the diff
⚠️ MCP client release lacks a changeset
When this feature reaches main without another changeset, agents receives no release entry. The release workflow versions packages through changeset version, so the new public reconnect option remains unpublished.
- connect:<id> Lifecycle job retries failed connects/discovery on a 30s..30m backoff, one bounded attempt per run, giving up after 24h with a recorded reconnect-exhausted failure - auth-expiry:<id> job fails a server whose authorization link expired unused (authorization-expired), instead of minting a new link - recorded failures persist in a failure column (added on first use); restore shows them without connecting, explicit reconnects clear them - addMcpServer reconnects a failed server instead of throwing - RPC restore builds its transport from the persisted binding and shares the HTTP restore path - MCPClientManagerOptions.reconnect tunes the schedule
…ration - restore leaves a server with a pending connect job failed (showing the job's last error) instead of connecting early - migrateServerId moves connect and auth-expiry jobs to the new id - the OAuth callback clears auth_url before redeeming the state, so a dead link on wake always means the flow expired unused - reaching ready clears the connection error left by a recorded failure
A durable reconnect only helps when the failure can pass. A 401 the agent cannot answer with a link (a revoked static token, no OAuth callback), a 403 left after any step-up, or an OAuth error such as invalid_target, invalid_scope or access_denied gets the same answer on every attempt, so the server now records an authorization-failed failure instead of retrying for a day. Network errors, 5xx, timeouts, server_error and temporarily_unavailable still back off as before; invalid_grant still starts a fresh authorization.
8a3b141 to
446f358
Compare
A failed MCP connect or discovery now schedules a durable
connect:<serverId>Lifecycle job. It retries after 30s, 1m, 2m, 5m and 10m, then every 30m, and after 24h records areconnect-exhaustedfailure. Anauth-expiry:<serverId>job moves a server whose authorization link expired unused tofailed, so a dead link is no longer shown and no new one gets minted.Stacked on #2661, and part of the same work on #2658. Every retry used to live in memory.
_connectWithRetrymade 3 quick attempts, and then the server sat infaileduntil the isolate died, which with live sockets could take hours. Nothing woke the object to try again, and the connect after an OAuth callback was a fire-and-forget promise.Things callers will notice:
401the agent can't answer with a link (a revoked static token, no OAuth callback), a403left after any step-up, or an OAuth error such asinvalid_targetoraccess_denied. The server records anauthorization-failedfailure. Network errors,5xx, timeouts,server_errorandtemporarily_unavailablestill back off.addMcpServer(),connectToServer(),establishConnection()orregisterServer()addMcpServer()on afailedserver reconnects. It used to throw.failedwhen the object wakes for another reason, and waits for that jobnew MCPClientManager(name, version, { reconnect: { delaysMs, giveUpAfterMs } })failurecolumn tocf_agents_mcp_serversthe first time it records a failurepnpm run check, the agents workers suite and the conformance lanes pass. New tests run both jobs through real Lifecycle alarms on a plain Durable Object, including staying failed after eviction, giving up and then reconnecting explicitly, and moving jobs whenmigrateServerId()renames a server.The durable reconnect schedule and the link-expiry job here are removed in #2778, which records failures and leaves retrying to
reconnectMcpServer(), as Claude Code does. Review refusal and failure recording here, and the rest there.