Add /health endpoint for Docker healthchecks

- Create wrapper Starlette app with health route + FastMCP mount
- Pass FastMCP lifespan to parent app for proper session management
- Health returns JSON with status, version, timestamp, transport
- Use uvicorn directly for better ASGI integration
This commit is contained in:
Ryan Malloy 2026-01-11 15:55:35 -07:00
parent 322ed78427
commit 2e8517c62d

View File

@ -12,6 +12,7 @@ Architecture uses official FastMCP MCPMixin pattern for clean separation of conc
import os import os
import tempfile import tempfile
from datetime import datetime, timezone
from fastmcp import FastMCP from fastmcp import FastMCP
from fastmcp.prompts import Prompt from fastmcp.prompts import Prompt
@ -568,6 +569,11 @@ def main():
if transport == "streamable-http": if transport == "streamable-http":
# HTTP transport for hosted/Docker mode # HTTP transport for hosted/Docker mode
import uvicorn
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route, Mount
host = os.environ.get("MCP_HOST", "0.0.0.0") host = os.environ.get("MCP_HOST", "0.0.0.0")
port = int(os.environ.get("MCP_PORT", "8000")) port = int(os.environ.get("MCP_PORT", "8000"))
@ -577,17 +583,37 @@ def main():
except Exception: except Exception:
pkg_version = "0.1.0" pkg_version = "0.1.0"
# Health check endpoint
async def health_check(request):
return JSONResponse({
"status": "healthy",
"service": "mcwaddams",
"version": pkg_version,
"timestamp": datetime.now(timezone.utc).isoformat(),
"transport": "streamable-http",
})
# Get FastMCP's HTTP app
mcp_app = app.http_app()
# Create wrapper app with health endpoint + MCP routes
# IMPORTANT: Must pass mcp_app.lifespan to initialize task groups
wrapper_app = Starlette(
routes=[
Route("/health", health_check, methods=["GET"]),
Mount("/", app=mcp_app), # Mount MCP at root (serves /mcp)
],
lifespan=mcp_app.lifespan, # Required for FastMCP session management
)
print(f"🖨️ mcwaddams v{pkg_version}") print(f"🖨️ mcwaddams v{pkg_version}")
print(f"📋 MCP Office Tools - Document Extraction Server") print(f"📋 MCP Office Tools - Document Extraction Server")
print(f"🌐 Starting streamable-http transport on {host}:{port}") print(f"🌐 Starting streamable-http transport on {host}:{port}")
print(f" Endpoint: http://{host}:{port}/mcp") print(f" Endpoint: http://{host}:{port}/mcp")
print(f" Health: http://{host}:{port}/health")
print() print()
app.run( uvicorn.run(wrapper_app, host=host, port=port, log_level="info")
transport="streamable-http",
host=host,
port=port,
)
else: else:
# Default stdio transport for local CLI usage # Default stdio transport for local CLI usage
# CRITICAL: show_banner=False is required for stdio transport! # CRITICAL: show_banner=False is required for stdio transport!