Skip to content

feat: honor HTTP_PROXY/HTTPS_PROXY/NO_PROXY for all outbound traffic#487

Merged
RealKai42 merged 7 commits into
mainfrom
feat/http-proxy
Jun 5, 2026
Merged

feat: honor HTTP_PROXY/HTTPS_PROXY/NO_PROXY for all outbound traffic#487
RealKai42 merged 7 commits into
mainfrom
feat/http-proxy

Conversation

@RealKai42
Copy link
Copy Markdown
Collaborator

Problem

Kimi Code makes all outbound HTTP(S) requests through Node's built-in fetch,
which does not honor the standard HTTP_PROXY / HTTPS_PROXY / NO_PROXY
environment variables. Users behind a corporate or local proxy had no way to
route the CLI's traffic — model API calls, MCP servers, web tools, telemetry,
sign-in, and update checks — through it.

What changed

Honor the standard proxy environment variables for all outbound HTTP(S)
traffic, applied only when a proxy variable is set (the zero-config default is
unchanged):

  • In-process traffic: install a global undici dispatcher
    (EnvHttpProxyAgent) once at CLI startup, before any client is constructed.
    Every egress point resolves to global fetch (LLM SDKs, MCP HTTP, web tools,
    telemetry, OAuth, update checks, downloads), so this single hook covers them
    all. Adds undici as an agent-core dependency (Node does not expose its
    bundled undici as an importable module).
  • Spawned children: stdio MCP servers run as separate Node processes that
    do not inherit the in-process dispatcher, so mergeStdioEnv propagates
    NODE_USE_ENV_PROXY=1 and a loopback-protected NO_PROXY, letting them honor
    the proxy natively without bundling undici.
  • Loopback safety: localhost, 127.0.0.1, ::1 are always added to
    NO_PROXY so a local server (e.g. a localhost MCP server) keeps working when
    a proxy is set. The * wildcard (bypass everything) is preserved verbatim.
  • Robustness: an invalid proxy URL is reported and ignored (connects
    directly) rather than aborting startup.

Tests: 17 unit tests for the pure proxy helpers — detection, NO_PROXY
resolution (including the * wildcard and the blank-lowercase fallthrough),
dispatcher creation, child-env propagation, and invalid-URL handling.
Docs updated in both languages (docs/{en,zh}/configuration/env-vars.md).

Install a global undici dispatcher at CLI startup so every in-process fetch
(LLM APIs, MCP HTTP, web tools, telemetry, sign-in, update checks) honors the
standard proxy variables, and propagate NODE_USE_ENV_PROXY to spawned stdio
MCP child processes. Loopback hosts always bypass the proxy; an invalid proxy
URL is reported and ignored rather than aborting startup.
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Jun 5, 2026

🦋 Changeset detected

Latest commit: 6cf1d3c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 5 packages
Name Type
@moonshot-ai/agent-core Minor
@moonshot-ai/kimi-code-sdk Minor
@moonshot-ai/kimi-code Minor
@moonshot-ai/acp-adapter Patch
@moonshot-ai/migration-legacy Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Jun 5, 2026

pnpm dlx https://pkg.pr.new/@moonshot-ai/kimi-code@6cf1d3c
npx https://pkg.pr.new/@moonshot-ai/kimi-code@6cf1d3c

commit: 6cf1d3c

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 5, 2026

❌ Nix build failed

Hash mismatch in pnpmDeps:

Hash
specified sha256-/Kgq76JAgi1NygbnYkBNACUl+U9TO5zwF1MaCzk3n9o=
got sha256-x5O/+bDRoEW3juoxe3XyvTJxHitQ0hZ2nVXBItkBA5E=

Please update flake.nix with the got hash.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bfee8b93d8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/agent-core/src/utils/proxy.ts Outdated
Comment thread packages/agent-core/src/mcp/client-stdio.ts Outdated

// Process-wide HTTP proxy bootstrap — installed once at CLI startup so all
// outbound fetch honors HTTP_PROXY / HTTPS_PROXY / NO_PROXY.
export { installGlobalProxyDispatcher } from '@moonshot-ai/agent-core';
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep undici out of the public SDK surface

Re-exporting installGlobalProxyDispatcher from the public SDK also exposes its optional deps parameter type, which depends on undici's Dispatcher type from packages/agent-core/src/utils/proxy.ts. Because @moonshot-ai/kimi-code-sdk does not list undici as a dependency, consumers of the published SDK can get missing-module type resolution errors just by importing the package declarations; either hide the undici-typed injection surface from the SDK export or add the dependency where the public package exposes it.

