openai/codex · error · StartupOutcomeError

executor-owned MCP server `{server_name}` cannot use hosted

Error message

executor-owned MCP server `{server_name}` cannot use hosted ChatGPT authentication; configure executor-owned credentials instead

What it means

make_rmcp_client refuses to start a server configured with auth = "chatgpt" that runs in a non-local (executor-owned) environment and has no explicit HTTP Authorization header. Hosted ChatGPT credentials are bound to the host session and cannot be handed to a remote executor, so the combination is rejected at startup rather than failing authentication later with an opaque 401.

Source

Thrown at codex-rs/codex-mcp/src/rmcp_client.rs:1081

#[allow(clippy::too_many_arguments)]
#[instrument(level = "trace", skip_all, fields(server_name = %server_name))]
async fn make_rmcp_client(
    server_name: &str,
    server: EffectiveMcpServer,
    store_mode: OAuthCredentialsStoreMode,
    keyring_backend_kind: AuthKeyringBackendKind,
    runtime_context: McpRuntimeContext,
    resolved_environment: std::result::Result<Option<Arc<Environment>>, String>,
    runtime_auth_provider: Option<SharedAuthProvider>,
    protocol_mode: McpProtocolMode,
) -> Result<RmcpClient, StartupOutcomeError> {
    let config = server.config().clone();
    if matches!(config.auth, McpServerAuth::ChatGpt)
        && !config.is_local_environment()
        && !has_explicit_http_authorization(&config)
    {
        return Err(StartupOutcomeError::from(anyhow!(
            "executor-owned MCP server `{server_name}` cannot use hosted ChatGPT authentication; configure executor-owned credentials instead"
        )));
    }
    let resolved_environment =
        resolved_environment.map_err(|err| StartupOutcomeError::from(anyhow!(err)))?;
    let is_local_environment = config.is_local_environment();
    let oauth_credential_name = config.oauth_credential_name(server_name);
    let McpServerConfig { transport, .. } = config;

    match transport {
        McpServerTransportConfig::Stdio {
            command,
            args,
            env,
            env_vars,
            cwd,
        } => {
            let command_os: OsString = command.into();

View on GitHub (pinned to 339751715c)

Solutions

  1. Give the server executor-owned credentials: set bearer_token_env_var or an Authorization entry under http_headers/env_http_headers in its config
  2. Or run the server in the local environment (drop the remote environment setting) so hosted ChatGPT auth applies
  3. Or switch to an OAuth credential the executor can obtain itself (oauth_credential_name)

Example fix

# before: ChatGPT-hosted auth on a remote executor
[mcp_servers.foo]
url = "https://foo.example/mcp"
auth = "chatgpt"

# after: executor-owned credential
[mcp_servers.foo]
url = "https://foo.example/mcp"
bearer_token_env_var = "FOO_MCP_TOKEN"
Defensive patterns

Strategy: validation

Validate before calling

// Reject auth/environment combos make_rmcp_client will refuse
fn will_fail_auth_check(cfg: &McpServerConfig) -> bool {
    matches!(cfg.auth, McpServerAuth::ChatGpt)
        && !cfg.is_local_environment()
        && !has_explicit_http_authorization(cfg)
}

Prevention

When it happens

Trigger: An MCP server entry with McpServerAuth::ChatGpt whose effective environment is remote/executor-owned (cloud execution, exec-server on another machine) and no Authorization entry under http_headers/env_http_headers and no bearer token: for example promoting a working local ChatGPT-auth MCP server to a cloud executor without changing its auth.

Common situations: Enterprise rollouts moving MCP execution to remote environments; app-server connected to an exec-server on a different OS; default auth left on 'chatgpt' when the server moved off the local environment.

Understand the failure class

Related errors


AI-assisted analysis of openai/codex@339751715c (2026-08-25). Data as JSON: /api/errors/07e5881cffa76b4d. Report an issue: GitHub.