From eda0249aec1097569efa1713cac948d10d200550 Mon Sep 17 00:00:00 2001 From: CREDO23 Date: Mon, 6 Jul 2026 02:29:19 +0200 Subject: [PATCH] feat(mcp): add environment-based configuration --- surfsense_mcp/src/surfsense_mcp/config.py | 62 +++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 surfsense_mcp/src/surfsense_mcp/config.py diff --git a/surfsense_mcp/src/surfsense_mcp/config.py b/surfsense_mcp/src/surfsense_mcp/config.py new file mode 100644 index 000000000..d67e635ab --- /dev/null +++ b/surfsense_mcp/src/surfsense_mcp/config.py @@ -0,0 +1,62 @@ +"""Runtime configuration, read once from the environment. + +Secrets never live in code or client config files — the client (Cursor/Claude) +passes them as environment variables when it launches this server (see README). +""" + +from __future__ import annotations + +import os +from dataclasses import dataclass + +DEFAULT_BASE_URL = "http://localhost:8000" +DEFAULT_API_PREFIX = "/api/v1" +DEFAULT_TIMEOUT_SECONDS = 180.0 + + +@dataclass(frozen=True) +class Settings: + """Resolved configuration for a server process.""" + + base_url: str + pat: str + api_prefix: str + timeout: float + default_workspace: str | None + + @property + def api_base(self) -> str: + return f"{self.base_url}{self.api_prefix}" + + @classmethod + def from_env(cls) -> Settings: + pat = os.environ.get("SURFSENSE_PAT", "").strip() + if not pat: + raise SystemExit( + "SURFSENSE_PAT is required. Create a Personal Access Token in " + "SurfSense (Settings -> API) and pass it via the SURFSENSE_PAT " + "environment variable." + ) + + base_url = ( + os.environ.get("SURFSENSE_BASE_URL", DEFAULT_BASE_URL).strip().rstrip("/") + ) + api_prefix = "/" + os.environ.get( + "SURFSENSE_API_PREFIX", DEFAULT_API_PREFIX + ).strip().strip("/") + + raw_timeout = os.environ.get("SURFSENSE_TIMEOUT", "").strip() + try: + timeout = float(raw_timeout) if raw_timeout else DEFAULT_TIMEOUT_SECONDS + except ValueError: + timeout = DEFAULT_TIMEOUT_SECONDS + + default_workspace = os.environ.get("SURFSENSE_WORKSPACE", "").strip() or None + + return cls( + base_url=base_url, + pat=pat, + api_prefix=api_prefix, + timeout=timeout, + default_workspace=default_workspace, + )