Remote MCP OAuth token exchange omits resource for resource-bound servers
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:
- Configure the server:
``toml``
[mcp_servers.<server-name>]
url = "https://example.com/api/mcp"
- Run:
``bash``
codex mcp login <server-name>
- Complete the browser OAuth flow.
- Confirm the server is present and OAuth-backed:
``bash``
codex mcp list --json
- Start a Codex session and trigger MCP startup,
resources/list, ortools/listfor that server.
- Observe MCP startup failing at
initializewithAuth required.
The failing shape is:
codex mcp login <server>starts OAuth and the authorization URL includesresource=<MCP URL>.- OAuth completes and credentials are saved.
- At runtime, Codex attempts MCP
initializewith the saved credentials. - 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.0added 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/listshould 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:
Commit:
https://github.com/sotayamashita/codex/commit/0b6d5c53f0adfad6ca6eda62c97ee37a2935025e
The patch addresses the compatibility issue in Codex's rmcp integration:
- updates
rmcpfrom0.15.0to0.16.0; - updates the relevant Codex
reqwestpath to0.13so rmcp can use a Codex-built OAuth client; - preserves Codex custom CA/default header behavior on the rmcp OAuth path;
- avoids duplicate
resourcequery parameters in the login URL; - rejects
oauth_resource != MCP URLduring login until rmcp exposes explicit resource override; - adds mock OAuth/MCP coverage for login, token exchange,
initialize, andtools/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, andmcp list --json. - Authorization URL included
resource=<MCP URL>exactly once withoutoauth_resourcein config. - MCP
initialize,tools/list, and a read-only tool call succeeded. resources/listreturnedMethod 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.