diff --git a/surfsense_mcp/src/surfsense_mcp/core/auth/headers.py b/surfsense_mcp/src/surfsense_mcp/core/auth/headers.py index c06989909..3bca45967 100644 --- a/surfsense_mcp/src/surfsense_mcp/core/auth/headers.py +++ b/surfsense_mcp/src/surfsense_mcp/core/auth/headers.py @@ -1,8 +1,6 @@ -"""Extraction of a SurfSense API key from request headers. +"""Extract a SurfSense API key from request headers. -Pure and side-effect free: given the request headers, return the caller's key -or ``None``. Isolated from transport and state so the parsing rules stay -trivially unit-testable. +Pure header parsing, kept separate from transport and state. """ from __future__ import annotations diff --git a/surfsense_mcp/src/surfsense_mcp/core/auth/identity.py b/surfsense_mcp/src/surfsense_mcp/core/auth/identity.py index 5f242e94e..0c8f6b315 100644 --- a/surfsense_mcp/src/surfsense_mcp/core/auth/identity.py +++ b/surfsense_mcp/src/surfsense_mcp/core/auth/identity.py @@ -1,12 +1,9 @@ """Request-scoped caller identity. -Over streamable-http one process serves many users, so the caller's key lives -in a contextvar for the life of a single request: the auth middleware binds it, -and the client reads it when building the outbound backend call. Under stdio -there is no request, the contextvar stays empty, and the env key is used. - -The contextvar is request-scoped, not stored state — it is re-derived from the -header on every request, which is what keeps the server stateless. +Over streamable-http one process serves many users, so the caller's key lives in +a contextvar for the life of a request: the auth middleware binds it and the +client reads it when calling the backend. Under stdio there is no request, so the +contextvar is empty and the env key is used instead. """ from __future__ import annotations @@ -24,7 +21,6 @@ def bind_api_key(api_key: str | None) -> Token: def unbind_api_key(token: Token) -> None: - """Release the binding once the request is done.""" _api_key.reset(token) @@ -34,9 +30,5 @@ def current_api_key() -> str | None: def current_identity() -> str: - """Stable per-caller key for scoping request state. - - The token identifies the account, so state keyed on it is naturally - per-user and survives reconnects. Under stdio all calls share one identity. - """ + """Stable per-caller key for scoping request state; shared under stdio.""" return _api_key.get() or _LOCAL_IDENTITY diff --git a/surfsense_mcp/src/surfsense_mcp/core/auth/middleware.py b/surfsense_mcp/src/surfsense_mcp/core/auth/middleware.py index 2f2356ad7..354ae0a89 100644 --- a/surfsense_mcp/src/surfsense_mcp/core/auth/middleware.py +++ b/surfsense_mcp/src/surfsense_mcp/core/auth/middleware.py @@ -2,8 +2,8 @@ A pure ASGI middleware, deliberately not Starlette's ``BaseHTTPMiddleware``: the latter runs the endpoint in a separate task, so a contextvar set in it does -not reach the tool handler. A pure middleware sets the key in the request's own -task, from which the SDK's per-request handling inherits it (verified). +not reach the tool handler. A pure middleware binds the key in the request's own +task, from which the SDK's per-request handling inherits it. Requests without a key are rejected here so no tool ever runs unauthenticated. """ diff --git a/surfsense_mcp/src/surfsense_mcp/core/client.py b/surfsense_mcp/src/surfsense_mcp/core/client.py index cfe1a73ee..9ae446ae2 100644 --- a/surfsense_mcp/src/surfsense_mcp/core/client.py +++ b/surfsense_mcp/src/surfsense_mcp/core/client.py @@ -32,9 +32,8 @@ class SurfSenseClient: self, *, api_base: str, timeout: float, fallback_api_key: str | None = None ) -> None: self._api_base = api_base - # The key is resolved per request (one client serves many users over - # http), so none is baked into the shared client. ``fallback_api_key`` - # is the env-supplied key used under stdio, where there is no header. + # Resolved per request, so no key is baked into the shared client. The + # fallback is the env key used under stdio, where there is no header. self._fallback_api_key = fallback_api_key self._http = httpx.AsyncClient( base_url=api_base,