feat: add MCP server with resources, tools, auth, and Traefik routing

- Add backend/app/mcp_server.py with FastMCP server (hms-cms)
- Resources: design-rules, page-structure, sync-status
- Tools: trigger_sync, get_sync_log, set_rentman_token, read_file,
  write_file, create_page, deploy, git_commit, git_status
- Bearer token auth via MCP_AUTH_TOKEN env var
- Mount MCP at /mcp with streamable HTTP transport
- Integrate session manager in FastAPI lifespan
- Add Traefik labels for external /mcp route on hms.media-on.de
- Add git, docker.io, curl to backend Dockerfile
- Mount repo root + docker socket in backend container
- Add mcp>=1.0.0 to requirements.txt
This commit is contained in:
Agent Zero
2026-07-12 15:58:22 +02:00
parent 00c23bc066
commit cd465e0564
124 changed files with 3309 additions and 225 deletions
+16
View File
@@ -9,6 +9,7 @@ from app.config import get_settings
from app.database import engine, init_db, async_session
from app.cache import cache
from app.routers import equipment, health, admin, rental_requests, contact
from app.mcp_server import get_mcp_app, mcp_session_manager
from app.services.sync_service import SyncService
from app.services.email_service import EmailService
@@ -16,6 +17,7 @@ logger = logging.getLogger(__name__)
settings = get_settings()
scheduler = AsyncIOScheduler()
_mcp_lifespan_cm = None # MCP session manager context manager
async def run_equipment_sync() -> None:
@@ -38,6 +40,7 @@ async def run_email_retry() -> None:
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Application lifespan: init DB, start scheduler, connect cache."""
global _mcp_lifespan_cm
# Create tables (for dev/testing; production uses Alembic)
await init_db()
@@ -62,9 +65,19 @@ async def lifespan(app: FastAPI):
scheduler.start()
logger.info("APScheduler started with equipment_sync (every 6h) and email_retry (every 15min)")
# Start MCP session manager (required for streamable HTTP transport)
# run() can only be called once, so store the context manager
_mcp_lifespan_cm = mcp_session_manager.run()
await _mcp_lifespan_cm.__aenter__()
logger.info("MCP session manager started")
yield
# Shutdown
# Stop MCP session manager
if _mcp_lifespan_cm:
await _mcp_lifespan_cm.__aexit__(None, None, None)
_mcp_lifespan_cm = None
scheduler.shutdown(wait=False)
await cache.disconnect()
await engine.dispose()
@@ -92,3 +105,6 @@ app.include_router(health.router)
app.include_router(admin.router)
app.include_router(rental_requests.router)
app.include_router(contact.router)
# MCP Server (streamable HTTP at /mcp)
app.mount("/mcp", get_mcp_app())