# mcp/clients.py import os, httpx from functools import lru_cache from typing import Any, Dict class APIError(Exception): pass class BaseClient: def __init__(self, base_url: str, api_key_env: str = None): self.base = base_url.rstrip("/") self.key = os.getenv(api_key_env) if api_key_env else None self._client = httpx.AsyncClient(timeout=10) async def request(self, method: str, path: str, **kwargs) -> Any: url = f"{self.base}/{path.lstrip('/')}" headers = kwargs.pop("headers", {}) if self.key: headers["Authorization"] = f"Bearer {self.key}" resp = await self._client.request(method, url, headers=headers, **kwargs) try: resp.raise_for_status() except httpx.HTTPStatusError as e: raise APIError(f"{resp.status_code} @ {url}") from e ct = resp.headers.get("Content-Type", "") return resp.json() if ct.startswith("application/json") else resp.text async def close(self): await self._client.aclose()