Fix UniFi OS authentication and simplify server architecture
All checks were successful
Build and Push Docker Image / build (push) Successful in 15s
All checks were successful
Build and Push Docker Image / build (push) Successful in 15s
- Use /api/auth/login for UniFi OS controllers (UDM, Cloud Gateway) - Use /api/login for standalone controllers - Refactor to use FastMCP's native mcp.run() with custom_route for /health - Switch to network_mode: host for local network access - Include README.md in Dockerfile for hatchling build
This commit is contained in:
45
server.py
45
server.py
@@ -11,18 +11,14 @@ Following the BLUEPRINT.md pattern:
|
||||
- Starlette wrapper with health endpoint
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import Any, Optional
|
||||
from typing import Optional
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from fastmcp import FastMCP
|
||||
from starlette.applications import Starlette
|
||||
from starlette.responses import JSONResponse
|
||||
from starlette.routing import Mount, Route
|
||||
|
||||
from api_docs import get_api_docs
|
||||
from unifi_client import UnifiClient, UnifiClientError, UnifiWriteBlockedError
|
||||
@@ -355,11 +351,14 @@ async def unifi_api_call(
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Starlette Wrapper with Health Endpoint
|
||||
# Health Check Endpoint (using FastMCP custom_route)
|
||||
# =============================================================================
|
||||
|
||||
from starlette.requests import Request
|
||||
|
||||
async def health_endpoint(request) -> JSONResponse:
|
||||
|
||||
@mcp.custom_route("/health", methods=["GET"])
|
||||
async def health_endpoint(request: Request) -> JSONResponse:
|
||||
"""
|
||||
Health check endpoint for Docker/Kubernetes.
|
||||
|
||||
@@ -386,9 +385,8 @@ async def health_endpoint(request) -> JSONResponse:
|
||||
)
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app):
|
||||
"""Application lifespan manager."""
|
||||
def main():
|
||||
"""Entry point for the server."""
|
||||
logger.info("Starting UniFi MCP Light server...")
|
||||
logger.info(f"Controller: {CONFIG['host']}:{CONFIG['port']}")
|
||||
logger.info(f"Site: {CONFIG['site']}")
|
||||
@@ -396,31 +394,8 @@ async def lifespan(app):
|
||||
f"Write operations: {'enabled' if CONFIG['allow_writes'] else 'disabled'}"
|
||||
)
|
||||
|
||||
yield
|
||||
|
||||
logger.info("Shutting down UniFi MCP Light server...")
|
||||
await close_client()
|
||||
|
||||
|
||||
def create_app() -> Starlette:
|
||||
"""Create the Starlette ASGI application."""
|
||||
mcp_app = mcp.http_app()
|
||||
|
||||
return Starlette(
|
||||
routes=[
|
||||
Route("/health", health_endpoint),
|
||||
Mount("/", app=mcp_app),
|
||||
],
|
||||
lifespan=lifespan,
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
"""Entry point for the server."""
|
||||
import uvicorn
|
||||
|
||||
app = create_app()
|
||||
uvicorn.run(app, host="0.0.0.0", port=8000)
|
||||
# Run with HTTP transport - MCP endpoint at /mcp, health at /health
|
||||
mcp.run(transport="http", host="0.0.0.0", port=8000)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user