codex mcp login sends the OAuth `resource` parameter twice when `oauth_resource` is set, breaking strict providers (e.g. Amplitude MCP)

Open 💬 1 comment Opened Jul 21, 2026 by andymoss-mindtrip

What version of Codex is running?

codex-cli 0.144.4

What issue are you seeing?

When an HTTP MCP server is configured with oauth_resource in config.toml, codex mcp login <server> builds an authorize URL containing the RFC 8707 resource query parameter twice. OAuth providers that strictly validate the authorize request parse the duplicated param as an array and reject the request. Amplitude's hosted MCP (https://mcp.amplitude.com/mcp) fails like this:

OAuth provider returned `invalid_request`: [
  {
    "expected": "string",
    "code": "invalid_type",
    "path": [
      "resource"
    ],
    "message": "Invalid input: expected string, received array"
  }
]

Providers that tolerate duplicate query params (Notion, Asana, Linear) happen to work, which masks the bug.

Repro

~/.codex/config.toml:

[mcp_servers.amplitude]
url = "https://mcp.amplitude.com/mcp"
oauth_resource = "https://mcp.amplitude.com/mcp"

Run codex mcp login amplitude → browser lands on the invalid_request error above instead of the consent page.

Removing the oauth_resource line works around it (login succeeds), confirming the config knob is the second source of the param.

Root cause

Two layers each append resource:

  1. rmcp 1.8.0 (pinned by codex-rs) already adds resource=<server base URL> when building the authorize URL: crates/rmcp/src/transport/auth.rs L1209 at rmcp-v1.8.0 (.add_extra_param("resource", self.base_url.to_string())).
  2. Codex then unconditionally appends resource=<oauth_resource> on top of the URL rmcp returned: codex-rs/rmcp-client/src/perform_oauth_login.rs L546-L550 at rust-v0.144.4.

Result: ...&resource=https%3A%2F%2Fmcp.amplitude.com%2Fmcp&resource=https%3A%2F%2Fmcp.amplitude.com%2Fmcp.

The oauth_resource knob predates rmcp's own RFC 8707 support (added for #13891 / #12589, when the param was omitted entirely), so on current versions it is purely duplicative when its value equals the server URL.

Suggested fix

In perform_oauth_login.rs, skip the append_query_param call when the authorize URL already contains a resource param (or replace rather than append). That keeps oauth_resource working as an override for gateways whose resource identifier differs from the server URL, without double-sending it.

Related

  • #33403 — the refresh-token path in rmcp 1.8.0 still omits resource, so strict providers also break at token refresh; both paths should end up sending it exactly once.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