Skip to content

[rmcp-client] Serialize shared MCP OAuth stores#29021

Open
stevenlee-oai wants to merge 1 commit into
dev/stevenlee/mcp-oauth-stack-3-login-logoutfrom
dev/stevenlee/mcp-oauth-stack-4-shared-stores
Open

[rmcp-client] Serialize shared MCP OAuth stores#29021
stevenlee-oai wants to merge 1 commit into
dev/stevenlee/mcp-oauth-stack-3-login-logoutfrom
dev/stevenlee/mcp-oauth-stack-4-shared-stores

Conversation

@stevenlee-oai

@stevenlee-oai stevenlee-oai commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Codex Thread 019edd6d-6f14-74e2-853c-345d1803d4a6

Important

This PR belongs to the superseded MCP OAuth stack. Please review and merge the replacement stack beginning with openai/codex#30292. This PR remains available only as historical/reference context.

Replacement review order:

  1. openai/codex#30292 — shared File/Secrets store locking
  2. openai/codex#30293 — authoritative serialized refresh
  3. openai/codex#30294 — Codex-owned transport refresh and one-shot 401 recovery
  4. openai/codex#30295 — login/logout transaction serialization
  5. openai/codex#30296 — diagnostic-only Auto store drift reporting

This is part 3 of a five-PR stack that prevents concurrent MCP OAuth refreshes from replaying a rotating refresh token or overwriting newer credentials.

Review and merge as one stack. The five PRs are an atomic merge unit split only for reviewability. Each tip compiles and is testable, but implementation and regression tests are intentionally not duplicated across intermediate layers.

Review order

  1. openai/codex#29017 — refresh ownership, authoritative reread, and lifecycle-local store pinning
  2. openai/codex#29019 — serialize login and logout with refresh
  3. openai/codex#29021 — lock aggregate stores and observe Auto resolution drift (this PR)
  4. openai/codex#29018 — route all OAuth recovery through Codex
  5. openai/codex#30089 — consolidated concurrency and transport regression tests

Why

The per-credential transaction lock protects one OAuth authority, but File and Secrets each store multiple server credentials in one aggregate document. Two different credential identities can still race a read-modify-write and lose each other's update.

Separately, lifecycle-local Auto resolution can choose a different store in a later process if keyring availability changes. Persisting that choice as authority would require migration and reconciliation policy that is intentionally outside this stack, but silently changing stores makes field failures hard to diagnose. This layer records only enough token-free history to surface that drift.

What changes

  • Add store-scoped cross-process locks around aggregate File and Secrets reads, saves, and deletes.
  • Keep aggregate-store locking independent from the per-credential refresh transaction while preserving one acquisition order.
  • Hold aggregate locks only for local store work, never across a provider request.
  • Add a versioned $CODEX_HOME/.mcp-oauth-store-resolutions.json diagnostic map, serialized with its own short best-effort lock and atomic writes.
  • Key each observation with compute_store_key(server_name, url) and store only store_mode, keyring_backend, and resolved_store; no tokens or raw URL are added.
  • When the same identity resolves Auto differently under the same keyring backend, emit a warning and increment codex.mcp.oauth.store_resolution_changed with low-cardinality previous/current/reason tags.
  • Treat explicit File/Keyring configuration or a keyring-backend change as an intentional baseline reset.
  • Emit a stable debug event on actual store-lock WouldBlock contention for diagnostics and deterministic regression tests.

Decisions encoded by this stack

  • The per-credential lock protects OAuth authority; the aggregate-store lock protects document integrity. Neither substitutes for the other.
  • Lock order is credential transaction first, aggregate store second.
  • Direct keyring entries are per credential and do not use the aggregate credential-store lock.
  • The resolution sidecar is diagnostic only. It is never read to select, migrate, refresh, save, or delete credentials, and its failures never fail OAuth.
  • Diagnostic history is scoped to the active CODEX_HOME, matching File/Secrets state. Distinct homes do not share an authority registry.
  • The last token-free observation survives logout and is replaced by the next successful resolution or save, allowing a later login to report a changed Auto choice without resurrecting credentials.
  • The existing synchronous store APIs remain synchronous and bounded in this stack; an async store-I/O redesign is separate work.
  • Auto never switches stores during one client lifecycle.
  • openai/codex#28647 and its branch remain untouched.

