fix: properly initialize FastMCP lifespan in Starlette app
All checks were successful
Build and Push Plex MCP Docker Image / build (push) Successful in 8s

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
This commit is contained in:
Ben
2025-12-28 21:00:51 +00:00
parent 5782ca3ea3
commit 8fc4f00d27

View File

@@ -11,6 +11,7 @@ import json
import logging import logging
import os import os
import sys import sys
from contextlib import asynccontextmanager
from pathlib import Path from pathlib import Path
from typing import Optional from typing import Optional
@@ -419,11 +420,15 @@ def create_app() -> Starlette:
"""Create the Starlette application wrapping the MCP server.""" """Create the Starlette application wrapping the MCP server."""
mcp_app = mcp.http_app() mcp_app = mcp.http_app()
async def lifespan(app): # Combine our custom lifespan with MCP's lifespan
# Startup @asynccontextmanager
async def combined_lifespan(app):
# Our startup logic
logger.info("Plex MCP Server starting up") logger.info("Plex MCP Server starting up")
yield # Nest MCP's lifespan inside ours
# Shutdown async with mcp_app.lifespan(app):
yield
# Our shutdown logic
logger.info("Plex MCP Server shutting down") logger.info("Plex MCP Server shutting down")
await plex_client.close() await plex_client.close()
@@ -432,7 +437,7 @@ def create_app() -> Starlette:
Route("/health", health_check), Route("/health", health_check),
Mount("/", app=mcp_app), Mount("/", app=mcp_app),
], ],
lifespan=lifespan, lifespan=combined_lifespan,
) )