Skip to content

Commit 90c525d

Browse files
committed
Refactor ClientFactory to accept all httpx parameters via kwargs instead of a separate verify param.
1 parent 3c5f2da commit 90c525d

File tree

4 files changed

+25
-50
lines changed

4 files changed

+25
-50
lines changed

src/mcp/client/sse.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ async def sse_client(
2828
sse_read_timeout: float = 60 * 5,
2929
httpx_client_factory: McpHttpClientFactory = create_mcp_http_client,
3030
auth: httpx.Auth | None = None,
31-
verify: bool | None = None,
3231
):
3332
"""
3433
Client transport for SSE.
@@ -59,7 +58,6 @@ async def sse_client(
5958
headers=headers,
6059
timeout=httpx.Timeout(timeout, read=sse_read_timeout),
6160
auth=auth,
62-
verify=verify,
6361
) as client:
6462
async with aconnect_sse(
6563
client,

src/mcp/client/streamable_http.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,6 @@ async def streamablehttp_client(
448448
terminate_on_close: bool = True,
449449
httpx_client_factory: McpHttpClientFactory = create_mcp_http_client,
450450
auth: httpx.Auth | None = None,
451-
verify: bool | None = None,
452451
) -> AsyncGenerator[
453452
tuple[
454453
MemoryObjectReceiveStream[SessionMessage | Exception],
@@ -482,7 +481,6 @@ async def streamablehttp_client(
482481
headers=transport.request_headers,
483482
timeout=httpx.Timeout(transport.timeout, read=transport.sse_read_timeout),
484483
auth=transport.auth,
485-
verify=verify,
486484
) as client:
487485
# Define callbacks that need access to tg
488486
def start_get_stream() -> None:

src/mcp/shared/_httpx_utils.py

Lines changed: 24 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -8,34 +8,20 @@
88

99

1010
class McpHttpClientFactory(Protocol):
11-
def __call__(
12-
self,
13-
headers: dict[str, str] | None = None,
14-
timeout: httpx.Timeout | None = None,
15-
auth: httpx.Auth | None = None,
16-
verify: bool | None = None,
17-
) -> httpx.AsyncClient: ...
18-
19-
20-
def create_mcp_http_client(
21-
headers: dict[str, str] | None = None,
22-
timeout: httpx.Timeout | None = None,
23-
auth: httpx.Auth | None = None,
24-
verify: bool | None = None,
25-
) -> httpx.AsyncClient:
11+
def __call__(self, **kwargs: Any) -> httpx.AsyncClient: ...
12+
13+
14+
def create_mcp_http_client(**kwargs: Any) -> httpx.AsyncClient:
2615
"""Create a standardized httpx AsyncClient with MCP defaults.
2716
2817
This function provides common defaults used throughout the MCP codebase:
2918
- follow_redirects=True (always enabled)
3019
- Default timeout of 30 seconds if not specified
20+
- You can pass any keyword argument accepted by httpx.AsyncClient
3121
3222
Args:
33-
headers: Optional headers to include with all requests.
34-
timeout: Request timeout as httpx.Timeout object.
35-
Defaults to 30 seconds if not specified.
36-
auth: Optional authentication handler.
37-
verify: Either True to use default CA bundle, False to disable verification, or an instance of ssl.SSLContext.
38-
23+
Any keyword argument supported by httpx.AsyncClient (e.g. headers, timeout, auth, verify, proxies, etc).
24+
MCP defaults are applied unless overridden.
3925
4026
Returns:
4127
Configured httpx.AsyncClient instance with MCP defaults.
@@ -51,45 +37,38 @@ def create_mcp_http_client(
5137
5238
# With custom headers
5339
headers = {"Authorization": "Bearer token"}
54-
async with create_mcp_http_client(headers) as client:
40+
async with create_mcp_http_client(headers=headers) as client:
5541
response = await client.get("/endpoint")
5642
5743
# With both custom headers and timeout
5844
timeout = httpx.Timeout(60.0, read=300.0)
59-
async with create_mcp_http_client(headers, timeout) as client:
45+
async with create_mcp_http_client(headers=headers, timeout=timeout) as client:
6046
response = await client.get("/long-request")
6147
6248
# With authentication
6349
from httpx import BasicAuth
6450
auth = BasicAuth(username="user", password="pass")
65-
async with create_mcp_http_client(headers, timeout, auth) as client:
51+
async with create_mcp_http_client(headers=headers, timeout=timeout, auth=auth) as client:
6652
response = await client.get("/protected-endpoint")
6753
6854
# With SSL verification disabled
6955
async with create_mcp_http_client(verify=False) as client:
7056
response = await client.get("/insecure-endpoint")
57+
58+
# With custom SSL context
59+
import ssl
60+
ssl_ctx = ssl.create_default_context()
61+
async with create_mcp_http_client(verify=ssl_ctx) as client:
62+
response = await client.get("/custom-endpoint")
63+
64+
# With proxies and base_url
65+
async with create_mcp_http_client(proxies="http://proxy:8080", base_url="https://api.example.com") as client:
66+
response = await client.get("/resource")
7167
"""
7268
# Set MCP defaults
73-
kwargs: dict[str, Any] = {
69+
default_kwargs: dict[str, Any] = {
7470
"follow_redirects": True,
71+
"timeout": httpx.Timeout(30.0),
7572
}
76-
77-
# Handle timeout
78-
if timeout is None:
79-
kwargs["timeout"] = httpx.Timeout(30.0)
80-
else:
81-
kwargs["timeout"] = timeout
82-
83-
# Handle headers
84-
if headers is not None:
85-
kwargs["headers"] = headers
86-
87-
# Handle authentication
88-
if auth is not None:
89-
kwargs["auth"] = auth
90-
91-
# Handle SSL verification
92-
if verify is not None:
93-
kwargs["verify"] = verify
94-
95-
return httpx.AsyncClient(**kwargs)
73+
default_kwargs.update(kwargs)
74+
return httpx.AsyncClient(**default_kwargs)

tests/shared/test_httpx_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def test_custom_parameters():
1818
headers = {"Authorization": "Bearer token"}
1919
timeout = httpx.Timeout(60.0)
2020

21-
client = create_mcp_http_client(headers, timeout)
21+
client = create_mcp_http_client(headers=headers, timeout=timeout)
2222

2323
assert client.headers["Authorization"] == "Bearer token"
2424
assert client.timeout.connect == 60.0

0 commit comments

Comments
 (0)