"""MCP-side Bearer token resolution. Reuses the existing api_keys infrastructure.""" from __future__ import annotations from scribe.services.api_keys import lookup_key async def resolve_bearer(auth_header: str | None) -> tuple[int, str] | None: """Resolve a Bearer token to (user_id, scope). scope is 'read' or 'write'. Returns None for a missing/malformed/invalid token. The MCP dispatch layer uses scope to deny write-class tool calls from read-only keys — the same read/write boundary the REST API enforces. """ if not auth_header or not auth_header.startswith("Bearer "): return None raw_token = auth_header[len("Bearer "):].strip() if not raw_token: return None api_key = await lookup_key(raw_token) if api_key is None: return None return api_key.user_id, (api_key.scope or "write")