Skip to content

Commit 56d811e

Browse files
committed
clean up
1 parent 1b5fcdc commit 56d811e

File tree

2 files changed

+63
-9
lines changed

2 files changed

+63
-9
lines changed

src/mcp/shared/httpx_utils.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,40 @@
11
"""Utilities for creating standardized httpx AsyncClient instances."""
22

3+
from __future__ import annotations
4+
35
from typing import Any
46

57
import httpx
68

9+
__all__ = ["create_mcp_http_client"]
10+
711

812
def create_mcp_http_client(
913
*,
1014
headers: dict[str, Any] | None = None,
11-
timeout: httpx.Timeout | float | None = None,
15+
timeout: httpx.Timeout | None = None,
1216
**kwargs: Any,
1317
) -> httpx.AsyncClient:
1418
"""Create a standardized httpx AsyncClient with MCP defaults.
1519
1620
This function provides common defaults used throughout the MCP codebase:
1721
- follow_redirects=True (always enabled)
1822
- Default timeout of 30 seconds if not specified
19-
- Header will be merged
23+
- Headers will be merged with any existing headers in kwargs
2024
2125
Args:
2226
headers: Optional headers to include with all requests.
23-
timeout: Request timeout in seconds (float) or httpx.Timeout object.
27+
timeout: Request timeout as httpx.Timeout object.
2428
Defaults to 30 seconds if not specified.
2529
**kwargs: Additional keyword arguments to pass to AsyncClient.
2630
2731
Returns:
2832
Configured httpx.AsyncClient instance with MCP defaults.
2933
34+
Note:
35+
The returned AsyncClient must be used as a context manager to ensure
36+
proper cleanup of connections.
37+
3038
Examples:
3139
# Basic usage with MCP defaults
3240
async with create_mcp_http_client() as client:
@@ -50,16 +58,16 @@ def create_mcp_http_client(
5058
# Handle timeout
5159
if timeout is None:
5260
defaults["timeout"] = httpx.Timeout(30.0)
53-
elif isinstance(timeout, int | float):
54-
defaults["timeout"] = httpx.Timeout(timeout)
5561
else:
5662
defaults["timeout"] = timeout
5763

58-
# Handle headers
64+
# Handle headers with proper merging
5965
if headers is not None:
60-
kwargs["headers"] = headers
66+
existing_headers = kwargs.get("headers", {})
67+
merged_headers = {**existing_headers, **headers}
68+
kwargs["headers"] = merged_headers
6169

62-
# Merge defaults with provided kwargs
63-
kwargs = {**defaults, **kwargs}
70+
# Merge kwargs with defaults (defaults take precedence)
71+
kwargs = {**kwargs, **defaults}
6472

6573
return httpx.AsyncClient(**kwargs)

tests/shared/test_httpx_utils.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""Tests for httpx utility functions."""
2+
3+
import httpx
4+
5+
from mcp.shared.httpx_utils import create_mcp_http_client
6+
7+
8+
class TestCreateMcpHttpClient:
9+
"""Test create_mcp_http_client function."""
10+
11+
def test_default_settings(self):
12+
"""Test that default settings are applied correctly."""
13+
client = create_mcp_http_client()
14+
15+
# Check follow_redirects is True
16+
assert client.follow_redirects is True
17+
18+
# Check default timeout is 30 seconds
19+
assert client.timeout.connect == 30.0
20+
assert client.timeout.read == 30.0
21+
assert client.timeout.write == 30.0
22+
assert client.timeout.pool == 30.0
23+
24+
def test_custom_parameters(self):
25+
"""Test custom headers and timeout are set correctly."""
26+
headers = {"Authorization": "Bearer token", "X-Custom": "value"}
27+
timeout = httpx.Timeout(connect=5.0, read=10.0, write=15.0, pool=20.0)
28+
29+
client = create_mcp_http_client(headers=headers, timeout=timeout)
30+
31+
# Check headers
32+
assert client.headers["Authorization"] == "Bearer token"
33+
assert client.headers["X-Custom"] == "value"
34+
35+
# Check custom timeout
36+
assert client.timeout.connect == 5.0
37+
assert client.timeout.read == 10.0
38+
assert client.timeout.write == 15.0
39+
assert client.timeout.pool == 20.0
40+
41+
def test_follow_redirects_enforced(self):
42+
"""Test follow_redirects is always True even if False is passed."""
43+
client = create_mcp_http_client(follow_redirects=False)
44+
45+
# Should still be True because our defaults override user input
46+
assert client.follow_redirects is True

0 commit comments

Comments
 (0)