pythonpython-asynciomodel-context-protocol

FastMCP client timing out while initializing the session


I am running a simple FastMCP server locally via the following server side code:

from mcp.server.fastmcp import FastMCP


server = FastMCP(
    name="Example-FastMCP",
    streamable_http_path="/mcp",   # ← default but shown for clarity
    # json_response=True,
    # stateless_http=True
)


@server.tool()
def add(x: int, y: int) -> int:
    return x + y


if __name__ == "__main__":
    server.run(transport="streamable-http")

I am trying to connect to this server using the below client code:

import asyncio
from datetime import timedelta

from mcp.client.streamable_http import streamablehttp_client          # <- transport
from mcp.client.session import ClientSession                          # <- high-level API

SERVER_URL = "http://127.0.0.1:8000/mcp/"


async def main() -> None:
    async with streamablehttp_client(
        url=SERVER_URL,
        timeout=100,
        sse_read_timeout=300,
    ) as (read_stream, write_stream, get_session_id):
        session = ClientSession(
            read_stream=read_stream,
            write_stream=write_stream,
            read_timeout_seconds=timedelta(seconds=100),
        )
        init_result = await session.initialize()
        print(" initialized – protocol version:", init_result.protocolVersion)
        print(" session-id received from server:", get_session_id())

        tools_result = await session.list_tools()
        tool_names = [tool.name for tool in tools_result.tools]
        print(" tools available on server:", tool_names)

        call_result = await session.call_tool("add", {"x": 2, "y": 3})
        print(" add(2, 3) =", call_result.output[0].text)


if __name__ == "__main__":
    asyncio.run(main())

While running client code, it times out while initializing the session with server. client side logs:

