fastapi_mcp icon indicating copy to clipboard operation
fastapi_mcp copied to clipboard

[BUG] Exception occurs during client session disconnection

Open cuspymd opened this issue 7 months ago • 5 comments

Describe the bug

When adding a middleware, the following exception always occurs during client session disconnection. While there is no issue with calling the tool, I'm curious if there is a way to prevent this exception from occurring.

[2025-06-13 12:15:28,591][DEBUG][sse_starlette.sse][line=230][49972] - Got event: http.disconnect. Stop streaming.
[2025-06-13 12:15:28,591][DEBUG][root][line=159][49972] - Client session disconnected 04bbc672-f124-4291-b1fa-3b8a923ffe35
     ERROR   Exception in ASGI application
  + Exception Group Traceback (most recent call last):
  |   File "C:\...\Lib\site-packages\starlette\_utils.py", line 76, in collapse_excgroups
  |     yield
  |   File "C:\...\Lib\site-packages\starlette\middleware\base.py", line 177, in __call__
  |     async with anyio.create_task_group() as task_group:
  |                ^^^^^^^^^^^^^^^^^^^^^^^^^
  |   File "C:\...\Lib\site-packages\anyio\_backends\_asyncio.py", line 772, in __aexit__
  |     raise BaseExceptionGroup(
  | ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
  +-+---------------- 1 ----------------
    | Traceback (most recent call last):
    |   File "C:\...\Lib\site-packages\uvicorn\protocols\http\httptools_impl.py", line 409, in run_asgi
    |     result = await app(  # type: ignore[func-returns-value]
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "C:\...\Lib\site-packages\uvicorn\middleware\proxy_headers.py", line 60, in __call__
    |     return await self.app(scope, receive, send)
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "C:\...\Lib\site-packages\fastapi\applications.py", line 1054, in __call__
    |     await super().__call__(scope, receive, send)
    |   File "C:\...\Lib\site-packages\starlette\applications.py", line 112, in __call__
    |     await self.middleware_stack(scope, receive, send)
    |   File "C:\...\Lib\site-packages\starlette\middleware\errors.py", line 187, in __call__
    |     raise exc
    |   File "C:\...\Lib\site-packages\starlette\middleware\errors.py", line 165, in __call__
    |     await self.app(scope, receive, _send)
    |   File "C:\...\Lib\site-packages\starlette\middleware\base.py", line 176, in __call__
    |     with recv_stream, send_stream, collapse_excgroups():
    |                                    ^^^^^^^^^^^^^^^^^^^^
    |   File "C:\...\Lib\contextlib.py", line 158, in __exit__
    |     self.gen.throw(value)
    |   File "C:\...\Lib\site-packages\starlette\_utils.py", line 82, in collapse_excgroups
    |     raise exc
    |   File "C:\...\Lib\site-packages\starlette\middleware\base.py", line 179, in __call__
    |     await response(scope, wrapped_receive, send)
    |   File "C:\...\Lib\site-packages\starlette\middleware\base.py", line 216, in __call__
    |     async for chunk in self.body_iterator:
    |   File "C:\...\Lib\site-packages\starlette\middleware\base.py", line 163, in body_stream
    |     assert message["type"] == "http.response.body"
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | AssertionError
    +------------------------------------

To Reproduce

  1. After adding the middleware below to the code, start the server
  2. Run Cline and connect to the MCP server
  3. Terminate the Cline (VS Code)
@app.middleware("http")
async def some_middleware(request: Request, call_next):
    return await call_next(request)

System Info

fastapi : 0.115.12 fastapi-mcp : 0.3.4 MCP host : Cline (VS Code)

cuspymd avatar Jun 13 '25 05:06 cuspymd

This is also happening here. I commented out all the middleware in my application and it stopped giving this exception.

satheler avatar Jun 19 '25 01:06 satheler

I had to rewrite my application's middlewares to be in the format of other Starlet middlewares (such as CORSMiddleware).

Previously, I created my middleware inheriting from BaseHTTPMiddleware. Now that I applied the standard, this error stopped happening.

In any case, I believe this error is related to the SSE return of the /mcp path.

satheler avatar Jun 19 '25 02:06 satheler

I also encounter some problem.

I print message

{'type': 'http.response.body', 'body': b''}
{'type': 'http.response.body', 'body': b'{"message":"Accepted"}'}
{'type': 'http.response.body', 'body': b'{"message":"Accepted"}'}
{'type': 'http.response.body', 'body': b'event: message\r\ndata: {"jsonrpc":"2.0","id":1,"result":{"tools":[]}}\r\n\r\n', 'more_body': True}
{'type': 'http.response.start', 'status': 200, 'headers': [(b'content-length', b'4'), (b'content-type', b'application/json')]}

I noticed that something extra was added to the last line.

Shengshenlan avatar Jul 08 '25 07:07 Shengshenlan

Does is still happen in 0.4.0, when using the new HTTP transport?

shahar4499 avatar Jul 29 '25 14:07 shahar4499

@shahar4499 I had this problem with middleware (GZipMiddleware) in 0.3.4. After trying 0.4.0 with the new HTTP transport (implementation of Streamable HTTP), there are now no more problems with middleware in my side.

Lexachoc avatar Oct 17 '25 14:10 Lexachoc