""" Mall API Client for MCP Servers 用于调用商城 API,包括订单查询等接口 """ from typing import Any, Optional import httpx from pydantic_settings import BaseSettings from pydantic import ConfigDict class MallSettings(BaseSettings): """Mall API configuration""" mall_api_url: Optional[str] = None mall_api_token: Optional[str] = None mall_tenant_id: str = "2" mall_currency_code: str = "EUR" mall_language_id: str = "1" mall_source: str = "us.qa1.gaia888.com" model_config = ConfigDict( env_file=".env", env_file_encoding="utf-8", extra="ignore" ) settings = MallSettings() class MallClient: """Async client for Mall API""" def __init__( self, api_url: Optional[str] = None, api_token: Optional[str] = None, tenant_id: Optional[str] = None, currency_code: Optional[str] = None, language_id: Optional[str] = None, source: Optional[str] = None ): self.api_url = (api_url or settings.mall_api_url or "").rstrip("/") self.api_token = api_token or settings.mall_api_token or "" self.tenant_id = tenant_id or settings.mall_tenant_id self.currency_code = currency_code or settings.mall_currency_code self.language_id = language_id or settings.mall_language_id self.source = source or settings.mall_source self._client: Optional[httpx.AsyncClient] = None async def _get_client(self) -> httpx.AsyncClient: """Get or create HTTP client with default headers""" if self._client is None: self._client = httpx.AsyncClient( base_url=self.api_url, headers={ "Authorization": f"Bearer {self.api_token}", "Content-Type": "application/json", "Accept": "application/json, text/plain, */*", "Device-Type": "pc", "tenant-Id": self.tenant_id, "currency-code": self.currency_code, "language-id": self.language_id, "source": self.source, "Origin": "https://www.qa1.gaia888.com", "Referer": "https://www.qa1.gaia888.com/", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36", "DNT": "1", }, timeout=30.0 ) return self._client async def close(self): """Close HTTP client""" 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, headers: Optional[dict[str, str]] = None ) -> dict[str, Any]: """Make API request and handle response Args: method: HTTP method endpoint: API endpoint (e.g., "/mall/api/order/show") params: Query parameters json: JSON body headers: Additional headers Returns: Response data """ client = await self._get_client() # Merge additional headers request_headers = {} if headers: request_headers.update(headers) response = await client.request( method=method, url=endpoint, params=params, json=json, headers=request_headers ) response.raise_for_status() data = response.json() # Mall API 返回格式: {"code": 200, "msg": "success", "result": {...}} # 检查 API 错误 if data.get("code") != 200: raise Exception(f"API Error [{data.get('code')}]: {data.get('msg') or data.get('message')}") # 返回 result 字段或整个 data return data.get("result", data) async def get( self, endpoint: str, params: Optional[dict[str, Any]] = None, **kwargs: Any ) -> dict[str, Any]: """GET request""" return await self.request("GET", endpoint, params=params, **kwargs) async def post( self, endpoint: str, json: Optional[dict[str, Any]] = None, **kwargs: Any ) -> dict[str, Any]: """POST request""" return await self.request("POST", endpoint, json=json, **kwargs) # ============ Order APIs ============ async def get_order_by_id( self, order_id: str ) -> dict[str, Any]: """Query order by order ID 根据订单号查询订单详情 Args: order_id: 订单号 (e.g., "202071324") Returns: 订单详情,包含订单号、状态、商品信息、金额、物流信息等 Order details including order ID, status, items, amount, logistics info, etc. Example: >>> client = MallClient() >>> order = await client.get_order_by_id("202071324") >>> print(order["order_id"]) """ try: result = await self.get( "/mall/api/order/show", params={"orderId": order_id} ) return result except Exception as e: raise Exception(f"查询订单失败 (Query order failed): {str(e)}") # Global Mall client instance mall_client: Optional[MallClient] = None def get_mall_client() -> MallClient: """Get or create global Mall client instance""" global mall_client if mall_client is None: mall_client = MallClient() return mall_client