Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Inconsistent timeout and sse_read_timeout Types in sse_client and streamablehttp_client #936

Closed
@yinglj

Description

@yinglj

Inconsistent timeout and sse_read_timeout Types in sse_client and streamablehttp_client

Description

In the modelcontextprotocol/python-sdk repository (version 1.9.3), the timeout and sse_read_timeout parameters in mcp/client/sse.py and mcp/client/streamable_http.py have inconsistent types, causing confusion and runtime errors in downstream applications:

  • mcp/client/sse.py (sse_client):

    @asynccontextmanager
    async def sse_client(
        url: str,
        headers: dict[str, Any] | None = None,
        timeout: float = 5,
        sse_read_timeout: float = 60 * 5,
        ...
    )
    • timeout and sse_read_timeout are typed as float (seconds).
  • mcp/client/streamable_http.py (streamablehttp_client):

    @asynccontextmanager
    async def streamablehttp_client(
        url: str,
        headers: dict[str, Any] | None = None,
        timeout: timedelta = timedelta(seconds=30),
        sse_read_timeout: timedelta = timedelta(seconds=60 * 5),
        ...
    )
    • timeout and sse_read_timeout are typed as timedelta.

This inconsistency forces developers to handle different types for similar parameters across MCP transport implementations, leading to errors. For example, in the openai-agents-python project, passing a float timeout to MCPServerStreamableHttp (which uses streamablehttp_client) causes a TaskGroup exception:

2025-06-11 19:17:20,478 server.py:132 - mcp_client - [MainThread:5432] - ERROR - Error initializing MCP server: unhandled errors in a TaskGroup (1 sub-exception)

The lack of clear error messages from streamablehttp_client (e.g., type mismatch) further complicates debugging.

Steps to Reproduce

  1. Configure an MCPServerStreamableHttp (from openai-agents-python) with a float timeout (e.g., timeout=30).
  2. Call server.connect(), which invokes streamablehttp_client.
  3. Observe a TaskGroup exception due to timedelta type mismatch.
  4. Compare with MCPServerSse, which accepts float without issues.

Expected Behavior

Both sse_client and streamablehttp_client should use consistent types for timeout and sse_read_timeout (preferably float, as it’s more intuitive for configuration files and aligns with sse_client). The functions should either handle type conversion internally or provide clear TypeError messages for invalid types.

Proposed Solution

  1. Unify Parameter Types:

    • Update streamablehttp_client to accept timeout and sse_read_timeout as float (seconds), matching sse_client.
    • Internally convert float to timedelta in streamablehttp_client if required by the underlying HTTP client (e.g., httpx).
  2. Add Type Validation:

    • In both sse_client and streamablehttp_client, validate that timeout and sse_read_timeout are int or float, raising a clear TypeError otherwise.
  3. Update Documentation:

    • Clearly document that timeout and sse_read_timeout are in seconds (float) for both functions.
    • Specify default values and any internal conversions.
  4. Ensure Backward Compatibility:

    • Allow streamablehttp_client to accept timedelta for a transition period, logging a deprecation warning and converting to float internally.

Example implementation for streamablehttp_client:

from datetime import timedelta
from typing import Union

@asynccontextmanager
async def streamablehttp_client(
    url: str,
    headers: dict[str, Any] | None = None,
    timeout: Union[float, timedelta] = 30.0,  # Accept float, support timedelta temporarily
    sse_read_timeout: Union[float, timedelta] = 60 * 5.0,
    terminate_on_close: bool = True,
    httpx_client_factory: McpHttpClientFactory = create_mcp_http_client,
    auth: httpx.Auth | None = None,
):
    if isinstance(timeout, timedelta):
        logger.warning("Using timedelta for timeout is deprecated; use float (seconds) instead")
        timeout = timeout.total_seconds()
    if isinstance(sse_read_timeout, timedelta):
        logger.warning("Using timedelta for sse_read_timeout is deprecated; use float (seconds) instead")
        sse_read_timeout = sse_read_timeout.total_seconds()
    
    if not isinstance(timeout, (int, float)):
        raise TypeError(f"timeout must be float, got {type(timeout)}")
    if not isinstance(sse_read_timeout, (int, float)):
        raise TypeError(f"sse_read_timeout must be float, got {type(sse_read_timeout)}")
    
    # Convert to timedelta for internal use if needed
    timeout_td = timedelta(seconds=float(timeout))
    sse_read_timeout_td = timedelta(seconds=float(sse_read_timeout))
    
    # Proceed with streamablehttp_client logic
    ...

Additional Notes

  • This issue was discovered while using MCPServerStreamableHttp with a server at http://localhost:3001/mcp (confirmed reachable via curl).
  • The type inconsistency propagates to downstream projects like openai-agents-python, causing errors in MCPServerStreamableHttp initialization.
  • Suggest updating MCPServerSseParams and MCPServerStreamableHttpParams in openai-agents-python to align with the unified float type after this change.
  • Clearer error messages in streamablehttp_client (e.g., for type mismatches or HTTP errors) would greatly improve debugging.

Environment

  • Package version: mcp 1.9.3
  • Python version: [Specify your Python version, e.g., 3.10]
  • Operating system: [Specify your OS, e.g., macOS]

Please let me know if you need additional details or assistance to resolve this issue!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions