fleet-memory/hindsight-api/hindsight_api/api/__init__.py
Nicolò Boschi 76fd052b3a
misc: add mcp integration tests and increase test coverage (#98)
* misc: add mcp integration tests and increase test coverage

* misc: add mcp integration tests and increase test coverage

* misc: add mcp integration tests and increase test coverage
2026-01-05 11:16:55 +01:00

126 lines
3.8 KiB
Python

"""
Unified API module for Hindsight.
Provides both HTTP REST API and MCP (Model Context Protocol) server.
"""
import logging
from contextlib import asynccontextmanager
from typing import Optional
from fastapi import FastAPI
from hindsight_api import MemoryEngine
logger = logging.getLogger(__name__)
def create_app(
memory: MemoryEngine,
http_api_enabled: bool = True,
mcp_api_enabled: bool = False,
mcp_mount_path: str = "/mcp",
initialize_memory: bool = True,
) -> FastAPI:
"""
Create and configure the unified Hindsight API application.
Args:
memory: MemoryEngine instance (already initialized with required parameters).
Migrations are controlled by the MemoryEngine's run_migrations parameter.
http_api_enabled: Whether to enable HTTP REST API endpoints (default: True)
mcp_api_enabled: Whether to enable MCP server (default: False)
mcp_mount_path: Path to mount MCP server (default: /mcp)
initialize_memory: Whether to initialize memory system on startup (default: True)
Returns:
Configured FastAPI application with enabled APIs
Example:
# HTTP only
app = create_app(memory)
# MCP only
app = create_app(memory, http_api_enabled=False, mcp_api_enabled=True)
# Both HTTP and MCP
app = create_app(memory, mcp_api_enabled=True)
"""
mcp_app = None
# Create MCP app first if enabled (we need its lifespan for chaining)
if mcp_api_enabled:
try:
from .mcp import create_mcp_app
mcp_app = create_mcp_app(memory=memory)
except ImportError as e:
logger.error(f"MCP server requested but dependencies not available: {e}")
logger.error("Install with: pip install hindsight-api[mcp]")
raise
# Import and create HTTP API if enabled
if http_api_enabled:
from .http import create_app as create_http_app
app = create_http_app(memory=memory, initialize_memory=initialize_memory)
logger.info("HTTP REST API enabled")
else:
# Create minimal FastAPI app
app = FastAPI(title="Hindsight API", version="0.0.7")
logger.info("HTTP REST API disabled")
# Mount MCP server and chain its lifespan if enabled
if mcp_app is not None:
# Get the MCP app's underlying Starlette app for lifespan access
mcp_starlette_app = mcp_app.mcp_app
# Store the original lifespan
original_lifespan = app.router.lifespan_context
@asynccontextmanager
async def chained_lifespan(app_instance: FastAPI):
"""Chain the MCP lifespan with the main app lifespan."""
# Start MCP lifespan first
async with mcp_starlette_app.router.lifespan_context(mcp_starlette_app):
logger.info("MCP lifespan started")
# Then start the original app lifespan
async with original_lifespan(app_instance):
yield
logger.info("MCP lifespan stopped")
# Replace the app's lifespan with the chained version
app.router.lifespan_context = chained_lifespan
# Mount the MCP middleware
app.mount(mcp_mount_path, mcp_app)
logger.info(f"MCP server enabled at {mcp_mount_path}/")
return app
# Re-export commonly used items for backwards compatibility
from .http import (
CreateBankRequest,
DispositionTraits,
MemoryItem,
RecallRequest,
RecallResponse,
RecallResult,
ReflectRequest,
ReflectResponse,
RetainRequest,
)
__all__ = [
"create_app",
"RecallRequest",
"RecallResult",
"RecallResponse",
"MemoryItem",
"RetainRequest",
"ReflectRequest",
"ReflectResponse",
"CreateBankRequest",
"DispositionTraits",
]