feat(mcp): honor HTTP(S)_PROXY env vars on MCP HTTP transport (#1408)

`reqwest 0.13` does not auto-detect proxy env vars by default, so MCP
HTTP connections were bypassing the proxy that every other tool on
the user's box (curl, npm, git, …) was using. Users behind corporate
egress proxies and China-mainland setups routing through a local
Clash / Shadowsocks tunnel had their MCP servers fail to connect or
silently leak around the tunnel.

When the `MCP HTTP transport client builder` runs, we now read
`HTTPS_PROXY` / `https_proxy` / `HTTP_PROXY` / `http_proxy` (first
non-empty wins) and route via `reqwest::Proxy::all(...)`. `NO_PROXY`
is honored via `reqwest::NoProxy::from_env()`. Malformed proxy URLs
log a `tracing::warn!` (no scroll-demon leak — see runtime_log) and
the connection proceeds without a proxy rather than failing the
whole MCP attach.

Closes #1408. Thanks @hlx98007 for the report.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Hunter Bown
2026-05-10 20:58:33 -05:00
parent 6d099d425c
commit 865db62487
+33 -3
View File
@@ -934,9 +934,39 @@ impl McpConnection {
}
}
}
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(connect_timeout_secs))
.build()?;
// Honor the standard `HTTP_PROXY` / `HTTPS_PROXY` (and their
// lowercase equivalents) plus `NO_PROXY` env vars when
// reaching MCP HTTP servers (#1408). Reqwest 0.13 does not
// auto-detect these by default, so users behind corporate
// proxies, on China-mainland connections routing through a
// local Clash / Shadowsocks tunnel, etc. previously had MCP
// HTTP traffic bypass the proxy entirely while every other
// tool on the box (curl, npm, …) used it.
let mut client_builder =
reqwest::Client::builder().timeout(Duration::from_secs(connect_timeout_secs));
let env_proxy_url = std::env::var("HTTPS_PROXY")
.or_else(|_| std::env::var("https_proxy"))
.or_else(|_| std::env::var("HTTP_PROXY"))
.or_else(|_| std::env::var("http_proxy"))
.ok()
.filter(|s| !s.trim().is_empty());
if let Some(proxy_url) = env_proxy_url {
match reqwest::Proxy::all(&proxy_url) {
Ok(proxy) => {
let proxy = proxy.no_proxy(reqwest::NoProxy::from_env());
client_builder = client_builder.proxy(proxy);
}
Err(err) => {
tracing::warn!(
target: "mcp",
?err,
proxy = %proxy_url,
"ignoring malformed HTTP(S)_PROXY env var; MCP connection will bypass proxy"
);
}
}
}
let client = client_builder.build()?;
Box::new(HttpTransport::new(
client,
url.clone(),