/Users/susai/repos/ds-mcp/.venv/bin/python /Users/susai/repos/ds-mcp/app/client3.py 
  + Exception Group Traceback (most recent call last):
  |   File "/Users/susai/repos/ds-mcp/app/client3.py", line 34, in <module>
  |     asyncio.run(main())
  |     ~~~~~~~~~~~^^^^^^^^
  |   File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/runners.py", line 195, in run
  |     return runner.run(main)
  |            ~~~~~~~~~~^^^^^^
  |   File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/runners.py", line 118, in run
  |     return self._loop.run_until_complete(task)
  |            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  |   File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/base_events.py", line 725, in run_until_complete
  |     return future.result()
  |            ~~~~~~~~~~~~~^^
  |   File "/Users/susai/repos/ds-mcp/app/client3.py", line 11, in main
  |     async with streamablehttp_client(
  |                ~~~~~~~~~~~~~~~~~~~~~^
  |         url=SERVER_URL,
  |         ^^^^^^^^^^^^^^^
  |         timeout=30,
  |         ^^^^^^^^^^^
  |         sse_read_timeout=300,
  |         ^^^^^^^^^^^^^^^^^^^^^
  |     ) as (read_stream, write_stream, get_session_id):
  |     ^
  |   File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/contextlib.py", line 235, in __aexit__
  |     await self.gen.athrow(value)
  |   File "/Users/susai/repos/ds-mcp/.venv/lib/python3.13/site-packages/mcp/client/streamable_http.py", line 437, in streamablehttp_client
  |     async with anyio.create_task_group() as tg:
  |                ~~~~~~~~~~~~~~~~~~~~~~~^^
  |   File "/Users/susai/repos/ds-mcp/.venv/lib/python3.13/site-packages/anyio/_backends/_asyncio.py", line 772, in __aexit__
  |     raise BaseExceptionGroup(
  |         "unhandled errors in a TaskGroup", self._exceptions
  |     ) from None
  | ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
  +-+---------------- 1 ----------------
    | Traceback (most recent call last):
    |   File "/Users/susai/repos/ds-mcp/.venv/lib/python3.13/site-packages/anyio/streams/memory.py", line 111, in receive
    |     return self.receive_nowait()
    |            ~~~~~~~~~~~~~~~~~~~^^
    |   File "/Users/susai/repos/ds-mcp/.venv/lib/python3.13/site-packages/anyio/streams/memory.py", line 106, in receive_nowait
    |     raise WouldBlock
    | anyio.WouldBlock
    | 
    | During handling of the above exception, another exception occurred:
    | 
    | Traceback (most recent call last):
    |   File "/Users/susai/repos/ds-mcp/.venv/lib/python3.13/site-packages/anyio/_core/_tasks.py", line 115, in fail_after
    |     yield cancel_scope
    |   File "/Users/susai/repos/ds-mcp/.venv/lib/python3.13/site-packages/mcp/shared/session.py", line 272, in send_request
    |     response_or_error = await response_stream_reader.receive()
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "/Users/susai/repos/ds-mcp/.venv/lib/python3.13/site-packages/anyio/streams/memory.py", line 119, in receive
    |     await receive_event.wait()
    |   File "/Users/susai/repos/ds-mcp/.venv/lib/python3.13/site-packages/anyio/_backends/_asyncio.py", line 1774, in wait
    |     await self._event.wait()
    |   File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/locks.py", line 213, in wait
    |     await fut
    | asyncio.exceptions.CancelledError: Cancelled by cancel scope 106faafd0
    | 
    | During handling of the above exception, another exception occurred:
    | 
    | Traceback (most recent call last):
    |   File "/Users/susai/repos/ds-mcp/.venv/lib/python3.13/site-packages/mcp/shared/session.py", line 271, in send_request
    |     with anyio.fail_after(timeout):
    |          ~~~~~~~~~~~~~~~~^^^^^^^^^
    |   File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/contextlib.py", line 162, in __exit__
    |     self.gen.throw(value)
    |     ~~~~~~~~~~~~~~^^^^^^^
    |   File "/Users/susai/repos/ds-mcp/.venv/lib/python3.13/site-packages/anyio/_core/_tasks.py", line 118, in fail_after
    |     raise TimeoutError
    | TimeoutError
    | 
    | During handling of the above exception, another exception occurred:
    | 
    | Traceback (most recent call last):
    |   File "/Users/susai/repos/ds-mcp/.venv/lib/python3.13/site-packages/mcp/client/streamable_http.py", line 461, in streamablehttp_client
    |     yield (
    |     ...<3 lines>...
    |     )
    |   File "/Users/susai/repos/ds-mcp/app/client3.py", line 21, in main
    |     init_result = await session.initialize()
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "/Users/susai/repos/ds-mcp/.venv/lib/python3.13/site-packages/mcp/client/session.py", line 123, in initialize
    |     result = await self.send_request(
    |              ^^^^^^^^^^^^^^^^^^^^^^^^
    |     ...<15 lines>...
    |     )
    |     ^
    |   File "/Users/susai/repos/ds-mcp/.venv/lib/python3.13/site-packages/mcp/shared/session.py", line 274, in send_request
    |     raise McpError(
    |     ...<8 lines>...
    |     )
    | mcp.shared.exceptions.McpError: Timed out while waiting for response to ClientRequest. Waited 100.0 seconds.
    +------------------------------------

Process finished with exit code 1

server side logs:

/Users/susai/repos/ds-mcp/.venv/bin/python /Users/susai/repos/ds-mcp/app/server3.py 
INFO:     Started server process [16523]
INFO:     Waiting for application startup.
StreamableHTTP session manager started
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
Created new transport with session ID: 278ddef2d9f044dd924b0b24da32c94d
INFO:     127.0.0.1:55002 - "POST /mcp/ HTTP/1.1" 200 OK
Terminating session: 278ddef2d9f044dd924b0b24da32c94d
INFO:     127.0.0.1:55006 - "DELETE /mcp/ HTTP/1.1" 200 OK

I have tried passing the json_response and stateless_http flags as True to the FastMCP instance, but this also results in the same behaviour.

Surprisingly the sse transport works as expected, but is now depricated. Also our API Gateway doesn't support SSE, so that is out of option.


Solution

  • On my computer it hangs on session.initialize().

    It works when I use async with to create session

    async with ClientSession(
                read_stream=read_stream,
                write_stream=write_stream,
                read_timeout_seconds=timedelta(seconds=100),
    ) as session:
        init_result = await session.initialize()
    
        # ... rest ...
    

    But I don't know how to write it without async with becaus this doesn't work with await

    session = await ClientSession(...)  # doesn't work
    

    I also need to use .content instead of .output to get result

    print(" add(2, 3) =", call_result.content[0].text)
    

    or .structuredContent['result']

    print(" add(2, 3) =", call_result.structuredContent['result'])
    

    You can see it if you use print(call_result)