""" Hyperf API Client for MCP Servers """ from typing import Any, Optional import httpx from pydantic_settings import BaseSettings from pydantic import ConfigDict class HyperfSettings(BaseSettings): """Hyperf configuration""" hyperf_api_url: str hyperf_api_token: str model_config = ConfigDict(env_file=".env") settings = HyperfSettings() class HyperfClient: """Async client for Hyperf PHP API""" def __init__( self, api_url: Optional[str] = None, api_token: Optional[str] = None ): self.api_url = (api_url or settings.hyperf_api_url).rstrip("/") self.api_token = api_token or settings.hyperf_api_token self._client: Optional[httpx.AsyncClient] = None async def _get_client(self) -> httpx.AsyncClient: if self._client is None: self._client = httpx.AsyncClient( base_url=f"{self.api_url}/api/v1", headers={ "Authorization": f"Bearer {self.api_token}", "Content-Type": "application/json", "Accept": "application/json" }, timeout=30.0 ) return self._client async def close(self): if self._client: await self._client.aclose() self._client = None async def request( self, method: str, endpoint: str, params: Optional[dict[str, Any]] = None, json: Optional[dict[str, Any]] = None ) -> dict[str, Any]: """Make API request and handle response""" client = await self._get_client() response = await client.request( method=method, url=endpoint, params=params, json=json ) response.raise_for_status() data = response.json() # Check for API-level errors if data.get("code", 0) != 0: raise Exception(f"API Error [{data.get('code')}]: {data.get('message')}") return data.get("data", data) async def get(self, endpoint: str, params: Optional[dict[str, Any]] = None) -> dict[str, Any]: return await self.request("GET", endpoint, params=params) async def post(self, endpoint: str, json: Optional[dict[str, Any]] = None) -> dict[str, Any]: return await self.request("POST", endpoint, json=json) async def put(self, endpoint: str, json: Optional[dict[str, Any]] = None) -> dict[str, Any]: return await self.request("PUT", endpoint, json=json) async def delete(self, endpoint: str) -> dict[str, Any]: return await self.request("DELETE", endpoint)