@@ -175,6 +175,7 @@ def __init__(
175
175
self ._event_store = event_store
176
176
self ._custom_starlette_routes : list [Route ] = []
177
177
self .dependencies = self .settings .dependencies
178
+ self ._session_manager : StreamableHTTPSessionManager | None = None
178
179
179
180
# Set up MCP protocol handlers
180
181
self ._setup_handlers ()
@@ -190,6 +191,25 @@ def name(self) -> str:
190
191
def instructions (self ) -> str | None :
191
192
return self ._mcp_server .instructions
192
193
194
+ @property
195
+ def session_manager (self ) -> StreamableHTTPSessionManager :
196
+ """Get the StreamableHTTP session manager.
197
+
198
+ This is exposed to enable advanced use cases like mounting multiple
199
+ FastMCP servers in a single FastAPI application.
200
+
201
+ Raises:
202
+ RuntimeError: If called before streamable_http_app() has been called.
203
+ """
204
+ if self ._session_manager is None :
205
+ raise RuntimeError (
206
+ "Session manager can only be accessed after"
207
+ "calling streamable_http_app()."
208
+ "The session manager is created lazily"
209
+ "to avoid unnecessary initialization."
210
+ )
211
+ return self ._session_manager
212
+
193
213
def run (
194
214
self ,
195
215
transport : Literal ["stdio" , "sse" , "streamable-http" ] = "stdio" ,
@@ -746,19 +766,20 @@ def streamable_http_app(self) -> Starlette:
746
766
from starlette .middleware import Middleware
747
767
from starlette .routing import Mount
748
768
749
- # Create session manager using the provided event store
750
- session_manager = StreamableHTTPSessionManager (
751
- app = self ._mcp_server ,
752
- event_store = self ._event_store ,
753
- json_response = self .settings .json_response ,
754
- stateless = self .settings .stateless_http , # Use the stateless setting
755
- )
769
+ # Create session manager on first call (lazy initialization)
770
+ if self ._session_manager is None :
771
+ self ._session_manager = StreamableHTTPSessionManager (
772
+ app = self ._mcp_server ,
773
+ event_store = self ._event_store ,
774
+ json_response = self .settings .json_response ,
775
+ stateless = self .settings .stateless_http , # Use the stateless setting
776
+ )
756
777
757
778
# Create the ASGI handler
758
779
async def handle_streamable_http (
759
780
scope : Scope , receive : Receive , send : Send
760
781
) -> None :
761
- await session_manager .handle_request (scope , receive , send )
782
+ await self . session_manager .handle_request (scope , receive , send )
762
783
763
784
# Create routes
764
785
routes : list [Route | Mount ] = []
@@ -807,12 +828,11 @@ async def handle_streamable_http(
807
828
808
829
routes .extend (self ._custom_starlette_routes )
809
830
810
- # Create Starlette app with routes and middleware
811
831
return Starlette (
812
832
debug = self .settings .debug ,
813
833
routes = routes ,
814
834
middleware = middleware ,
815
- lifespan = lambda app : session_manager .run (),
835
+ lifespan = lambda app : self . session_manager .run (),
816
836
)
817
837
818
838
async def list_prompts (self ) -> list [MCPPrompt ]:
0 commit comments