Skip to content

Expose create_mcp_http_client and McpHttpClientFactory as public API (2.0 made them private-only) #3238

Description

@ProgrammerPlus1998

Summary

Customizing the HTTP client for streamable_http_client (custom headers, auth, timeout, proxy, etc.) is a common and legitimate need, but as of 2.0.0 the only supported way to build a conforming client is through helpers that live in the private module mcp.shared._httpx_utils. Users are therefore forced to depend on a private API.

What changed in 2.0

In 1.x, streamable_http_client accepted convenience kwargs directly:

streamable_http_client(url, headers=..., timeout=..., sse_read_timeout=..., auth=...)

2.0 (via #2972, which replaced httpx/httpx-sse with httpx2) removed those kwargs. The signature is now:

async def streamable_http_client(
    url: str,
    *,
    http_client: httpx2.AsyncClient | None = None,
    terminate_on_close: bool = True,
) -> ...

So the only way to pass custom headers/auth/timeout is to build an httpx2.AsyncClient yourself and pass it as http_client=. The standardized factory for doing so is create_mcp_http_client — but it is only available at the private path:

from mcp.shared._httpx_utils import create_mcp_http_client  # private module

The same applies to McpHttpClientFactory: in 1.x it was importable from the public mcp.client.streamable_http, but in 2.0 it is defined in mcp.shared._httpx_utils and is no longer re-exported from any public module.

Why this is a problem

  • "Connect to an MCP server that requires auth headers / a custom timeout / a proxy" is a standard use case, not an edge case.
  • The leading underscore on mcp.shared._httpx_utils signals "private, may change without notice", so every downstream project that needs a custom client has to take on that fragility.
  • It's inconsistent: the consumption side (streamable_http_client(url, http_client=...)) is public, but the construction side (create_mcp_http_client, McpHttpClientFactory) is private.

Suggestion

Re-export create_mcp_http_client and McpHttpClientFactory from a public module — e.g. mcp.client.streamable_http (where McpHttpClientFactory used to live) or mcp.shared — so building a custom HTTP client does not require importing a private module.

(Related: because the HTTP layer now uses httpx2, a short note in the migration docs on how to build/pass a custom http_client would also help.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions