You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
While designing V2 MCP OAuth (registering remote MCP servers as synthetic OAuth integrations, with tokens stored in the global Credential table), we identified a concurrency hazard that we are explicitly deferring out of the initial auth implementation.
Problem
Integration is location-scoped (packages/core/src/integration.tsmakeLocationNode) but Credential is global (packages/core/src/credential.tsmakeGlobalNode). The OAuth tokens for an MCP server therefore live in one shared row, identified by a hash of the server URL, while refresh can be driven from multiple places.
When the same MCP server (same URL → same credential row) is used from:
Multiple locations in one process — each location-scoped MCP service has its own SDK OAuthClientProvider. On token expiry they can each independently refresh against the shared global row.
Multiple processes (e.g. a daemon plus a CLI invocation, or two servers) — no shared memory, only the shared SQLite DB.
If the auth server uses rotating refresh tokens (common), two concurrent refreshes invalidate each other: the loser's refresh token goes stale and that consumer falls into needs_auth.
Note: V1 had the same race — its file lock only serialized the write, not the decision to refresh.
Proposed direction (not yet implemented)
Same-process, multi-location: an in-memory global single-flight keyed by credential id (in the global tier alongside Credential) so concurrent refreshes coalesce and await one result.
Cross-process: optimistic compare-and-swap — refresh inside a transaction, re-read the row, and if the stored refresh token already changed, adopt the existing fresh token instead of overwriting.
To control when refresh happens, the MCP provider should refresh proactively under the single-flight (in its tokens() path) and hand the SDK an already-fresh token, so the SDK rarely refreshes reactively.
Scope
Tracking only. The initial MCP OAuth implementation intentionally ships without this hardening (tolerates last-write-wins / re-auth, V1 parity).
Closing as a duplicate of #34520. Both track the same V2 MCP OAuth token refresh concurrency race across locations/processes; keeping #34520 as the canonical follow-up.
Activity
github-actions commentedon Jun 29, 2026
This issue might be a duplicate of existing issues. Please check:
opencode-agent commentedon Jun 30, 2026
Closing as a duplicate of #34520. Both track the same V2 MCP OAuth token refresh concurrency race across locations/processes; keeping #34520 as the canonical follow-up.