From 98f5a14f69f46bbc0858775324ad704bf29cbc98 Mon Sep 17 00:00:00 2001 From: donbr Date: Sat, 6 Dec 2025 23:59:23 -0800 Subject: [PATCH] Add lifespan context manager for FastMCP Cloud initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FastMCP Cloud does not execute the if __name__ == '__main__' block, so the Graphiti service was never initialized. This adds a lifespan context manager that FastMCP uses for server startup/shutdown. The lifespan: - Loads configuration from environment variables - Initializes GraphitiService and QueueService - Connects to the database (Neo4j/FalkorDB) - Sets up global clients for tool access 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- mcp_server/src/graphiti_mcp_server.py | 50 +++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/mcp_server/src/graphiti_mcp_server.py b/mcp_server/src/graphiti_mcp_server.py index 215651b1..a314e6a2 100644 --- a/mcp_server/src/graphiti_mcp_server.py +++ b/mcp_server/src/graphiti_mcp_server.py @@ -8,6 +8,7 @@ import asyncio import logging import os import sys +from contextlib import asynccontextmanager from pathlib import Path from typing import Any, Optional @@ -328,6 +329,55 @@ class GraphitiService: return self.client +@asynccontextmanager +async def graphiti_lifespan(app): + """Lifespan context manager for FastMCP Cloud deployment. + + This function initializes the Graphiti service when the server starts. + FastMCP Cloud calls this automatically - it does NOT run the if __name__ == '__main__' block. + """ + global config, graphiti_service, queue_service, graphiti_client, semaphore + + logger.info('Initializing Graphiti service via lifespan...') + + try: + # Load configuration from environment variables (FastMCP Cloud sets these) + config = GraphitiConfig() + + # Log configuration details + logger.info('Using configuration:') + logger.info(f' - LLM: {config.llm.provider} / {config.llm.model}') + logger.info(f' - Embedder: {config.embedder.provider} / {config.embedder.model}') + logger.info(f' - Database: {config.database.provider}') + logger.info(f' - Group ID: {config.graphiti.group_id}') + + # Initialize services + graphiti_service = GraphitiService(config, SEMAPHORE_LIMIT) + queue_service = QueueService() + await graphiti_service.initialize() + + # Set global client for backward compatibility + graphiti_client = await graphiti_service.get_client() + semaphore = graphiti_service.semaphore + + # Initialize queue service with the client + await queue_service.initialize(graphiti_client) + + logger.info('Graphiti service initialized successfully via lifespan') + + yield # Server runs here + + except Exception as e: + logger.error(f'Failed to initialize Graphiti service: {e}') + raise + finally: + logger.info('Shutting down Graphiti service...') + + +# Update the MCP server to use the lifespan +mcp.lifespan = graphiti_lifespan + + @mcp.tool() async def add_memory( name: str,