11import logging
22
33from fastapi import Request , Response , HTTPException
4+ from mcp .server .lowlevel .server import Server
45from mcp .server .streamable_http import StreamableHTTPServerTransport
56from mcp .server .transport_security import TransportSecuritySettings
67
@@ -14,6 +15,7 @@ def __init__(
1415 is_json_response_enabled : bool = True , # Default to JSON for HTTP transport
1516 event_store = None ,
1617 security_settings : TransportSecuritySettings | None = None ,
18+ mcp_server : Server | None = None ,
1719 ):
1820 super ().__init__ (
1921 mcp_session_id = mcp_session_id ,
@@ -22,8 +24,10 @@ def __init__(
2224 security_settings = security_settings ,
2325 )
2426 logger .debug (f"FastApiStreamableHttpTransport initialized with session_id: { mcp_session_id } " )
27+ self ._mcp_server = mcp_server
28+ self ._server_running = False
2529
26- async def handle_fastapi_request (self , request : Request ) -> Response :
30+ async def handle_fastapi_request (self , request : Request , mcp_server : Server | None = None ) -> Response :
2731 """
2832 The approach here is different from FastApiSseTransport.
2933 In FastApiSseTransport, we reimplement the SSE transport logic to have a more FastAPI-native transport.
@@ -37,6 +41,33 @@ async def handle_fastapi_request(self, request: Request) -> Response:
3741 """
3842 logger .debug (f"Handling FastAPI request: { request .method } { request .url .path } " )
3943
44+ # Use the stored server if available, or the passed one
45+ server = self ._mcp_server or mcp_server
46+ if not server :
47+ raise HTTPException (status_code = 500 , detail = "No MCP server available" )
48+
49+ # Initialize the transport if not already done
50+ if not self ._server_running :
51+ import anyio
52+
53+ async def start_server ():
54+ self ._server_running = True
55+ async with self .connect () as (reader , writer ):
56+ await server .run (
57+ reader ,
58+ writer ,
59+ server .create_initialization_options (notification_options = None , experimental_capabilities = {}),
60+ raise_exceptions = False ,
61+ )
62+
63+ # Start the server in a background task
64+ import asyncio
65+
66+ asyncio .create_task (start_server ())
67+
68+ # Give the server a moment to initialize
69+ await anyio .sleep (0.1 )
70+
4071 # Capture the response from the SDK's handle_request method
4172 response_started = False
4273 response_status = 200
0 commit comments