Client transport for StreamableHTTP. Args: url: The MCP server endpoint URL. http_client: Optional pre-configured httpx.AsyncClient. If None, a default client with recommended MCP timeouts will be created. To configure headers, authentication, or other HT
(
url: str,
*,
http_client: httpx.AsyncClient | None = None,
terminate_on_close: bool = True,
)
| 525 | # we should think about a better way to do it. I believe we can achieve it with other means. |
| 526 | @asynccontextmanager |
| 527 | async def streamable_http_client( |
| 528 | url: str, |
| 529 | *, |
| 530 | http_client: httpx.AsyncClient | None = None, |
| 531 | terminate_on_close: bool = True, |
| 532 | ) -> AsyncGenerator[TransportStreams, None]: |
| 533 | """Client transport for StreamableHTTP. |
| 534 | |
| 535 | Args: |
| 536 | url: The MCP server endpoint URL. |
| 537 | http_client: Optional pre-configured httpx.AsyncClient. If None, a default |
| 538 | client with recommended MCP timeouts will be created. To configure headers, |
| 539 | authentication, or other HTTP settings, create an httpx.AsyncClient and pass it here. |
| 540 | terminate_on_close: If True, send a DELETE request to terminate the session when the context exits. |
| 541 | |
| 542 | Yields: |
| 543 | Tuple containing: |
| 544 | - read_stream: Stream for reading messages from the server |
| 545 | - write_stream: Stream for sending messages to the server |
| 546 | |
| 547 | Example: |
| 548 | See examples/snippets/clients/ for usage patterns. |
| 549 | """ |
| 550 | # Determine if we need to create and manage the client |
| 551 | client_provided = http_client is not None |
| 552 | client = http_client |
| 553 | |
| 554 | if client is None: |
| 555 | # Create default client with recommended MCP timeouts |
| 556 | client = create_mcp_http_client() |
| 557 | |
| 558 | transport = StreamableHTTPTransport(url) |
| 559 | |
| 560 | logger.debug(f"Connecting to StreamableHTTP endpoint: {url}") |
| 561 | |
| 562 | async with contextlib.AsyncExitStack() as stack: |
| 563 | # Only manage client lifecycle if we created it |
| 564 | if not client_provided: |
| 565 | await stack.enter_async_context(client) |
| 566 | |
| 567 | read_stream_writer, read_stream = create_context_streams[SessionMessage | Exception](0) |
| 568 | write_stream, write_stream_reader = create_context_streams[SessionMessage](0) |
| 569 | |
| 570 | async with ( |
| 571 | read_stream_writer, |
| 572 | read_stream, |
| 573 | write_stream, |
| 574 | write_stream_reader, |
| 575 | anyio.create_task_group() as tg, |
| 576 | ): |
| 577 | |
| 578 | def start_get_stream() -> None: |
| 579 | tg.start_soon(transport.handle_get_stream, client, read_stream_writer) |
| 580 | |
| 581 | tg.start_soon( |
| 582 | transport.post_writer, |
| 583 | client, |
| 584 | write_stream_reader, |