feat: add /health endpoint and switch to Streamable HTTP transport
All checks were successful
Build and Push Komodo MCP Docker Image / build (push) Successful in 14s
All checks were successful
Build and Push Komodo MCP Docker Image / build (push) Successful in 14s
- Switch from legacy SSE transport (sse_app) to Streamable HTTP (http_app)
- Fixes 405 Method Not Allowed for MCP clients like Gemini CLI
- MCP endpoint now at /mcp (POST) instead of /sse (GET)
- Add /health endpoint that bypasses MCP_ALLOWED_HOSTS validation
- Returns {"status": "ok"} (200) or {"status": "degraded"} (503)
- Enables Docker health checks without exposing to external hosts
- Add curl to Docker image for health checks
- Add healthcheck config to docker-compose files
- Add test-health and test-mcp Makefile targets
- Update documentation
This commit is contained in:
35
server.py
35
server.py
@@ -3,6 +3,9 @@ import logging
|
||||
import httpx
|
||||
from mcp.server.fastmcp import FastMCP
|
||||
from mcp.server.transport_security import TransportSecuritySettings
|
||||
from starlette.applications import Starlette
|
||||
from starlette.responses import JSONResponse
|
||||
from starlette.routing import Route, Mount
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Load environment variables
|
||||
@@ -225,6 +228,36 @@ def komodo_api_call(
|
||||
return method(request_type, params or {})
|
||||
|
||||
|
||||
# --- Health Check Endpoint ---
|
||||
# This bypasses MCP_ALLOWED_HOSTS for Docker health checks
|
||||
async def health(request):
|
||||
"""Health check endpoint - bypasses transport security."""
|
||||
# Optionally verify Komodo connectivity
|
||||
client, error = _get_client()
|
||||
if error:
|
||||
return JSONResponse({"status": "degraded", "error": error["error"]}, status_code=503)
|
||||
return JSONResponse({"status": "ok"})
|
||||
|
||||
|
||||
# --- ASGI Application ---
|
||||
def create_app():
|
||||
"""Create the ASGI application with health check and MCP routes."""
|
||||
mcp_app = mcp.http_app()
|
||||
|
||||
# Wrapper app: /health bypasses security, everything else goes to MCP
|
||||
routes = [
|
||||
Route("/health", health, methods=["GET"]),
|
||||
Mount("/", app=mcp_app), # MCP handles /mcp endpoint
|
||||
]
|
||||
|
||||
return Starlette(routes=routes)
|
||||
|
||||
|
||||
# Create the app instance for uvicorn
|
||||
app = create_app()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
uvicorn.run(mcp.sse_app, host="0.0.0.0", port=8000)
|
||||
# Run the wrapper app (includes /health and /mcp endpoints)
|
||||
uvicorn.run(app, host="0.0.0.0", port=8000)
|
||||
|
||||
Reference in New Issue
Block a user