Remote MCP: scopes_supported should be extracted from the protected resource metadata document
What version of Codex CLI is running?
0.116.0
What subscription do you have?
Enterprise
Which model were you using?
_No response_
What platform is your computer?
_No response_
What terminal emulator and version are you using (if applicable)?
_No response_
What issue are you seeing?
Hello team,
I believe there is an issue with https://github.com/openai/codex/pull/14419 as Codex extracts the scopes_supported value from the auth server metadata document (/.well-known/oauth-authorization-server) instead of the protected resource one (/.well-known/oauth-protected-resource).
The MCP specification states the following:
If scope is not available, use all scopes defined in scopes_supported from the Protected Resource Metadata document, omitting the scope parameter if scopes_supported is undefined.
I am currently developing an MCP server and was testing the DCR flow with the Codex CLI. With this bug, the Codex MCP client is ignoring the scopes I am defining in /.well-known/oauth-protected-resource and thus creates an OAuth app with the wrong scopes.
What steps can reproduce the bug?
Define scopes_supported in /.well-known/oauth-protected-resource
What is the expected behavior?
scopes_supported is extracted from /.well-known/oauth-protected-resource
Additional information
_No response_
7 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
I traced this to the scope discovery added in #14419.
Right now
codex-rs/rmcp-client/src/auth_status.rsonly fetches/.well-known/oauth-authorization-server...and readsscopes_supportedfrom that response. That value is then threaded throughcodex-rs/core/src/mcp/auth.rsasdiscovered_scopesand used for login when there are no explicit/configured scopes.I do not see any corresponding read of
/.well-known/oauth-protected-resourceforscopes_supported, so this matches the behavior reported here.The smallest fix looks like:
authorization_endpoint/token_endpointscopes_supportedfrom the protected-resource metadata document insteadHi! I had a similar issue for our MCP where authorization server and the MCP server itself are two different (independent) hosts. I have fixed and tested it locally, by updating rmcp to
1.3and adjusting the auth logic. It's not a log of changes that are required and I would be happy to open a pull request(s) if given the option.I reproduced this against current
mainand prepared a small contributor-grade fix here:Repro:
scopes_supported, but whose authorization server metadata omits it.mainfails to surface the protected-resource scopes because discovery only readsscopes_supportedfrom the authorization server metadata path.Root cause:
codex-rs/rmcp-client/src/auth_status.rsonly pullsscopes_supportedfrom OAuth Authorization Server Metadata. The MCP auth guidance expects clients to use the Protected Resource Metadata document for that field when scope support is advertised there.Approaches considered:
scopes_supportedthrough the existing auth-server-only discovery path by adding fallback logic in place.I chose the second option because it keeps the spec boundary explicit, stays small, and avoids further overloading the authorization-server metadata helper.
Fix summary:
/.well-known/oauth-protected-resource/...with root fallback)scopes_supportedfrom protected-resource metadata when presentValidation:
cargo test -p codex-rmcp-client streamable_http_oauth_discovery_prefers_protected_resource_scopes_without_fallback -- --nocapturecargo test -p codex-rmcp-client streamable_http_oauth_discovery_omits_scopes_when_protected_resource_metadata_has_none -- --nocapturecargo test -p codex-rmcp-client protected_resource_metadata_paths_try_endpoint_path_before_root -- --nocapturecargo fmt --check -p codex-rmcp-clientgit diff --checkLocal limitation in this sandbox: the existing live HTTP-backed tests try to bind
127.0.0.1, which is blocked here (Operation not permitted), so I added the integration-style cases but could not execute those network-bound tests locally in this run.If this direction looks right and you want an invited PR, I can open/retarget it quickly.
I can reproduce the same issue on Codex 0.147.0.
Before on 0.141.0 I was able to work around this by using
codex mcp login <name> --scopes openid,profile,email,offline_accessHowever, in newer versions the OAuth flow starts automatically as part of
codex mcp add --url ..., andmcp adddoes not provide an option to specify the scopes used for that OAuth flow.Because Codex currently ignores
scopes_supportedfrom the protected-resource metadata and instead requests all scopes advertised by the authorization server, the automatic login fails withinvalid_scope. As far as I can tell, there is also no option to add the remote MCP server without immediately starting the OAuth flow, so I currently have to fall back to Codex 0.141.0 in order to use themcp login --scopes ...workaround.I also need the functionallity that FoROzX mentioned. And have the same use case. When do we get that fix? :)
Additional confirmation on
codex-cli 0.147.0. All hostnames, client names, and non-standard scope names below are intentionally sanitized.This also reproduces during
codex mcp loginwith an existing OAuth client, so a DCR failure is not required to trigger the bug.Sanitized setup
Protected Resource Metadata advertises only resource-specific scopes:
The shared authorization server's global OIDC metadata advertises those scopes plus unrelated scopes used by other applications:
The OAuth client is intentionally not allowed to request
unrelated_client_scope.Actual behavior
Running:
causes the first authorization request to contain the authorization server's global scope catalog, including
unrelated_client_scope, instead of the Protected Resource Metadata list. The provider rejects that request withinvalid_scope, after which Codex prints:The second authorization request omits
scopeentirely and login reports success.The resulting stored credential contains only the provider's default scopes (for example,
emailandprofile), notoffline_access. Consequently, it receives a normal short-lived refresh token rather than an offline credential. After that refresh token expires, a later Codex process fails during MCP startup with:This makes the fallback look successful while causing repeated interactive reauthentication later.
Control checks
client_id.codex mcp login --scopes ...avoids requesting the unrelated global scope and is a workable manual mitigation where that command path is available.Expected behavior
Codex should use
scopes_supportedfrom Protected Resource Metadata and should not replace it with the authorization server's global scope catalog. This also matches the current Codex documentation:https://learn.chatgpt.com/docs/extend/mcp?surface=cli#other-configuration-options
The retry-without-scopes path compounds the original discovery bug by silently discarding
offline_access; avoiding the incorrect global scope set prevents that fallback and the later refresh-token failure.