Useful? React with 👍 / 👎.

Recognize SOCKS proxies (socks5/socks5h/socks4/socks alias) from ALL_PROXY or a
socks-scheme HTTP(S)_PROXY, routing traffic through a custom undici connector
backed by the socks client (reusing undici's own TLS handling for https).
HTTP(S) proxies keep precedence; NO_PROXY and loopback are honored for the SOCKS
path too. Child stdio MCP node processes honor HTTP(S) proxies via
NODE_USE_ENV_PROXY; SOCKS applies to the main process only.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ed46887703

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/agent-core/src/utils/proxy.ts
Comment thread packages/agent-core/src/utils/proxy.ts Outdated
Comment thread packages/agent-core/src/mcp/client-stdio.ts Outdated
…hash)

- Resolve HTTP(S)_PROXY explicitly via the first non-blank casing so a blank
  lowercase var can no longer mask a populated uppercase one (the dispatcher
  installed but went direct), and coerce a SOCKS-scheme value sitting in an
  HTTP(S) var to '' so it is never handed to EnvHttpProxyAgent.
- Reconcile a child's NO_PROXY override across both casings using the first
  non-blank value run through resolveNoProxy, so a per-server config override
  is not shadowed by the injected lowercase value, keeps the loopback bypass,
  and passes '*' through verbatim.