Review focus

Review store scope, lock ordering, whether unrelated credential entries survive concurrent read-modify-writes, and the hard boundary between diagnostic history and credential authority.

Non-goals

  • Persisting an authoritative backend selector, backend migration, or reconciliation of legacy entries.
  • Redesigning the underlying synchronous file/secrets APIs.
  • Cleanup of non-selected legacy credential entries.

Validation

  • just test -p codex-rmcp-client: 90 passed, 2 skipped at this layer.
  • Resolution-state and File/Secrets contention coverage is consolidated in part 5.

@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-4-shared-stores branch from 73edd11 to 2baa0c1 Compare June 19, 2026 04:06
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-3-login-logout branch from c81db4f to b723a59 Compare June 19, 2026 04:06
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-4-shared-stores branch from 2baa0c1 to 98c3fc1 Compare June 19, 2026 15:29
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-3-login-logout branch from 0da283d to 50cbb47 Compare June 19, 2026 16:18
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-4-shared-stores branch from 98c3fc1 to 38b1739 Compare June 19, 2026 16:18
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-3-login-logout branch from 50cbb47 to 4d5fa46 Compare June 23, 2026 06:16
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-4-shared-stores branch 2 times, most recently from 0a1fd12 to f928100 Compare June 23, 2026 07:27
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-3-login-logout branch 2 times, most recently from 0c1a341 to 8926a37 Compare June 23, 2026 23:38
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-4-shared-stores branch from f928100 to 966f233 Compare June 23, 2026 23:38
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-3-login-logout branch from 8926a37 to a548c67 Compare June 25, 2026 02:45
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-4-shared-stores branch from ac8101b to 25011b8 Compare June 25, 2026 02:45
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-3-login-logout branch from a548c67 to e6aa44f Compare June 25, 2026 02:54
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-4-shared-stores branch from 25011b8 to c37c566 Compare June 25, 2026 02:54
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-4-shared-stores branch from c37c566 to b44ee7c Compare June 25, 2026 17:26
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-3-login-logout branch from e6aa44f to e7cdf26 Compare June 25, 2026 17:26
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-3-login-logout branch from e7cdf26 to f6102b4 Compare June 25, 2026 18:07
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-4-shared-stores branch from b44ee7c to 3628ccf Compare June 25, 2026 18:07
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-3-login-logout branch from f6102b4 to b614316 Compare June 25, 2026 18:45
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-4-shared-stores branch from 3628ccf to 606864f Compare June 25, 2026 18:45
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-3-login-logout branch from b614316 to 349a7f4 Compare June 25, 2026 21:11
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-4-shared-stores branch from 606864f to 0b3dcef Compare June 25, 2026 21:11
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-3-login-logout branch from 349a7f4 to a727719 Compare June 25, 2026 21:16
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-4-shared-stores branch from 0b3dcef to b210375 Compare June 25, 2026 21:29
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-3-login-logout branch 2 times, most recently from 674f690 to 4c3d976 Compare June 26, 2026 05:51
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-4-shared-stores branch from b210375 to 2b88193 Compare June 26, 2026 05:51
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-3-login-logout branch from 4c3d976 to a6f054b Compare June 26, 2026 06:10
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-4-shared-stores branch 2 times, most recently from 51cdac5 to fdb60d6 Compare June 26, 2026 06:33
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-3-login-logout branch from a6f054b to b60ae97 Compare June 26, 2026 06:33
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-4-shared-stores branch from fdb60d6 to 665d653 Compare June 26, 2026 07:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant