Remote MCP OAuth token exchange omits resource for resource-bound servers

Open 💬 0 comments Opened May 2, 2026 by sotayamashita

What version of Codex CLI is running?

codex-cli 0.128.0

What subscription do you have?

ChatGPT Pro. No subscription comparison was performed.

Which model were you using?

gpt-5.5. No model comparison was performed.

What platform is your computer?

Darwin 25.3.0 arm64 arm

What terminal emulator and version are you using (if applicable)?

Observed with Ghostty 1.3.1, Codex app 26.429.30905 (bundle 2345), and the terminal embedded in the Codex app.

What issue are you seeing?

A resource-bound remote MCP OAuth server can complete codex mcp login <server> and save OAuth credentials, but Codex can still fail during runtime MCP initialization because its current rmcp integration does not include the RFC 8707 resource parameter during OAuth token exchange.

The observed failure mode is:

resources/list failed: failed to get client: MCP startup failed:
handshaking with MCP server failed:
Send message error Transport [...]
error: Auth required, when send initialize request

The provider advertises OAuth protected resource metadata and returns a WWW-Authenticate challenge with resource_metadata. Its protected resource metadata has a resource value matching the MCP endpoint URL.

What steps can reproduce the bug?

Use a streamable HTTP MCP server that:

  • advertises OAuth protected resource metadata;
  • has protected resource metadata with resource == <MCP URL>;
  • requires a resource-bound access token for MCP initialize.

Then:

  1. Configure the server:

``toml
[mcp_servers.<server-name>]
url = "https://example.com/api/mcp"
``

  1. Run:

``bash
codex mcp login <server-name>
``

  1. Complete the browser OAuth flow.
  1. Confirm the server is present and OAuth-backed:

``bash
codex mcp list --json
``

  1. Start a Codex session and trigger MCP startup, resources/list, or tools/list for that server.
  1. Observe MCP startup failing at initialize with Auth required.

The failing shape is:

  1. codex mcp login <server> starts OAuth and the authorization URL includes resource=<MCP URL>.
  2. OAuth completes and credentials are saved.
  3. At runtime, Codex attempts MCP initialize with the saved credentials.
  4. The MCP endpoint rejects initialization as auth-required.

The relevant behavior appears to come from Codex's pinned rmcp version:

  • Codex currently pins rmcp = "0.15.0".
  • With Cargo pre-1.0 caret semantics, that does not automatically update to 0.16.0.
  • rmcp 0.16.0 added OAuth resource handling for both authorization and token exchange.

This makes the issue a Codex dependency-backed compatibility bug: login can appear successful, but the issued token may not be bound to the MCP resource because Codex's current rmcp version does not send the same resource indicator during token exchange.

What is the expected behavior?

For resource-bound remote MCP OAuth servers:

  • authorization request should include resource;
  • token exchange should include the same resource;
  • saved credentials should be usable for MCP initialize;
  • tools/list should succeed after initialization.

For providers where protected resource metadata has resource == MCP URL, users should not need to set oauth_resource manually.

Additional information

Patch available for maintainer review:

https://github.com/openai/codex/compare/main...sotayamashita:codex:fix/rmcp-oauth-resource-token-exchange

Commit:

https://github.com/sotayamashita/codex/commit/0b6d5c53f0adfad6ca6eda62c97ee37a2935025e

The patch addresses the compatibility issue in Codex's rmcp integration:

  • updates rmcp from 0.15.0 to 0.16.0;
  • updates the relevant Codex reqwest path to 0.13 so rmcp can use a Codex-built OAuth client;
  • preserves Codex custom CA/default header behavior on the rmcp OAuth path;
  • avoids duplicate resource query parameters in the login URL;
  • rejects oauth_resource != MCP URL during login until rmcp exposes explicit resource override;
  • adds mock OAuth/MCP coverage for login, token exchange, initialize, and tools/list.

The fail-fast behavior avoids a mismatch where Codex adds one resource while rmcp derives another from the MCP base URL.

Verification on the fork:

cargo test -p codex-rmcp-client --test oauth_resource
cargo test -p codex-rmcp-client
python3 .github/scripts/verify_cargo_workspace_manifests.py
just fix -p codex-rmcp-client
just bazel-lock-check
git diff --check

External smoke test against a private resource-bound MCP provider:

  • URL-only config completed mcp logout, mcp login, and mcp list --json.
  • Authorization URL included resource=<MCP URL> exactly once without oauth_resource in config.
  • MCP initialize, tools/list, and a read-only tool call succeeded.
  • resources/list returned Method not found; that is separate from the previous auth failure.

Related to #20707, #20009, and #18527 because they are in the same remote MCP OAuth / tool exposure area. This issue is narrower: it is specifically about missing RFC 8707 resource during token exchange for resource-bound MCP OAuth.

This issue does not claim to fix Desktop UI readiness state, browser OAuth flows that fail before credentials are stored, or broader tool mounting visibility issues.

View original on GitHub ↗