Files
codex/codex-rs/codex-mcp/src/executor_environment_http_client.rs
jif 93c54bca38 Resolve HTTP MCP bearer tokens in executor environments (#39926)
## Why

Executor-owned HTTP MCP servers need to read their bearer credentials from the
selected executor environment instead of the host process.

## What changed

- Preserve `bearer_token_env_var` for executor-owned HTTP MCP configurations and
  resolve it when the executor sends each request.
- Extend delegated HTTP headers with executor-local environment references while
  rejecting missing, empty, or protected credential variables.
- Keep transport-provided bearer authentication compatible with MCP redirect and
  OAuth handling without sending a placeholder authorization value.

## Testing

- Cover authenticated executor-owned MCP requests end to end.
- Cover delegated header resolution and rejection of protected variables.
- Cover parsing executor-owned bearer configuration and transport-provided bearer
  behavior.

GitOrigin-RevId: 442bf7382198ffb69eba797eb36d4c74faabda88
2026-08-21 12:50:15 +00:00

46 lines
1.4 KiB
Rust

use std::sync::Arc;
use codex_exec_server::ExecServerError;
use codex_exec_server::HttpClient;
use codex_exec_server::HttpHeader;
use codex_exec_server::HttpRequestParams;
use codex_exec_server::HttpRequestResponse;
use codex_exec_server::HttpResponseBodyStream;
use futures::future::BoxFuture;
pub(crate) struct ExecutorEnvironmentHttpClient {
pub(crate) bearer_token_env_var: String,
pub(crate) http_client: Arc<dyn HttpClient>,
}
impl ExecutorEnvironmentHttpClient {
fn attach_authorization(&self, params: &mut HttpRequestParams) {
params
.headers
.retain(|header| !header.name.eq_ignore_ascii_case("authorization"));
params.headers.push(HttpHeader {
name: "authorization".to_string(),
value: "Bearer ".to_string(),
value_env_var: Some(self.bearer_token_env_var.clone()),
});
}
}
impl HttpClient for ExecutorEnvironmentHttpClient {
fn http_request(
&self,
mut params: HttpRequestParams,
) -> BoxFuture<'_, Result<HttpRequestResponse, ExecServerError>> {
self.attach_authorization(&mut params);
self.http_client.http_request(params)
}
fn http_request_stream(
&self,
mut params: HttpRequestParams,
) -> BoxFuture<'_, Result<(HttpRequestResponse, HttpResponseBodyStream), ExecServerError>> {
self.attach_authorization(&mut params);
self.http_client.http_request_stream(params)
}
}