Skip to content

bug: --enable-proxy broken on Node.js 22+ — globalThis.fetch bypasses proxy dispatcher #281

Description

@fqx

Summary

--enable-proxy calls setGlobalDispatcher(new EnvHttpProxyAgent()) but this only affects the npm-installed undici instance. On Node.js 22+, globalThis.fetch uses the Node.js built-in undici — a separate instance that is unaffected by setGlobalDispatcher from an npm package.

StreamableHTTPClientTransport.send() (from @modelcontextprotocol/sdk) falls back to globalThis.fetch when no custom fetch is injected:

const response = await (this._fetch ?? fetch)(this._url, init)

So even with --enable-proxy set, all HTTP requests go through the unproxied built-in fetch.

Symptom

The server is reachable through the proxy (no timeout), but the response is missing the Content-Type header because the direct connection hits an unexpected path. mcp-remote throws:

StreamableHTTPError: Streamable HTTP error: Unexpected content type: null

Environment

  • Node.js v22+ (tested on v26.0.0)
  • OS: macOS with Surge HTTP proxy on 127.0.0.1:6152
  • mcp-remote: 0.1.38
  • Config: HTTPS_PROXY=http://127.0.0.1:6152 + --enable-proxy

Reproducer

const { fetch: undici_fetch, EnvHttpProxyAgent, setGlobalDispatcher } = require('undici')
setGlobalDispatcher(new EnvHttpProxyAgent())

// undici fetch correctly uses the proxy:
undici_fetch(url, opts).then(r => console.log(r.headers.get('content-type')))  // ✅ text/event-stream

// globalThis.fetch does NOT — still uses built-in Node.js undici:
globalThis.fetch(url, opts).then(r => console.log(r.headers.get('content-type')))  // ❌ null

Fix

After configuring the dispatcher, also replace globalThis.fetch with undici's fetch:

  if (enableProxy) {
    setGlobalDispatcher(new EnvHttpProxyAgent())
+   globalThis.fetch = fetch as typeof globalThis.fetch
    log('HTTP proxy support enabled ...')
  }

fetch is already imported from undici at the top of utils.ts, so this is a one-line fix.

PR with fix and tests: #280

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions