Add lifespan context manager for FastMCP Cloud initialization

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 <noreply@anthropic.com>
This commit is contained in:
donbr 2025-12-06 23:59:23 -08:00
parent 83f03aefc9
commit 98f5a14f69

View file

@ -8,6 +8,7 @@ import asyncio
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 Any, Optional from typing import Any, Optional
@ -328,6 +329,55 @@ class GraphitiService:
return self.client 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() @mcp.tool()
async def add_memory( async def add_memory(
name: str, name: str,