openai/codex · error

MCP HTTP headers helper returned a reserved header

Error message

MCP HTTP headers helper returned a reserved header

What it means

The helper may not supply headers the adapter owns: accept, authorization, connection, content-encoding, content-length, content-type, host, keep-alive, last-event-id, mcp-protocol-version, mcp-session-id, origin, proxy-connection, referer, te, trailer, transfer-encoding, upgrade. Protocol framing and auth (bearer/OAuth) are managed by the client itself, so helper-supplied values for these names are rejected outright to avoid spoofing or corrupting protocol state.

Source

Thrown at codex-rs/rmcp-client/src/http_headers.rs:391

                | "authorization"
                | "connection"
                | "content-encoding"
                | "content-length"
                | "content-type"
                | "host"
                | "keep-alive"
                | "last-event-id"
                | "mcp-protocol-version"
                | "mcp-session-id"
                | "origin"
                | "proxy-connection"
                | "referer"
                | "te"
                | "trailer"
                | "transfer-encoding"
                | "upgrade"
        ) {
            return Err(anyhow!(
                "MCP HTTP headers helper returned a reserved header"
            ));
        }
        if parsed.contains_key(&name) {
            return Err(anyhow!(
                "MCP HTTP headers helper returned duplicate header names"
            ));
        }
        let value = HeaderValue::from_str(&value)
            .map_err(|_| anyhow!("MCP HTTP headers helper returned an invalid header value"))?;
        parsed.insert(name, value);
    }
    Ok(parsed)
}

#[cfg(test)]
#[path = "http_headers_tests.rs"]
mod tests;

View on GitHub (pinned to 339751715c)

Solutions

  1. Remove all reserved names from the helper output; keep only genuinely custom headers (e.g. X-Api-Key, X-Org-Id)
  2. Supply auth through the client's configured headers/OAuth flow instead of the helper
  3. If you need a proxy auth header, use Proxy-Authorization (explicitly allowed for IAP-style setups)
  4. Add a filter step in the helper that drops the reserved set before printing

Example fix

# before
{"Authorization":"Bearer eyJ...","X-Api-Key":"k"}

# after
{"X-Api-Key":"k"}   # Authorization is managed by OAuth/bearer config
Defensive patterns

Strategy: validation

Validate before calling

# Fail if the helper output contains any reserved header name
RESERVED="accept authorization connection content-encoding content-length content-type host keep-alive last-event-id mcp-protocol-version mcp-session-id origin proxy-connection referer te trailer transfer-encoding upgrade"
cd "$MCP_CWD" && env -i PATH=/usr/bin:/bin sh -c "$HTTP_HEADERS_HELPER" \
  | jq -r 'keys[] | ascii_downcase' | while IFS= read -r name; do
      case " $RESERVED " in *" $name "*) echo "reserved: $name";; esac
  done

Type guard

const RESERVED: &[&str] = &["accept","authorization","connection","content-encoding","content-length","content-type","host","keep-alive","last-event-id","mcp-protocol-version","mcp-session-id","origin","proxy-connection","referer","te","trailer","transfer-encoding","upgrade"];

fn is_reserved_header(name: &str) -> bool {
    RESERVED.contains(&name.to_ascii_lowercase().as_str())
}

Prevention

When it happens

Trigger: Helper JSON including Authorization (owned by bearer/OAuth), Accept or Content-Type (set per MCP request), Mcp-Session-Id / Mcp-Protocol-Version, or hop-by-hop headers like Connection, Transfer-Encoding, Upgrade.

Common situations: Credential helpers that naturally want to set Authorization; helpers forwarding a captured browser request's headers wholesale; gateway auth schemes that reuse protocol header names.

Related errors


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