- Update flake.nix pnpmDeps hash for the added socks/undici dependencies.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e30eb8919b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/agent-core/src/utils/proxy.ts Outdated
Comment thread packages/agent-core/src/utils/proxy.ts Outdated
): Dispatcher | undefined {
const { makeHttpAgent = defaultMakeHttpAgent, makeSocksAgent = defaultMakeSocksAgent } = factories;
try {
if (hasHttpProxy(env)) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fall back to ALL_PROXY per missing scheme

When one scheme-specific HTTP proxy is set together with a SOCKS ALL_PROXY, this branch chooses the HTTP-agent path for the whole dispatcher and never evaluates the SOCKS fallback. For example, with HTTPS_PROXY=http://corp:3128 and ALL_PROXY=socks5://127.0.0.1:1080, pickHttpProxy() passes httpProxy: '', so undici sends http:// requests directly even though ALL_PROXY is documented as the fallback when the scheme-specific variable is unset. Preserve the ALL_PROXY fallback for schemes that do not have an HTTP(S) proxy value.

Useful? React with 👍 / 👎.

Comment thread packages/agent-core/src/mcp/client-stdio.ts Outdated
Comment thread packages/agent-core/src/utils/proxy.ts Outdated
… child Node version

- Honor an http-scheme ALL_PROXY as the catch-all fallback for both http and
  https (scheme-specific HTTP(S)_PROXY still wins), so an ALL_PROXY-only setup
  no longer installs a no-op dispatcher and connects direct.
- Make the SOCKS-path NO_PROXY matcher port-aware: a `host:port` entry now
  matches only that port (with IPv6-safe parsing for `::1` / `[::1]:443`).
- Document that child stdio MCP proxying via NODE_USE_ENV_PROXY only applies on
  Node versions that support it (>= 22.21 / >= 24.5).
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6b4e094712

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/agent-core/src/utils/proxy.ts Outdated
- Strip IPv6 brackets from a SOCKS proxy host (e.g. ALL_PROXY=socks5://[::1]:1080)
  so the socks client connects to the bare address.
- Add the bracketed [::1] to the loopback bypass: undici's EnvHttpProxyAgent
  only exempts IPv6 loopback when the NO_PROXY entry is bracketed (it mis-parses
  bare ::1). The SOCKS-path matcher normalizes brackets on both sides.
- Match *.domain wildcard (and host:port) NO_PROXY entries in the SOCKS matcher.
- Compute the child stdio proxy env from the MERGED env so a proxy declared only
  in a server's config.env also enables NODE_USE_ENV_PROXY.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 72cf98e0f9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

import {
createKimiHarness,
flushDiagnosticLogs,
installGlobalProxyDispatcher,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Bundle or declare the proxy runtime packages

In the packaged CLI, this new SDK import pulls in packages/agent-core/src/utils/proxy.ts, which statically imports undici and socks. I checked apps/kimi-code/tsdown.config.ts: only @moonshot-ai/* packages are forced into the bundle, so those third-party imports are left as runtime dependencies, but apps/kimi-code/package.json does not declare either package. A fresh npm install of @moonshot-ai/kimi-code would therefore fail to load dist/main.mjs before startup whenever Node cannot resolve those packages; add them to the app package dependencies or force them into the CLI bundle.

Useful? React with 👍 / 👎.

if (value !== undefined) merged[key] = value;
}
if (configEnv !== undefined) Object.assign(merged, configEnv);
Object.assign(merged, proxyEnvForChild(merged));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve explicit child proxy opt-outs

When a stdio server config explicitly sets NODE_USE_ENV_PROXY: '0' to keep that child from using Node's native proxy support, this assignment runs after config.env is merged and rewrites the value back to 1 whenever any HTTP proxy variable is present. Node documents NODE_USE_ENV_PROXY=1 as the opt-in switch for env proxying, so this breaks the usual config.env override behavior for per-server opt-outs; only inject it when the merged env did not already set the variable.

Useful? React with 👍 / 👎.

Comment thread packages/agent-core/src/utils/proxy.ts Outdated
export function proxyEnvForChild(env: Env = process.env): Record<string, string> {
if (!hasHttpProxy(env)) return {};
const noProxy = resolveNoProxy(env);
return { NODE_USE_ENV_PROXY: '1', NO_PROXY: noProxy, no_proxy: noProxy };
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Mirror normalized child proxy values across casings

When the merged child env has a blank lowercase proxy and a populated uppercase one (for example http_proxy='' with HTTP_PROXY='http://corp:3128'), hasHttpProxy() enables native proxying but this returned env leaves the blank lowercase value in place. Node's Built-in Proxy Support docs state that http_proxy/https_proxy take precedence when both casings are set, so supported Node stdio servers still see no usable proxy and go direct; mirror the first non-blank proxy URL into both casings or remove the blank lowercase key before setting NODE_USE_ENV_PROXY.

Useful? React with 👍 / 👎.

proxyEnvForChild now hands spawned stdio MCP children the resolved
HTTP_PROXY/HTTPS_PROXY (in both casings), synthesizing them from an http-scheme
ALL_PROXY when no scheme-specific variable is set. Node's --use-env-proxy reads
HTTP_PROXY/HTTPS_PROXY (not ALL_PROXY), so an ALL_PROXY-only parent now proxies
the child consistently with the main process. Shared resolveHttpProxyUrls helper
is reused by createProxyDispatcher and proxyEnvForChild.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 54e97c083e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (value !== undefined) merged[key] = value;
}
if (configEnv !== undefined) Object.assign(merged, configEnv);
Object.assign(merged, proxyEnvForChild(merged));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve per-server proxy overrides across casing

When the parent env has a lowercase proxy (for example http_proxy=http://parent) and an MCP stdio server config overrides only the uppercase key (HTTP_PROXY=http://server), this post-merge proxyEnvForChild(merged) call resolves lowercase first and writes the parent value back to both casings. The spawned Node server then uses the parent proxy despite config.env being intended to override the inherited environment; normalize/mirror proxy overrides from config.env before this assignment, similar to the new NO_PROXY reconciliation.

Useful? React with 👍 / 👎.

if (!hasHttpProxy(env)) return {};
const noProxy = resolveNoProxy(env);
const result: Record<string, string> = {
NODE_USE_ENV_PROXY: '1',
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid claiming env proxy covers child fetch

For stdio MCP servers implemented with Node's global fetch on the repo's minimum Node 24.15.0, this env injection still does not proxy their outbound calls: fresh evidence beyond the earlier version note is that node --help documents --use-env-proxy as applying to "global HTTP/HTTPS clients", and a local Node 24.15.0 child with NODE_USE_ENV_PROXY=1 proxied http.get but global fetch went direct. Those MCP servers are common, so either avoid documenting/depending on automatic child proxying for fetch-based servers or inject a child-side undici dispatcher.

Useful? React with 👍 / 👎.

@RealKai42 RealKai42 merged commit 4d11394 into main Jun 5, 2026
8 checks passed
@RealKai42 RealKai42 deleted the feat/http-proxy branch June 5, 2026 17:44
@github-actions github-actions Bot mentioned this pull request Jun 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant