From e97742305def10dc919f54f282ff2b60d52349fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E5=BE=90?= Date: Thu, 31 Jul 2025 21:09:11 +0800 Subject: [PATCH 1/8] fid sse client disconnect --- examples/fastmcp/simple_echo.py | 7 +++++-- .../simple-prompt/mcp_simple_prompt/server.py | 4 ++-- .../simple-resource/mcp_simple_resource/server.py | 4 ++-- .../servers/simple-tool/mcp_simple_tool/server.py | 4 ++-- src/mcp/server/fastmcp/server.py | 12 +++++++++++- src/mcp/server/sse.py | 2 +- tests/server/test_sse_security.py | 4 ++-- tests/shared/test_sse.py | 5 +++-- 8 files changed, 28 insertions(+), 14 deletions(-) diff --git a/examples/fastmcp/simple_echo.py b/examples/fastmcp/simple_echo.py index c26152646..8db04e702 100644 --- a/examples/fastmcp/simple_echo.py +++ b/examples/fastmcp/simple_echo.py @@ -2,13 +2,16 @@ FastMCP Echo Server """ -from mcp.server.fastmcp import FastMCP +from mcp.server.fastmcp import FastMCP,Context # Create server mcp = FastMCP("Echo Server") @mcp.tool() -def echo(text: str) -> str: +def echo(text: str, ctx: Context) -> str: """Echo the input text""" + ctx.request_context.request.query_params.get("session_id") return text + +mcp.run(transport="sse") \ No newline at end of file diff --git a/examples/servers/simple-prompt/mcp_simple_prompt/server.py b/examples/servers/simple-prompt/mcp_simple_prompt/server.py index b562cc932..e3f26c934 100644 --- a/examples/servers/simple-prompt/mcp_simple_prompt/server.py +++ b/examples/servers/simple-prompt/mcp_simple_prompt/server.py @@ -91,8 +91,8 @@ async def get_prompt( if transport == "sse": from mcp.server.sse import SseServerTransport from starlette.applications import Starlette - from starlette.responses import Response from starlette.routing import Mount, Route + from mcp.server.fastmcp.server import SilentResponse sse = SseServerTransport("/messages/") @@ -103,7 +103,7 @@ async def handle_sse(request): await app.run( streams[0], streams[1], app.create_initialization_options() ) - return Response() + return SilentResponse() starlette_app = Starlette( debug=True, diff --git a/examples/servers/simple-resource/mcp_simple_resource/server.py b/examples/servers/simple-resource/mcp_simple_resource/server.py index cef29b851..8f0dba2bb 100644 --- a/examples/servers/simple-resource/mcp_simple_resource/server.py +++ b/examples/servers/simple-resource/mcp_simple_resource/server.py @@ -58,7 +58,7 @@ async def read_resource(uri: AnyUrl) -> str | bytes: if transport == "sse": from mcp.server.sse import SseServerTransport from starlette.applications import Starlette - from starlette.responses import Response + from mcp.server.fastmcp.server import SilentResponse from starlette.routing import Mount, Route sse = SseServerTransport("/messages/") @@ -70,7 +70,7 @@ async def handle_sse(request): await app.run( streams[0], streams[1], app.create_initialization_options() ) - return Response() + return SilentResponse() starlette_app = Starlette( debug=True, diff --git a/examples/servers/simple-tool/mcp_simple_tool/server.py b/examples/servers/simple-tool/mcp_simple_tool/server.py index bf3683c9e..0cc1846a6 100644 --- a/examples/servers/simple-tool/mcp_simple_tool/server.py +++ b/examples/servers/simple-tool/mcp_simple_tool/server.py @@ -59,8 +59,8 @@ async def list_tools() -> list[types.Tool]: if transport == "sse": from mcp.server.sse import SseServerTransport from starlette.applications import Starlette - from starlette.responses import Response from starlette.routing import Mount, Route + from mcp.server.fastmcp.server import SilentResponse sse = SseServerTransport("/messages/") @@ -71,7 +71,7 @@ async def handle_sse(request): await app.run( streams[0], streams[1], app.create_initialization_options() ) - return Response() + return SilentResponse() starlette_app = Starlette( debug=True, diff --git a/src/mcp/server/fastmcp/server.py b/src/mcp/server/fastmcp/server.py index 924baaa9b..73e748434 100644 --- a/src/mcp/server/fastmcp/server.py +++ b/src/mcp/server/fastmcp/server.py @@ -52,6 +52,16 @@ logger = get_logger(__name__) +class SilentResponse(Response): + """A response that does not send any HTTP response back to the client.""" + + def __init__(self) -> None: + super().__init__() + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> Awaitable[None]: + pass + + class Settings(BaseSettings, Generic[LifespanResultT]): """FastMCP server settings. @@ -748,7 +758,7 @@ async def handle_sse(scope: Scope, receive: Receive, send: Send): streams[1], self._mcp_server.create_initialization_options(), ) - return Response() + return SilentResponse() # Create routes routes: list[Route | Mount] = [] diff --git a/src/mcp/server/sse.py b/src/mcp/server/sse.py index b7ff33280..bcd2b547c 100644 --- a/src/mcp/server/sse.py +++ b/src/mcp/server/sse.py @@ -23,7 +23,7 @@ async def handle_sse(request): streams[0], streams[1], app.create_initialization_options() ) # Return empty response to avoid NoneType error - return Response() + return SilentResponse() # Create and run Starlette app starlette_app = Starlette(routes=routes) diff --git a/tests/server/test_sse_security.py b/tests/server/test_sse_security.py index 43af35061..dd0be811e 100644 --- a/tests/server/test_sse_security.py +++ b/tests/server/test_sse_security.py @@ -10,10 +10,10 @@ import uvicorn from starlette.applications import Starlette from starlette.requests import Request -from starlette.responses import Response from starlette.routing import Mount, Route from mcp.server import Server +from mcp.server.fastmcp.server import SilentResponse from mcp.server.sse import SseServerTransport from mcp.server.transport_security import TransportSecuritySettings from mcp.types import Tool @@ -55,7 +55,7 @@ async def handle_sse(request: Request): except ValueError as e: # Validation error was already handled inside connect_sse logger.debug(f"SSE connection failed validation: {e}") - return Response() + return SilentResponse() routes = [ Route("/sse", endpoint=handle_sse), diff --git a/tests/shared/test_sse.py b/tests/shared/test_sse.py index 39ae13524..2751c88fa 100644 --- a/tests/shared/test_sse.py +++ b/tests/shared/test_sse.py @@ -19,6 +19,7 @@ from mcp.client.session import ClientSession from mcp.client.sse import sse_client from mcp.server import Server +from mcp.server.fastmcp.server import SilentResponse from mcp.server.sse import SseServerTransport from mcp.server.transport_security import TransportSecuritySettings from mcp.shared.exceptions import McpError @@ -91,7 +92,7 @@ def make_server_app() -> Starlette: async def handle_sse(request: Request) -> Response: async with sse.connect_sse(request.scope, request.receive, request._send) as streams: await server.run(streams[0], streams[1], server.create_initialization_options()) - return Response() + return SilentResponse() app = Starlette( routes=[ @@ -354,7 +355,7 @@ def run_context_server(server_port: int) -> None: async def handle_sse(request: Request) -> Response: async with sse.connect_sse(request.scope, request.receive, request._send) as streams: await context_server.run(streams[0], streams[1], context_server.create_initialization_options()) - return Response() + return SilentResponse() app = Starlette( routes=[ From 9019b4bc606e844e0babad613bda06ed0c92e33f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E5=BE=90?= Date: Thu, 31 Jul 2025 22:25:32 +0800 Subject: [PATCH 2/8] fix pyright check error --- src/mcp/server/fastmcp/server.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mcp/server/fastmcp/server.py b/src/mcp/server/fastmcp/server.py index 73e748434..00e028fd8 100644 --- a/src/mcp/server/fastmcp/server.py +++ b/src/mcp/server/fastmcp/server.py @@ -58,8 +58,8 @@ class SilentResponse(Response): def __init__(self) -> None: super().__init__() - async def __call__(self, scope: Scope, receive: Receive, send: Send) -> Awaitable[None]: - pass + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + return class Settings(BaseSettings, Generic[LifespanResultT]): From 98129c25906142178908be6ae6813fa5161d65d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E5=BE=90?= Date: Thu, 31 Jul 2025 22:49:37 +0800 Subject: [PATCH 3/8] recover unused change --- examples/fastmcp/simple_echo.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/examples/fastmcp/simple_echo.py b/examples/fastmcp/simple_echo.py index 8db04e702..c26152646 100644 --- a/examples/fastmcp/simple_echo.py +++ b/examples/fastmcp/simple_echo.py @@ -2,16 +2,13 @@ FastMCP Echo Server """ -from mcp.server.fastmcp import FastMCP,Context +from mcp.server.fastmcp import FastMCP # Create server mcp = FastMCP("Echo Server") @mcp.tool() -def echo(text: str, ctx: Context) -> str: +def echo(text: str) -> str: """Echo the input text""" - ctx.request_context.request.query_params.get("session_id") return text - -mcp.run(transport="sse") \ No newline at end of file From f29a898a8ee7e8e4c3d9ddf8e36b663fd14da26f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E5=BE=90?= Date: Thu, 31 Jul 2025 22:57:02 +0800 Subject: [PATCH 4/8] fix ruff check --- examples/servers/simple-prompt/mcp_simple_prompt/server.py | 2 +- examples/servers/simple-resource/mcp_simple_resource/server.py | 2 +- examples/servers/simple-tool/mcp_simple_tool/server.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/servers/simple-prompt/mcp_simple_prompt/server.py b/examples/servers/simple-prompt/mcp_simple_prompt/server.py index e3f26c934..634ac43dc 100644 --- a/examples/servers/simple-prompt/mcp_simple_prompt/server.py +++ b/examples/servers/simple-prompt/mcp_simple_prompt/server.py @@ -89,10 +89,10 @@ async def get_prompt( ) if transport == "sse": + from mcp.server.fastmcp.server import SilentResponse from mcp.server.sse import SseServerTransport from starlette.applications import Starlette from starlette.routing import Mount, Route - from mcp.server.fastmcp.server import SilentResponse sse = SseServerTransport("/messages/") diff --git a/examples/servers/simple-resource/mcp_simple_resource/server.py b/examples/servers/simple-resource/mcp_simple_resource/server.py index 8f0dba2bb..80fc51521 100644 --- a/examples/servers/simple-resource/mcp_simple_resource/server.py +++ b/examples/servers/simple-resource/mcp_simple_resource/server.py @@ -56,9 +56,9 @@ async def read_resource(uri: AnyUrl) -> str | bytes: return SAMPLE_RESOURCES[name]["content"] if transport == "sse": + from mcp.server.fastmcp.server import SilentResponse from mcp.server.sse import SseServerTransport from starlette.applications import Starlette - from mcp.server.fastmcp.server import SilentResponse from starlette.routing import Mount, Route sse = SseServerTransport("/messages/") diff --git a/examples/servers/simple-tool/mcp_simple_tool/server.py b/examples/servers/simple-tool/mcp_simple_tool/server.py index 0cc1846a6..8e30aa59b 100644 --- a/examples/servers/simple-tool/mcp_simple_tool/server.py +++ b/examples/servers/simple-tool/mcp_simple_tool/server.py @@ -57,10 +57,10 @@ async def list_tools() -> list[types.Tool]: ] if transport == "sse": + from mcp.server.fastmcp.server import SilentResponse from mcp.server.sse import SseServerTransport from starlette.applications import Starlette from starlette.routing import Mount, Route - from mcp.server.fastmcp.server import SilentResponse sse = SseServerTransport("/messages/") From 635ffcbeb4c838c683279d061506e7f3911cced7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E5=BE=90?= Date: Wed, 20 Aug 2025 18:08:08 +0800 Subject: [PATCH 5/8] return response for handle_sse --- src/mcp/server/fastmcp/server.py | 60 +++++++++++++++----------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/src/mcp/server/fastmcp/server.py b/src/mcp/server/fastmcp/server.py index 00e028fd8..b8439788d 100644 --- a/src/mcp/server/fastmcp/server.py +++ b/src/mcp/server/fastmcp/server.py @@ -52,16 +52,6 @@ logger = get_logger(__name__) -class SilentResponse(Response): - """A response that does not send any HTTP response back to the client.""" - - def __init__(self) -> None: - super().__init__() - - async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: - return - - class Settings(BaseSettings, Generic[LifespanResultT]): """FastMCP server settings. @@ -745,20 +735,25 @@ def sse_app(self, mount_path: str | None = None) -> Starlette: security_settings=self.settings.transport_security, ) - async def handle_sse(scope: Scope, receive: Receive, send: Send): - # Add client ID from auth context into request context if available - - async with sse.connect_sse( - scope, - receive, - send, - ) as streams: - await self._mcp_server.run( - streams[0], - streams[1], - self._mcp_server.create_initialization_options(), - ) - return SilentResponse() + async def handle_sse(request: Request) -> Response: + """Handle SSE connection using Starlette's EventSourceResponse.""" + # Create a custom Response class that wraps the SSE connection + class SSEConnectionResponse(Response): + def __init__(self, sse_transport: SseServerTransport, server: MCPServer) -> None: + super().__init__() + self.sse_transport = sse_transport + self.server = server + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + async with self.sse_transport.connect_sse(scope, receive, send) as streams: + await self.server.run( + streams[0], + streams[1], + self.server.create_initialization_options(), + ) + + # Return the Response object for Starlette to handle + return SSEConnectionResponse(sse, self._mcp_server) # Create routes routes: list[Route | Mount] = [] @@ -796,7 +791,7 @@ async def handle_sse(scope: Scope, receive: Receive, send: Send): ) ) - # When auth is configured, require authentication + # Create auth wrapper if needed if self._token_verifier: # Determine resource metadata URL resource_metadata_url = None @@ -807,11 +802,16 @@ async def handle_sse(scope: Scope, receive: Receive, send: Send): str(self.settings.auth.resource_server_url).rstrip("/") + "/.well-known/oauth-protected-resource" ) - # Auth is enabled, wrap the endpoints with RequireAuthMiddleware + # # Auth is enabled, wrap the endpoints with RequireAuthMiddleware + async def handle_sse_auth(scope: Scope, receive: Receive, send: Send) -> None: + request = Request(scope, receive) + response = await handle_sse(request) + await response(scope, receive, send) + routes.append( Route( self.settings.sse_path, - endpoint=RequireAuthMiddleware(handle_sse, required_scopes, resource_metadata_url), + endpoint=RequireAuthMiddleware(handle_sse_auth, required_scopes, resource_metadata_url), methods=["GET"], ) ) @@ -824,14 +824,10 @@ async def handle_sse(scope: Scope, receive: Receive, send: Send): else: # Auth is disabled, no need for RequireAuthMiddleware # Since handle_sse is an ASGI app, we need to create a compatible endpoint - async def sse_endpoint(request: Request) -> Response: - # Convert the Starlette request to ASGI parameters - return await handle_sse(request.scope, request.receive, request._send) # type: ignore[reportPrivateUsage] - routes.append( Route( self.settings.sse_path, - endpoint=sse_endpoint, + endpoint=handle_sse, methods=["GET"], ) ) From 14e5b9b736e1e485d0fb0394a1d0114c2fabdc2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E5=BE=90?= Date: Wed, 20 Aug 2025 19:42:34 +0800 Subject: [PATCH 6/8] remove SilentResponse --- examples/servers/simple-prompt/mcp_simple_prompt/server.py | 4 ++-- .../servers/simple-resource/mcp_simple_resource/server.py | 4 ++-- examples/servers/simple-tool/mcp_simple_tool/server.py | 4 ++-- src/mcp/server/sse.py | 2 +- tests/server/test_sse_security.py | 4 ++-- tests/shared/test_sse.py | 5 ++--- 6 files changed, 11 insertions(+), 12 deletions(-) diff --git a/examples/servers/simple-prompt/mcp_simple_prompt/server.py b/examples/servers/simple-prompt/mcp_simple_prompt/server.py index 8770bd6f4..76b598f93 100644 --- a/examples/servers/simple-prompt/mcp_simple_prompt/server.py +++ b/examples/servers/simple-prompt/mcp_simple_prompt/server.py @@ -77,9 +77,9 @@ async def get_prompt(name: str, arguments: dict[str, str] | None = None) -> type ) if transport == "sse": - from mcp.server.fastmcp.server import SilentResponse from mcp.server.sse import SseServerTransport from starlette.applications import Starlette + from starlette.responses import Response from starlette.routing import Mount, Route sse = SseServerTransport("/messages/") @@ -87,7 +87,7 @@ async def get_prompt(name: str, arguments: dict[str, str] | None = None) -> type async def handle_sse(request: Request): async with sse.connect_sse(request.scope, request.receive, request._send) as streams: # type: ignore[reportPrivateUsage] await app.run(streams[0], streams[1], app.create_initialization_options()) - return SilentResponse() + return Response() starlette_app = Starlette( debug=True, diff --git a/examples/servers/simple-resource/mcp_simple_resource/server.py b/examples/servers/simple-resource/mcp_simple_resource/server.py index 789ce8793..002d7ad10 100644 --- a/examples/servers/simple-resource/mcp_simple_resource/server.py +++ b/examples/servers/simple-resource/mcp_simple_resource/server.py @@ -57,9 +57,9 @@ async def read_resource(uri: AnyUrl) -> str | bytes: return SAMPLE_RESOURCES[name]["content"] if transport == "sse": - from mcp.server.fastmcp.server import SilentResponse from mcp.server.sse import SseServerTransport from starlette.applications import Starlette + from starlette.responses import Response from starlette.routing import Mount, Route sse = SseServerTransport("/messages/") @@ -67,7 +67,7 @@ async def read_resource(uri: AnyUrl) -> str | bytes: async def handle_sse(request: Request): async with sse.connect_sse(request.scope, request.receive, request._send) as streams: # type: ignore[reportPrivateUsage] await app.run(streams[0], streams[1], app.create_initialization_options()) - return SilentResponse() + return Response() starlette_app = Starlette( debug=True, diff --git a/examples/servers/simple-tool/mcp_simple_tool/server.py b/examples/servers/simple-tool/mcp_simple_tool/server.py index e9708906c..5b2b7d068 100644 --- a/examples/servers/simple-tool/mcp_simple_tool/server.py +++ b/examples/servers/simple-tool/mcp_simple_tool/server.py @@ -58,9 +58,9 @@ async def list_tools() -> list[types.Tool]: ] if transport == "sse": - from mcp.server.fastmcp.server import SilentResponse from mcp.server.sse import SseServerTransport from starlette.applications import Starlette + from starlette.responses import Response from starlette.routing import Mount, Route sse = SseServerTransport("/messages/") @@ -68,7 +68,7 @@ async def list_tools() -> list[types.Tool]: async def handle_sse(request: Request): async with sse.connect_sse(request.scope, request.receive, request._send) as streams: # type: ignore[reportPrivateUsage] await app.run(streams[0], streams[1], app.create_initialization_options()) - return SilentResponse() + return Response() starlette_app = Starlette( debug=True, diff --git a/src/mcp/server/sse.py b/src/mcp/server/sse.py index bcd2b547c..b7ff33280 100644 --- a/src/mcp/server/sse.py +++ b/src/mcp/server/sse.py @@ -23,7 +23,7 @@ async def handle_sse(request): streams[0], streams[1], app.create_initialization_options() ) # Return empty response to avoid NoneType error - return SilentResponse() + return Response() # Create and run Starlette app starlette_app = Starlette(routes=routes) diff --git a/tests/server/test_sse_security.py b/tests/server/test_sse_security.py index dd0be811e..43af35061 100644 --- a/tests/server/test_sse_security.py +++ b/tests/server/test_sse_security.py @@ -10,10 +10,10 @@ import uvicorn from starlette.applications import Starlette from starlette.requests import Request +from starlette.responses import Response from starlette.routing import Mount, Route from mcp.server import Server -from mcp.server.fastmcp.server import SilentResponse from mcp.server.sse import SseServerTransport from mcp.server.transport_security import TransportSecuritySettings from mcp.types import Tool @@ -55,7 +55,7 @@ async def handle_sse(request: Request): except ValueError as e: # Validation error was already handled inside connect_sse logger.debug(f"SSE connection failed validation: {e}") - return SilentResponse() + return Response() routes = [ Route("/sse", endpoint=handle_sse), diff --git a/tests/shared/test_sse.py b/tests/shared/test_sse.py index 08c0ae879..7b0d89cb4 100644 --- a/tests/shared/test_sse.py +++ b/tests/shared/test_sse.py @@ -20,7 +20,6 @@ from mcp.client.session import ClientSession from mcp.client.sse import sse_client from mcp.server import Server -from mcp.server.fastmcp.server import SilentResponse from mcp.server.sse import SseServerTransport from mcp.server.transport_security import TransportSecuritySettings from mcp.shared.exceptions import McpError @@ -93,7 +92,7 @@ def make_server_app() -> Starlette: async def handle_sse(request: Request) -> Response: async with sse.connect_sse(request.scope, request.receive, request._send) as streams: await server.run(streams[0], streams[1], server.create_initialization_options()) - return SilentResponse() + return Response() app = Starlette( routes=[ @@ -356,7 +355,7 @@ def run_context_server(server_port: int) -> None: async def handle_sse(request: Request) -> Response: async with sse.connect_sse(request.scope, request.receive, request._send) as streams: await context_server.run(streams[0], streams[1], context_server.create_initialization_options()) - return SilentResponse() + return Response() app = Starlette( routes=[ From a7014674f166474e533f48803f76df857391792a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E5=BE=90?= Date: Wed, 20 Aug 2025 19:44:56 +0800 Subject: [PATCH 7/8] fix typo --- src/mcp/server/fastmcp/server.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/mcp/server/fastmcp/server.py b/src/mcp/server/fastmcp/server.py index b8439788d..52bd558d6 100644 --- a/src/mcp/server/fastmcp/server.py +++ b/src/mcp/server/fastmcp/server.py @@ -737,7 +737,6 @@ def sse_app(self, mount_path: str | None = None) -> Starlette: async def handle_sse(request: Request) -> Response: """Handle SSE connection using Starlette's EventSourceResponse.""" - # Create a custom Response class that wraps the SSE connection class SSEConnectionResponse(Response): def __init__(self, sse_transport: SseServerTransport, server: MCPServer) -> None: super().__init__() @@ -791,7 +790,7 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: ) ) - # Create auth wrapper if needed + # When auth is configured, require authentication if self._token_verifier: # Determine resource metadata URL resource_metadata_url = None @@ -802,7 +801,7 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: str(self.settings.auth.resource_server_url).rstrip("/") + "/.well-known/oauth-protected-resource" ) - # # Auth is enabled, wrap the endpoints with RequireAuthMiddleware + # Auth is enabled, wrap the endpoints with RequireAuthMiddleware async def handle_sse_auth(scope: Scope, receive: Receive, send: Send) -> None: request = Request(scope, receive) response = await handle_sse(request) From 18d248b66dc1b6261e78372b0f9a69848866d33c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E5=BE=90?= Date: Wed, 20 Aug 2025 20:00:07 +0800 Subject: [PATCH 8/8] fix ruff check error --- src/mcp/server/fastmcp/server.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mcp/server/fastmcp/server.py b/src/mcp/server/fastmcp/server.py index 52bd558d6..00e4d0f8d 100644 --- a/src/mcp/server/fastmcp/server.py +++ b/src/mcp/server/fastmcp/server.py @@ -737,6 +737,7 @@ def sse_app(self, mount_path: str | None = None) -> Starlette: async def handle_sse(request: Request) -> Response: """Handle SSE connection using Starlette's EventSourceResponse.""" + class SSEConnectionResponse(Response): def __init__(self, sse_transport: SseServerTransport, server: MCPServer) -> None: super().__init__()