modelcontextprotocol / modelcontextprotocol/python-sdk

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

Open Beginner friendly
#3,238 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

P1 v2
Dominant language
Python
Stars
24.3k
Forks
4k
Avg merge
1d 1h
Merged PRs (30d)
31

Description

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.)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by inspecting mcp/shared/_httpx_utils.py and mcp/client/streamable_http.py to compare the current definitions and public exports. Re-export create_mcp_http_client and McpHttpClientFactory from a public module, and consider the migration documentation note mentioned in the issue. Done means users can construct and pass a custom client without importing the private module.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
api
Issue type
Feature
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.