mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-07-10 00:08:38 +00:00
refactor(mcp): resolve API key per request in client
This commit is contained in:
parent
7a91aced68
commit
953eeb11b2
1 changed files with 29 additions and 7 deletions
|
|
@ -10,10 +10,11 @@ from typing import Any
|
|||
|
||||
import httpx
|
||||
|
||||
from .auth.identity import current_api_key
|
||||
from .errors import ToolError
|
||||
|
||||
_FAILURE_HINTS: dict[int, str] = {
|
||||
401: "Authentication failed — check that SURFSENSE_API_KEY is a valid, unexpired key.",
|
||||
401: "Authentication failed — the SurfSense API key is invalid or expired.",
|
||||
402: "The workspace is out of credits for this operation.",
|
||||
403: (
|
||||
"Access denied — the token lacks permission, or API access is disabled "
|
||||
|
|
@ -27,17 +28,31 @@ _FAILURE_HINTS: dict[int, str] = {
|
|||
class SurfSenseClient:
|
||||
"""Issues authenticated requests against ``{base_url}{api_prefix}``."""
|
||||
|
||||
def __init__(self, *, api_base: str, api_key: str, timeout: float) -> None:
|
||||
def __init__(
|
||||
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.
|
||||
self._fallback_api_key = fallback_api_key
|
||||
self._http = httpx.AsyncClient(
|
||||
base_url=api_base,
|
||||
headers={
|
||||
"Authorization": f"Bearer {api_key}",
|
||||
"Accept": "application/json",
|
||||
},
|
||||
headers={"Accept": "application/json"},
|
||||
timeout=timeout,
|
||||
)
|
||||
|
||||
def _auth_headers(self) -> dict[str, str]:
|
||||
"""Resolve the caller's key: the per-request header, else the env key."""
|
||||
api_key = current_api_key() or self._fallback_api_key
|
||||
if not api_key:
|
||||
raise ToolError(
|
||||
"No SurfSense API key supplied. Send it as an 'Authorization: "
|
||||
"Bearer ss_pat_...' header (remote server), or set the "
|
||||
"SURFSENSE_API_KEY environment variable (stdio)."
|
||||
)
|
||||
return {"Authorization": f"Bearer {api_key}"}
|
||||
|
||||
async def request(
|
||||
self,
|
||||
method: str,
|
||||
|
|
@ -53,9 +68,16 @@ class SurfSenseClient:
|
|||
# as a value (e.g. int("") on folder_id) and fail.
|
||||
if params is not None:
|
||||
params = {key: value for key, value in params.items() if value is not None}
|
||||
headers = self._auth_headers()
|
||||
try:
|
||||
response = await self._http.request(
|
||||
method, path, params=params, json=json, data=data, files=files
|
||||
method,
|
||||
path,
|
||||
params=params,
|
||||
json=json,
|
||||
data=data,
|
||||
files=files,
|
||||
headers=headers,
|
||||
)
|
||||
except httpx.RequestError as exc:
|
||||
raise ToolError(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue