-
Notifications
You must be signed in to change notification settings - Fork 354
Description
Problem
The current account selection flow requires a stateful two-step dance:
- Call
accounts_listto discover accounts - Call
set_active_accountto persist the selection in a Durable Object
This breaks in many MCP clients that don't maintain state across tool calls, leading to repeated "No currently active accountId" errors. Multiple issues have been filed about this: #226, #260, #281, #175.
Additional problems with the current approach:
set_active_accountis not registered for account-scoped tokens, but error messages still reference it ([Bug]set_active_accounttool not exposed - cannot use D1/KV/R2 tools with single account #260)- Account persistence doesn't work across different MCP server instances (Account persistence issue: set_active_account succeeds but other MCP tools report "No currently active accountId" #226)
- Requires an extra round-trip before any useful work can happen
Proposed Solution
Add an optional account_id parameter to every tool that requires an account, and remove the stateful set_active_account tool entirely.
Spec
Resolution logic (resolveAccountId)
When a tool needs an account ID, resolve it in this order:
- Account token: Always use
props.account.id. Ignore anyaccount_idparameter. - User token +
account_idprovided: Validate it againstprops.accounts. Use it if valid, return error listing valid accounts if not. - User token + single account + no
account_id: Auto-select the only account. - User token + multiple accounts + no
account_id: Return an error response listing available accounts (id + name) so the LLM can self-correct on the next call.
Tool changes
- Add
account_id?: string(optional Zod param) to every tool that currently callsgetActiveAccountId() - Shared
AccountIdParamschema andresolveAccountId()helper in a newpackages/mcp-common/src/tools/account.helpers.ts - Error responses include
available_accountslist — no separateaccounts_listcall needed to recover
What gets removed
set_active_accounttool registration (fromaccount.tools.ts)getActiveAccountId()/setActiveAccountId()from theCloudflareMcpAgentinterfacegetActiveAccountId()/setActiveAccountId()implementations from all ~14 app classesactive_account_idstorage fromUserDetailsDurable ObjectMISSING_ACCOUNT_ID_RESPONSEconstant
What stays
accounts_listtool (for explicit discovery)UserDetailsDurable Object class (may be used for other per-user state)
Affected tools (~20+ across packages/mcp-common and apps/)
packages/mcp-common/src/tools/: d1 (5), kv (5), r2 (4), workers (3), zones (2), hyperdrive (4)
apps/: ai-gateway, workers-observability, workers-builds, logpush, autorag, auditlogs, browser-rendering, dex-analysis, dns-analytics, graphql, radar, cloudflare-one-casb
Benefits
- Stateless: Works with any MCP client, no state management required
- Fewer round-trips: Single account users auto-resolve; multi-account users get account list in the error response
- Self-correcting: Error responses include available accounts, so LLMs can retry immediately with the right ID
- Simpler code: No Durable Object reads on every tool call, synchronous resolution from props