from contextvars import ContextVar from starlette.responses import JSONResponse principal = ContextVar("firegex_mcp_principal", default=None) ROLES = {"observer": 0, "operator": 1, "admin": 2} class MCPError(Exception): def __init__(self, code, message, **details): super().__init__(message) self.data = {"code": code, "message": message, **details} def require(role="observer"): user = principal.get() if not user or ROLES.get(user["role"], -1) < ROLES[role]: raise MCPError("FORBIDDEN", f"This operation requires the {role} role") return user class BearerMiddleware: """Authentication independent of the UI's password/unsafe-disable-auth setting.""" def __init__(self, app, store): self.app, self.store = app, store async def __call__(self, scope, receive, send): if scope["type"] != "http": await self.app(scope, receive, send) return headers = dict(scope.get("headers", [])) raw = headers.get(b"authorization", b"").decode("latin1") user = self.store.token_verify(raw[7:]) if raw.lower().startswith("bearer ") else None if user is None: await JSONResponse({"error": "Invalid, expired or revoked MCP token"}, status_code=401, headers={"WWW-Authenticate": 'Bearer realm="firegex-mcp"'})(scope, receive, send) return marker = principal.set(user) try: await self.app(scope, receive, send) finally: principal.reset(marker)