Skip to content

V2: MCP OAuth token refresh concurrency (cross-location/cross-process race) #34523

Closed

Description

@rekram1-node

Context

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.ts makeLocationNode) but Credential is global (packages/core/src/credential.ts makeGlobalNode). 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:

  1. 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.
  2. 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).

Activity

  1. self-assigned this
    on Jun 29, 2026
  2. github-actions commented on Jun 29, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

  3. opencode-agent commented on Jun 30, 2026

    @opencode-agent
    Contributor

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions