From 8fc4f00d278fab7ea2babad99178fe72dc7e1432 Mon Sep 17 00:00:00 2001 From: Ben Date: Sun, 28 Dec 2025 21:00:51 +0000 Subject: [PATCH] fix: properly initialize FastMCP lifespan in Starlette app FastMCP requires its lifespan context to be passed to the parent ASGI app to initialize the StreamableHTTPSessionManager task group. This fix nests mcp_app.lifespan() inside our custom lifespan to ensure proper initialization while maintaining our custom startup/shutdown logic. Resolves: RuntimeError: Task group is not initialized --- server.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/server.py b/server.py index b3a1cb7..1e32d7a 100644 --- a/server.py +++ b/server.py @@ -11,6 +11,7 @@ import json import logging import os import sys +from contextlib import asynccontextmanager from pathlib import Path from typing import Optional @@ -419,11 +420,15 @@ def create_app() -> Starlette: """Create the Starlette application wrapping the MCP server.""" mcp_app = mcp.http_app() - async def lifespan(app): - # Startup + # Combine our custom lifespan with MCP's lifespan + @asynccontextmanager + async def combined_lifespan(app): + # Our startup logic logger.info("Plex MCP Server starting up") - yield - # Shutdown + # Nest MCP's lifespan inside ours + async with mcp_app.lifespan(app): + yield + # Our shutdown logic logger.info("Plex MCP Server shutting down") await plex_client.close() @@ -432,7 +437,7 @@ def create_app() -> Starlette: Route("/health", health_check), Mount("/", app=mcp_app), ], - lifespan=lifespan, + lifespan=combined_lifespan, )