Skip to content

Commit cd038cf

Browse files
refactor: Address API design improvements in StreamableHTTP client
This commit addresses two API design concerns: 1. Remove private module usage in examples: Examples no longer import from the private mcp.shared._httpx_utils module. Instead, they create httpx clients directly using the public httpx library. 2. Rename httpx_client parameter to http_client: The 'httpx_client' parameter name was redundant since the type annotation already specifies it's an httpx.AsyncClient. Renaming to 'http_client' provides a cleaner, more concise API. Changes: - Updated oauth_client.py and simple-auth-client examples to use public APIs - Renamed httpx_client to http_client in function signatures - Updated all internal callers and tests - Updated deprecated streamablehttp_client wrapper function
1 parent 5e7c5d2 commit cd038cf

File tree

6 files changed

+20
-19
lines changed

6 files changed

+20
-19
lines changed

examples/clients/simple-auth-client/mcp_simple_auth_client/main.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@
1515
from typing import Any
1616
from urllib.parse import parse_qs, urlparse
1717

18+
import httpx
19+
1820
from mcp.client.auth import OAuthClientProvider, TokenStorage
1921
from mcp.client.session import ClientSession
2022
from mcp.client.sse import sse_client
2123
from mcp.client.streamable_http import streamable_http_client
22-
from mcp.shared._httpx_utils import create_mcp_http_client
2324
from mcp.shared.auth import OAuthClientInformationFull, OAuthClientMetadata, OAuthToken
2425

2526

@@ -205,10 +206,10 @@ async def _default_redirect_handler(authorization_url: str) -> None:
205206
await self._run_session(read_stream, write_stream, None)
206207
else:
207208
print("📡 Opening StreamableHTTP transport connection with auth...")
208-
async with create_mcp_http_client(auth=oauth_auth) as custom_client:
209+
async with httpx.AsyncClient(auth=oauth_auth, follow_redirects=True) as custom_client:
209210
async with streamable_http_client(
210211
url=self.server_url,
211-
httpx_client=custom_client,
212+
http_client=custom_client,
212213
) as (read_stream, write_stream, get_session_id):
213214
await self._run_session(read_stream, write_stream, get_session_id)
214215

examples/snippets/clients/oauth_client.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@
1010
import asyncio
1111
from urllib.parse import parse_qs, urlparse
1212

13+
import httpx
1314
from pydantic import AnyUrl
1415

1516
from mcp import ClientSession
1617
from mcp.client.auth import OAuthClientProvider, TokenStorage
1718
from mcp.client.streamable_http import streamable_http_client
18-
from mcp.shared._httpx_utils import create_mcp_http_client
1919
from mcp.shared.auth import OAuthClientInformationFull, OAuthClientMetadata, OAuthToken
2020

2121

@@ -69,8 +69,8 @@ async def main():
6969
callback_handler=handle_callback,
7070
)
7171

72-
async with create_mcp_http_client(auth=oauth_auth) as custom_client:
73-
async with streamable_http_client("http://localhost:8001/mcp", httpx_client=custom_client) as (read, write, _):
72+
async with httpx.AsyncClient(auth=oauth_auth, follow_redirects=True) as custom_client:
73+
async with streamable_http_client("http://localhost:8001/mcp", http_client=custom_client) as (read, write, _):
7474
async with ClientSession(read, write) as session:
7575
await session.initialize()
7676

