1
1
import logging
2
2
3
3
from fastapi import Request , Response , HTTPException
4
+ from mcp .server .lowlevel .server import Server
4
5
from mcp .server .streamable_http import StreamableHTTPServerTransport
5
6
from mcp .server .transport_security import TransportSecuritySettings
6
7
@@ -14,6 +15,7 @@ def __init__(
14
15
is_json_response_enabled : bool = True , # Default to JSON for HTTP transport
15
16
event_store = None ,
16
17
security_settings : TransportSecuritySettings | None = None ,
18
+ mcp_server : Server | None = None ,
17
19
):
18
20
super ().__init__ (
19
21
mcp_session_id = mcp_session_id ,
@@ -22,8 +24,10 @@ def __init__(
22
24
security_settings = security_settings ,
23
25
)
24
26
logger .debug (f"FastApiStreamableHttpTransport initialized with session_id: { mcp_session_id } " )
27
+ self ._mcp_server = mcp_server
28
+ self ._server_running = False
25
29
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 :
27
31
"""
28
32
The approach here is different from FastApiSseTransport.
29
33
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:
37
41
"""
38
42
logger .debug (f"Handling FastAPI request: { request .method } { request .url .path } " )
39
43
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
+
40
71
# Capture the response from the SDK's handle_request method
41
72
response_started = False
42
73
response_status = 200
0 commit comments