""" MCP-Authentifizierung – Token-basierte Authentifizierung mit 3 Rollen. Tokens werden über Umgebungsvariablen konfiguriert: MCP_TOKEN_READONLY – Nur-Lese-Zugriff (alle Daten, PII maskiert) MCP_TOKEN_EDITOR – Lesen + Schreiben (PII maskiert) MCP_TOKEN_ADMIN – Voll-Zugriff (keine PII-Maskierung, alle Schreib-Ops) Das aktive Token wird per MCP_AUTH_TOKEN übergeben (wird vom MCP-Client gesetzt). """ import os ROLE_READONLY = "readonly" ROLE_EDITOR = "editor" ROLE_ADMIN = "admin" # Rollenrangfolge (höher = mehr Rechte) ROLE_RANK = {ROLE_READONLY: 1, ROLE_EDITOR: 2, ROLE_ADMIN: 3} def _token_map() -> dict[str, str]: """Erstellt Mapping token → Rolle aus Umgebungsvariablen.""" mapping: dict[str, str] = {} for role, env_var in [ (ROLE_READONLY, "MCP_TOKEN_READONLY"), (ROLE_EDITOR, "MCP_TOKEN_EDITOR"), (ROLE_ADMIN, "MCP_TOKEN_ADMIN"), ]: token = os.environ.get(env_var, "").strip() if token: mapping[token] = role return mapping def get_role_for_token(token: str) -> str | None: """ Gibt die Rolle für einen Token zurück oder None bei ungültigem Token. """ if not token: return None return _token_map().get(token) def get_current_role() -> str | None: """ Gibt die Rolle des aktuell gesetzten MCP_AUTH_TOKEN zurück. Wird vom Server beim Start einmalig ausgewertet. """ token = os.environ.get("MCP_AUTH_TOKEN", "").strip() return get_role_for_token(token) def can_write(role: str | None) -> bool: """Darf die Rolle Schreiboperationen ausführen?""" return role in (ROLE_EDITOR, ROLE_ADMIN) def can_read_unmasked(role: str | None) -> bool: """Darf die Rolle ungemaskierte PII-Daten lesen?""" return role == ROLE_ADMIN def require_role(role: str | None) -> None: """Wirft ValueError wenn keine gültige Rolle vorhanden.""" if not role: raise ValueError( "Ungültiger oder fehlender MCP_AUTH_TOKEN. " "Bitte MCP_AUTH_TOKEN-Umgebungsvariable setzen." )