from __future__ import annotations from dataclasses import dataclass from pathlib import Path import os def _load_dotenv(path: Path) -> None: if not path.exists(): return for raw_line in path.read_text(encoding="utf-8").splitlines(): line = raw_line.strip() if not line or line.startswith("#"): continue if line.startswith("export "): line = line[len("export ") :].strip() if "=" not in line: continue key, value = line.split("=", 1) key = key.strip() value = value.strip() if not key or key in os.environ: continue if len(value) >= 2 and value[0] == value[-1] and value[0] in {'"', "'"}: value = value[1:-1] os.environ[key] = value def _env(name: str, default: str = "") -> str: return os.getenv(name, default).strip() def _int_env(name: str, default: int) -> int: value = _env(name) if not value: return default try: return int(value) except ValueError: return default def _split_csv(value: str, default: tuple[str, ...]) -> tuple[str, ...]: if not value: return default items = tuple(part.strip() for part in value.split(",") if part.strip()) return items or default @dataclass(frozen=True, slots=True) class ArgusConfig: app_name: str = "argus-mcp" sqlite_path: Path = Path("data/argus_mcp.sqlite3") finnhub_token: str = "" twelve_data_key: str = "" symbols: tuple[str, ...] = ("QQQ", "SPY", "DXY", "HYG", "BTCUSD", "ETHUSD", "VXX") interval: str = "1d" finnhub_ttl_seconds: int = 60 twelve_data_ttl_seconds: int = 900 snapshot_ttl_seconds: int = 60 def load_config() -> ArgusConfig: _load_dotenv(Path.cwd() / ".env") return ArgusConfig( sqlite_path=Path(_env("ARGUS_SQLITE_PATH", "data/argus_mcp.sqlite3")), finnhub_token=_env("FINNHUB_TOKEN"), twelve_data_key=_env("TWELVE_DATA_KEY"), symbols=_split_csv( _env("ARGUS_SYMBOLS"), ("QQQ", "SPY", "DXY", "HYG", "BTCUSD", "ETHUSD", "VXX"), ), interval=_env("ARGUS_INTERVAL", "1d"), finnhub_ttl_seconds=_int_env("ARGUS_FINNHUB_TTL_SECONDS", 60), twelve_data_ttl_seconds=_int_env("ARGUS_TWELVE_DATA_TTL_SECONDS", 900), snapshot_ttl_seconds=_int_env("ARGUS_SNAPSHOT_TTL_SECONDS", 60), )