7935b671d3
Exposes homelab topology to MCP-compatible AI clients (Claude Code, etc.) over LAN via HTTP/SSE on port 8001. - New mcp/ service: FastAPI + mcp SDK, SSE transport - Auth: X-API-Key for AI clients, X-MCP-Service-Key for backend (Docker-internal) - Resources: canvas, nodes, edges, scan/pending, scan/runs - Tools: create/update/delete nodes+edges, trigger scan, approve/hide devices - Backend deps.py: accepts JWT or MCP service key (no plain-text password) - 40 tests (auth, resources, tools) across asyncio + trio - docker-compose.yml: mcp service on port 8001 - README: MCP setup section with Claude Code/Desktop config examples
32 lines
1.3 KiB
Python
32 lines
1.3 KiB
Python
import hmac
|
|
|
|
from fastapi import Depends, Header, HTTPException, Request, status
|
|
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
|
|
|
from app.core.config import settings
|
|
from app.core.security import decode_token
|
|
|
|
bearer = HTTPBearer(auto_error=False)
|
|
|
|
|
|
def get_current_user(
|
|
request: Request,
|
|
credentials: HTTPAuthorizationCredentials | None = Depends(bearer),
|
|
x_mcp_service_key: str | None = Header(default=None),
|
|
) -> str:
|
|
# 1. MCP service key (Docker-internal only — backend port is not externally exposed)
|
|
if x_mcp_service_key is not None:
|
|
if not settings.mcp_service_key:
|
|
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="MCP service key not configured")
|
|
if not hmac.compare_digest(x_mcp_service_key.encode(), settings.mcp_service_key.encode()):
|
|
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid MCP service key")
|
|
return "__mcp_service__"
|
|
|
|
# 2. Standard JWT bearer token
|
|
if credentials is None:
|
|
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Not authenticated")
|
|
username = decode_token(credentials.credentials)
|
|
if not username:
|
|
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token")
|
|
return username
|