From 376e129c14c557f23af6c58fd17a7ba6d5c3717a Mon Sep 17 00:00:00 2001 From: Pawit A Date: Mon, 7 Apr 2025 20:38:13 +0700 Subject: [PATCH 1/4] Refactor FastMCP to update message path for SSE handling --- src/mcp/server/fastmcp/server.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mcp/server/fastmcp/server.py b/src/mcp/server/fastmcp/server.py index bf0ce880a..6356e9e68 100644 --- a/src/mcp/server/fastmcp/server.py +++ b/src/mcp/server/fastmcp/server.py @@ -497,7 +497,8 @@ async def handle_sse(request: Request) -> None: debug=self.settings.debug, routes=[ Route(self.settings.sse_path, endpoint=handle_sse), - Mount(self.settings.message_path, app=sse.handle_post_message), + # Mount(self.settings.message_path, app=sse.handle_post_message), + Mount("/messages/", app=sse.handle_post_message), ], ) From 2c3b5e37215362c0d6f23d480151a23b0e051def Mon Sep 17 00:00:00 2001 From: Pawit A Date: Mon, 7 Apr 2025 21:10:23 +0700 Subject: [PATCH 2/4] Enhance SSE server transport to support base path configuration --- src/mcp/server/fastmcp/server.py | 6 +++--- src/mcp/server/sse.py | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/mcp/server/fastmcp/server.py b/src/mcp/server/fastmcp/server.py index 6356e9e68..15bbea1fe 100644 --- a/src/mcp/server/fastmcp/server.py +++ b/src/mcp/server/fastmcp/server.py @@ -75,6 +75,7 @@ class Settings(BaseSettings, Generic[LifespanResultT]): port: int = 8000 sse_path: str = "/sse" message_path: str = "/messages/" + base_path: str = "/" # resource settings warn_on_duplicate_resources: bool = True @@ -479,7 +480,7 @@ async def run_sse_async(self) -> None: def sse_app(self) -> Starlette: """Return an instance of the SSE server app.""" - sse = SseServerTransport(self.settings.message_path) + sse = SseServerTransport(self.settings.message_path, self.settings.base_path) async def handle_sse(request: Request) -> None: async with sse.connect_sse( @@ -497,8 +498,7 @@ async def handle_sse(request: Request) -> None: debug=self.settings.debug, routes=[ Route(self.settings.sse_path, endpoint=handle_sse), - # Mount(self.settings.message_path, app=sse.handle_post_message), - Mount("/messages/", app=sse.handle_post_message), + Mount(self.settings.message_path, app=sse.handle_post_message), ], ) diff --git a/src/mcp/server/sse.py b/src/mcp/server/sse.py index d051c25bf..148a48219 100644 --- a/src/mcp/server/sse.py +++ b/src/mcp/server/sse.py @@ -67,7 +67,7 @@ class SseServerTransport: UUID, MemoryObjectSendStream[types.JSONRPCMessage | Exception] ] - def __init__(self, endpoint: str) -> None: + def __init__(self, endpoint: str, base_path: str) -> None: """ Creates a new SSE server transport, which will direct the client to POST messages to the relative or absolute URL given. @@ -75,6 +75,7 @@ def __init__(self, endpoint: str) -> None: super().__init__() self._endpoint = endpoint + self._base_path = base_path self._read_stream_writers = {} logger.debug(f"SseServerTransport initialized with endpoint: {endpoint}") @@ -96,6 +97,7 @@ async def connect_sse(self, scope: Scope, receive: Receive, send: Send): session_id = uuid4() session_uri = f"{quote(self._endpoint)}?session_id={session_id.hex}" + session_full_url = f"{self._base_path}{session_uri}" self._read_stream_writers[session_id] = read_stream_writer logger.debug(f"Created new session with ID: {session_id}") @@ -106,8 +108,8 @@ async def connect_sse(self, scope: Scope, receive: Receive, send: Send): async def sse_writer(): logger.debug("Starting SSE writer") async with sse_stream_writer, write_stream_reader: - await sse_stream_writer.send({"event": "endpoint", "data": session_uri}) - logger.debug(f"Sent endpoint event: {session_uri}") + await sse_stream_writer.send({"event": "endpoint", "data": session_full_url}) + logger.debug(f"Sent endpoint event: {session_full_url}") async for message in write_stream_reader: logger.debug(f"Sending message via SSE: {message}") From c6811a708105e3b41af1317a1d62c4a808d3487e Mon Sep 17 00:00:00 2001 From: Pawit A Date: Mon, 7 Apr 2025 21:13:12 +0700 Subject: [PATCH 3/4] Fix SSE server transport to correctly join base path and endpoint for session URL --- src/mcp/server/sse.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mcp/server/sse.py b/src/mcp/server/sse.py index 148a48219..dfe0890a2 100644 --- a/src/mcp/server/sse.py +++ b/src/mcp/server/sse.py @@ -36,6 +36,7 @@ async def handle_sse(request): from typing import Any from urllib.parse import quote from uuid import UUID, uuid4 +import os import anyio from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream @@ -97,7 +98,8 @@ async def connect_sse(self, scope: Scope, receive: Receive, send: Send): session_id = uuid4() session_uri = f"{quote(self._endpoint)}?session_id={session_id.hex}" - session_full_url = f"{self._base_path}{session_uri}" + # join the base path and endpoint + session_full_url = os.path.join(self._base_path, session_uri.replace("$/", "")) self._read_stream_writers[session_id] = read_stream_writer logger.debug(f"Created new session with ID: {session_id}") From 451c35afafbb690ffb1c994cf20d8d977b6b4958 Mon Sep 17 00:00:00 2001 From: Pawit A Date: Mon, 7 Apr 2025 21:31:04 +0700 Subject: [PATCH 4/4] Fix SSE server transport to correctly handle leading slashes in session URL --- src/mcp/server/sse.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mcp/server/sse.py b/src/mcp/server/sse.py index dfe0890a2..bb0911cc4 100644 --- a/src/mcp/server/sse.py +++ b/src/mcp/server/sse.py @@ -37,6 +37,7 @@ async def handle_sse(request): from urllib.parse import quote from uuid import UUID, uuid4 import os +import re import anyio from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream @@ -99,7 +100,7 @@ async def connect_sse(self, scope: Scope, receive: Receive, send: Send): session_id = uuid4() session_uri = f"{quote(self._endpoint)}?session_id={session_id.hex}" # join the base path and endpoint - session_full_url = os.path.join(self._base_path, session_uri.replace("$/", "")) + session_full_url = os.path.join(self._base_path, re.sub("^/", "", session_uri, 1)) self._read_stream_writers[session_id] = read_stream_writer logger.debug(f"Created new session with ID: {session_id}")