src/mcp/client/session_group.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ async def _establish_session(
263263

264264
client = streamable_http_client(
265265
url=server_params.url,
266-
httpx_client=httpx_client,
266+
http_client=httpx_client,
267267
terminate_on_close=server_params.terminate_on_close,
268268
)
269269
read, write, _ = await session_stack.enter_async_context(client)

src/mcp/client/streamable_http.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ def get_session_id(self) -> str | None:
452452
async def streamable_http_client(
453453
url: str,
454454
*,
455-
httpx_client: httpx.AsyncClient | None = None,
455+
http_client: httpx.AsyncClient | None = None,
456456
terminate_on_close: bool = True,
457457
) -> AsyncGenerator[
458458
tuple[
@@ -467,7 +467,7 @@ async def streamable_http_client(
467467
468468
Args:
469469
url: The MCP server endpoint URL.
470-
httpx_client: Optional pre-configured httpx.AsyncClient. If None, a default
470+
http_client: Optional pre-configured httpx.AsyncClient. If None, a default
471471
client with recommended MCP timeouts will be created. To configure headers,
472472
authentication, or other HTTP settings, create an httpx.AsyncClient and pass it here.
473473
terminate_on_close: If True, send a DELETE request to terminate the session
@@ -486,8 +486,8 @@ async def streamable_http_client(
486486
write_stream, write_stream_reader = anyio.create_memory_object_stream[SessionMessage](0)
487487

488488
# Determine if we need to create and manage the client
489-
client_provided = httpx_client is not None
490-
client = httpx_client
489+
client_provided = http_client is not None
490+
client = http_client
491491

492492
if client is None:
493493
# Create default client with recommended MCP timeouts
@@ -579,7 +579,7 @@ async def streamablehttp_client(
579579
async with client:
580580
async with streamable_http_client(
581581
url,
582-
httpx_client=client,
582+
http_client=client,
583583
terminate_on_close=terminate_on_close,
584584
) as streams:
585585
yield streams

tests/client/test_session_group.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,13 +347,13 @@ async def test_establish_session_parameterized(
347347
elif client_type_name == "streamablehttp":
348348
assert isinstance(server_params_instance, StreamableHttpParameters)
349349
# Verify streamable_http_client was called with url, httpx_client, and terminate_on_close
350-
# The httpx_client is created by the real create_mcp_http_client
350+
# The http_client is created by the real create_mcp_http_client
351351
import httpx
352352

353353
call_args = mock_specific_client_func.call_args
354354
assert call_args.kwargs["url"] == server_params_instance.url
355355
assert call_args.kwargs["terminate_on_close"] == server_params_instance.terminate_on_close
356-
assert isinstance(call_args.kwargs["httpx_client"], httpx.AsyncClient)
356+
assert isinstance(call_args.kwargs["http_client"], httpx.AsyncClient)
357357

358358
mock_client_cm_instance.__aenter__.assert_awaited_once()
359359

tests/shared/test_streamable_http.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,7 +1008,7 @@ async def test_streamable_http_client_session_termination(basic_server: None, ba
10081008
headers[MCP_SESSION_ID_HEADER] = captured_session_id
10091009

10101010
async with create_mcp_http_client(headers=headers) as httpx_client:
1011-
async with streamable_http_client(f"{basic_server_url}/mcp", httpx_client=httpx_client) as (
1011+
async with streamable_http_client(f"{basic_server_url}/mcp", http_client=httpx_client) as (
10121012
read_stream,
10131013
write_stream,
10141014
_,
@@ -1075,7 +1075,7 @@ async def mock_delete(self: httpx.AsyncClient, *args: Any, **kwargs: Any) -> htt
10751075
headers[MCP_SESSION_ID_HEADER] = captured_session_id
10761076

10771077
async with create_mcp_http_client(headers=headers) as httpx_client:
1078-
async with streamable_http_client(f"{basic_server_url}/mcp", httpx_client=httpx_client) as (
1078+
async with streamable_http_client(f"{basic_server_url}/mcp", http_client=httpx_client) as (
10791079
read_stream,
10801080
write_stream,
10811081
_,
@@ -1175,7 +1175,7 @@ async def run_tool():
11751175
headers[MCP_PROTOCOL_VERSION_HEADER] = captured_protocol_version
11761176

11771177
async with create_mcp_http_client(headers=headers) as httpx_client:
1178-
async with streamable_http_client(f"{server_url}/mcp", httpx_client=httpx_client) as (
1178+
async with streamable_http_client(f"{server_url}/mcp", http_client=httpx_client) as (
11791179
read_stream,
11801180
write_stream,
11811181
_,
@@ -1398,7 +1398,7 @@ async def test_streamablehttp_request_context_propagation(context_aware_server:
13981398
}
13991399

14001400
async with create_mcp_http_client(headers=custom_headers) as httpx_client:
1401-
async with streamable_http_client(f"{basic_server_url}/mcp", httpx_client=httpx_client) as (
1401+
async with streamable_http_client(f"{basic_server_url}/mcp", http_client=httpx_client) as (
14021402
read_stream,
14031403
write_stream,
14041404
_,
@@ -1436,7 +1436,7 @@ async def test_streamablehttp_request_context_isolation(context_aware_server: No
14361436
}
14371437

14381438
async with create_mcp_http_client(headers=headers) as httpx_client:
1439-
async with streamable_http_client(f"{basic_server_url}/mcp", httpx_client=httpx_client) as (
1439+
async with streamable_http_client(f"{basic_server_url}/mcp", http_client=httpx_client) as (
14401440
read_stream,
14411441
write_stream,
14421442
_,

0 commit comments

Comments
 (0)