openai/codex · error

Environment variable {env_var} for MCP server '{server_name}

Error message

Environment variable {env_var} for MCP server '{server_name}' is empty

What it means

Thrown while starting an MCP server whose config declares bearer_token_env_var for the streamable-http transport. resolve_bearer_token found the variable in the process environment, but its value is the empty string. An empty Bearer credential can never authenticate, so Codex fails the server at startup instead of sending a guaranteed-401 request later.

Source

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

    }
}

fn is_untrusted_connector_meta_key(key: &str) -> bool {
    UNTRUSTED_CONNECTOR_META_KEYS.contains(&key)
}

fn resolve_bearer_token(
    server_name: &str,
    bearer_token_env_var: Option<&str>,
) -> Result<Option<String>> {
    let Some(env_var) = bearer_token_env_var else {
        return Ok(None);
    };

    match env::var(env_var) {
        Ok(value) => {
            if value.is_empty() {
                Err(anyhow!(
                    "Environment variable {env_var} for MCP server '{server_name}' is empty"
                ))
            } else {
                Ok(Some(value))
            }
        }
        Err(env::VarError::NotPresent) => Err(anyhow!(
            "Environment variable {env_var} for MCP server '{server_name}' is not set"
        )),
        Err(env::VarError::NotUnicode(_)) => Err(anyhow!(
            "Environment variable {env_var} for MCP server '{server_name}' contains invalid Unicode"
        )),
    }
}

fn validate_mcp_server_name(server_name: &str) -> Result<()> {
    let re = regex_lite::Regex::new(r"^[a-zA-Z0-9_-]+$")?;
    if !re.is_match(server_name) {

View on GitHub (pinned to 339751715c)

Solutions

  1. Export a real value: FOO_TOKEN=<actual-token> codex (or put it in the shell profile / .env the launcher reads) and restart so the MCP server retries startup
  2. Grep launch files for an empty assignment: grep -rn 'FOO_TOKEN=$' ~/.bashrc .env docker-compose.yml, and fill in the value
  3. If this server does not use bearer auth, delete bearer_token_env_var from its [mcp_servers.NAME] entry
  4. If the token should come from the remote executor, configure it in the executor environment (which must advertise http_header_env_vars) instead of the local one

Example fix

# before (.env)
FOO_TOKEN=

# after
FOO_TOKEN=ghp_0123456789abcdef
Defensive patterns

Strategy: validation

Validate before calling

#!/usr/bin/env bash
# Fail fast before Codex ever starts the MCP server
: "${FOO_TOKEN:?FOO_TOKEN must be set and non-empty for MCP server 'foo'}"
if [ -z "$FOO_TOKEN" ]; then echo "FOO_TOKEN is empty" >&2; exit 1; fi
exec codex "$@"

Try / catch

let token = resolve_bearer_token(server, bearer_env).map_err(StartupOutcomeError::from);
if let Err(err) = &token {
    if err.to_string().contains("is empty") {
        // env var exists but holds "" - surface a 'set the secret' setup message
    }
}

Prevention

When it happens

Trigger: config.toml contains [mcp_servers.NAME] with streamable_http transport and bearer_token_env_var = "FOO_TOKEN", and the process launching Codex exports FOO_TOKEN as empty (FOO_TOKEN= codex, an .env line 'FOO_TOKEN=', a CI secret defined but unset, docker-compose '- FOO_TOKEN='). Hit only when the token is resolved host-side, i.e. the server runs in the local environment or the executor does not advertise http_header_env_vars.

Common situations: CI pipeline references a secret never configured on the runner; compose/direnv files with a trailing '=' and no value; a secret-name typo so the platform injects an empty placeholder; a login script that exports the variable before fetching the token.

Related errors


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