Allow ChatGPT-hosted MCP servers to use session auth (#29733)

## Why

ChatGPT session authentication was inferred from the reserved Codex Apps
server name. That couples credential routing to Codex Apps-specific
behavior and prevents other MCP endpoints hosted by ChatGPT from
explicitly using the current session.

The opt-in also needs a clear security boundary: an arbitrary MCP
configuration must not be able to redirect ChatGPT credentials to
another origin.

## What changed

- Add `use_chatgpt_auth` to HTTP MCP server configuration, defaulting to
`false`.
- Honor the setting only when the parsed server URL has the same HTTP(S)
origin as the configured `chatgpt_base_url`; otherwise remove the
capability before startup.
- Resolve bearer tokens and static or environment-backed authorization
headers before selecting authentication, with configured authorization
taking precedence over ChatGPT session auth.
- Enable the setting for the built-in Codex Apps and hosted plugin
runtime endpoints while keeping Codex Apps caching and tool
normalization scoped to the reserved server.
- Persist the setting through MCP config rewrite paths and expose it in
the generated config schema.
- Load the current login state for `codex mcp list` so reported auth
status matches runtime behavior.

## Verification

Core integration coverage exercises the complete streamable HTTP MCP
startup path and verifies that:

- a same-origin opted-in server receives the current ChatGPT access
token;
- an explicitly configured authorization header takes precedence;
- a different-origin server completes MCP initialization and tool
listing without receiving any ChatGPT authorization header.
This commit is contained in:
Ahmed Ibrahim
2026-06-24 19:21:28 -07:00
committed by GitHub
Unverified
parent a0d5fd772e
commit 4c0706e24a
29 changed files with 313 additions and 59 deletions
+7 -2
View File
@@ -18,6 +18,7 @@ use codex_core::config::edit::ConfigEditsBuilder;
use codex_core::config::find_codex_home;
use codex_core::config::load_global_mcp_servers;
use codex_core_plugins::PluginsManager;
use codex_login::AuthManager;
use codex_mcp::McpOAuthLoginSupport;
use codex_mcp::ResolvedMcpOAuthScopes;
use codex_mcp::compute_auth_statuses;
@@ -344,6 +345,7 @@ async fn run_add(config_overrides: &CliConfigOverrides, add_args: AddArgs) -> Re
};
let new_entry = McpServerConfig {
use_chatgpt_auth: false,
transport: transport.clone(),
environment_id: codex_config::DEFAULT_MCP_SERVER_ENVIRONMENT_ID.to_string(),
enabled: true,
@@ -543,8 +545,11 @@ async fn run_list(config_overrides: &CliConfigOverrides, list_args: ListArgs) ->
let mcp_manager = McpManager::new(Arc::new(PluginsManager::new(
config.codex_home.to_path_buf(),
)));
let auth_manager =
AuthManager::shared_from_config(&config, /*enable_codex_api_key_env*/ true).await;
let auth = auth_manager.auth().await;
let mcp_servers = mcp_manager.configured_servers(&config).await;
let effective_mcp_servers = mcp_manager.effective_servers(&config, /*auth*/ None).await;
let effective_mcp_servers = mcp_manager.effective_servers(&config, auth.as_ref()).await;
let mut entries: Vec<_> = mcp_servers.iter().collect();
entries.sort_by_key(|(name, _)| *name);
@@ -552,7 +557,7 @@ async fn run_list(config_overrides: &CliConfigOverrides, list_args: ListArgs) ->
effective_mcp_servers.iter(),
config.mcp_oauth_credentials_store_mode,
config.auth_keyring_backend_kind(),
/*auth*/ None,
auth.as_ref(),
)
.await;