Skip to content

[rmcp-client] Route all MCP OAuth recovery through Codex#29018

Open
stevenlee-oai wants to merge 1 commit into
dev/stevenlee/mcp-oauth-stack-4-shared-storesfrom
dev/stevenlee/mcp-oauth-stack-5-codex-refresh
Open

[rmcp-client] Route all MCP OAuth recovery through Codex#29018
stevenlee-oai wants to merge 1 commit into
dev/stevenlee/mcp-oauth-stack-4-shared-storesfrom
dev/stevenlee/mcp-oauth-stack-5-codex-refresh

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 4 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
  4. openai/codex#29018 — route all OAuth recovery through Codex (this PR)
  5. openai/codex#30089 — consolidated concurrency and transport regression tests

Why

Giving RMCP a refresh token creates a second, unsynchronized refresh owner. Simply removing it would leave RMCP-owned SSE reconnects, server-response POSTs, and session DELETEs unable to recover. This layer switches both sides together: RMCP receives request-only credentials while Codex owns proactive refresh and one-shot 401 recovery for every transport path.

What changes

  • Give RMCP only the access token and token type during ordinary requests; withhold refresh token and expiry metadata so RMCP cannot refresh independently.
  • Temporarily install full credentials only while Codex holds the serialized refresh transaction, then restore request-only credentials.
  • Add a Codex-owned StreamableHttpClient wrapper around RMCP's authenticated client.
  • Proactively refresh and recover once for RMCP-owned Response/Error POSTs, SSE GET/reconnects, and session DELETEs.
  • Keep client-originated Request/Notification recovery in outer RmcpClient, which knows the caller deadline and whether replay is still allowed.
  • Attribute a delayed 401 to the access token actually sent, so a request rejected for A adopts B instead of rotating B again.
  • Refresh 60 seconds before expiry so normal requests do not race the boundary.

Decisions encoded by this stack

  • OAuth policy belongs to Codex; RMCP remains the transport and bearer-injection layer.
  • Public Request/Notification recovery stays outside the wrapper because wrapper-level retry could replay a request after its caller timed out.
  • RMCP-generated Response/Error POSTs, GET/reconnect, and DELETE recover in the wrapper because no public outer operation owns them.
  • Every rejected request gets at most one 401 recovery attempt.
  • A provider timeout releases the lock with an unknown outcome and permits a later serialized retry.
  • Refreshed B becomes request-authoritative only after the selected store accepts it. Persistence failure is logged at the failing transaction, restores the previous request-only credentials, returns an error, and is not retried automatically.
  • Auto stays pinned to one source for the client lifecycle; part 3's durable record is diagnostic only.
  • openai/codex#28647 and its branch remain untouched.

Review focus

Review the ownership handoff as one unit: request-only exposure, temporary full credentials inside the transaction, token-attributed delayed-401 handling, and exactly one owner for each POST/GET/DELETE category.

Non-goals

  • Changing upstream RMCP.
  • Persistence retries, provider-timeout quarantine, or durable backend authority.
  • Changing caller-visible MCP timeout configuration.

Validation

  • just test -p codex-rmcp-client: 90 passed, 2 skipped at this layer.
  • Live transport and delayed-concurrency coverage is consolidated in part 5.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dc25e7aae8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread codex-rs/rmcp-client/src/oauth.rs Outdated
Comment thread codex-rs/rmcp-client/src/rmcp_client.rs Outdated
Comment thread codex-rs/rmcp-client/src/streamable_http_retry.rs Outdated
@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-5-codex-refresh branch from dc25e7a to ebb9b90 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-5-codex-refresh branch 2 times, most recently from 8828c4b to b88dbae 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-4-shared-stores branch from 38b1739 to 0a1fd12 Compare June 23, 2026 06:19
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-5-codex-refresh branch from b88dbae to 0def9f2 Compare June 23, 2026 06:28
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-4-shared-stores branch from 0a1fd12 to f928100 Compare June 23, 2026 07:27
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-5-codex-refresh branch from 0def9f2 to 31ceaeb Compare June 23, 2026 07:27
@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-5-codex-refresh branch 3 times, most recently from 55c407e to 6957b8b 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-5-codex-refresh branch from 6957b8b to 3246e90 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-5-codex-refresh branch from 3246e90 to aa94ede Compare June 25, 2026 17:26
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-5-codex-refresh branch from aa94ede to d6434ec 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-5-codex-refresh branch from d6434ec to 64f9f77 Compare June 25, 2026 18:13
@stevenlee-oai stevenlee-oai changed the title [rmcp-client] Keep MCP OAuth refreshes in Codex [rmcp-client] Route MCP OAuth refresh through Codex Jun 25, 2026
@stevenlee-oai stevenlee-oai changed the base branch from dev/stevenlee/mcp-oauth-stack-4-shared-stores to dev/stevenlee/mcp-oauth-stack-6-codex-recovery June 25, 2026 18:18
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-5-codex-refresh branch from 64f9f77 to 6bf5882 Compare June 25, 2026 18:45
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-6-codex-recovery branch from 2bb8dc9 to 0e139f8 Compare June 25, 2026 18:45
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-5-codex-refresh branch 2 times, most recently from 7b4f748 to dd9a13b Compare June 25, 2026 21:11
@stevenlee-oai stevenlee-oai requested a review from a team as a code owner June 25, 2026 21:11
@stevenlee-oai stevenlee-oai changed the title [rmcp-client] Route MCP OAuth refresh through Codex [rmcp-client] Route all MCP OAuth recovery through Codex Jun 25, 2026
@stevenlee-oai stevenlee-oai changed the base branch from dev/stevenlee/mcp-oauth-stack-6-codex-recovery to dev/stevenlee/mcp-oauth-stack-4-shared-stores June 25, 2026 21:13
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-5-codex-refresh branch from dd9a13b to 0b3dcef Compare June 25, 2026 21:16
@stevenlee-oai stevenlee-oai reopened this Jun 25, 2026
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-5-codex-refresh branch from dd9a13b to 52e1548 Compare June 25, 2026 21:29
@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-5-codex-refresh branch from 52e1548 to 6bb89cb 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-5-codex-refresh branch from 6bb89cb to 6705ef7 Compare June 26, 2026 06:10
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-4-shared-stores branch from 2b88193 to 51cdac5 Compare June 26, 2026 06:10
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-5-codex-refresh branch from 6705ef7 to 44d29b6 Compare June 26, 2026 06:33
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-4-shared-stores branch from 51cdac5 to fdb60d6 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
@stevenlee-oai stevenlee-oai force-pushed the dev/stevenlee/mcp-oauth-stack-5-codex-refresh branch from 44d29b6 to 2e6a3e1 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