Skip to main content
Glama
client.py4.14 kB
"""Siigo API client wrapper.""" import logging import uuid from typing import Any import httpx from siigo_mcp.auth import SiigoAuth logger = logging.getLogger(__name__) BASE_URL = "https://api.siigo.com/v1" class SiigoClient: """Async client for the Siigo API.""" def __init__(self, username: str, access_key: str, partner_id: str): self.partner_id = partner_id self._auth = SiigoAuth(username, access_key) self._client = httpx.AsyncClient( base_url=BASE_URL, timeout=30.0, ) async def _get_headers(self) -> dict[str, str]: """Get headers with current auth token.""" token = await self._auth.get_token(self._client) return { "Authorization": f"Bearer {token}", "Partner-Id": self.partner_id, "Content-Type": "application/json", } async def get(self, path: str, params: dict[str, Any] | None = None) -> Any: """Make a GET request to the Siigo API.""" headers = await self._get_headers() response = await self._client.get(path, headers=headers, params=params) response.raise_for_status() return response.json() async def post(self, path: str, data: dict[str, Any]) -> Any: """Make a POST request to the Siigo API.""" headers = await self._get_headers() response = await self._client.post(path, headers=headers, json=data) response.raise_for_status() return response.json() async def put(self, path: str, data: dict[str, Any]) -> Any: """Make a PUT request to the Siigo API.""" headers = await self._get_headers() response = await self._client.put(path, headers=headers, json=data) response.raise_for_status() return response.json() async def delete(self, path: str) -> Any: """Make a DELETE request to the Siigo API.""" headers = await self._get_headers() response = await self._client.delete(path, headers=headers) response.raise_for_status() if response.content: return response.json() return None async def get_pdf(self, path: str) -> bytes: """Get PDF content from the Siigo API.""" headers = await self._get_headers() headers["Accept"] = "application/pdf" response = await self._client.get(path, headers=headers) response.raise_for_status() return response.content async def close(self) -> None: """Close the HTTP client.""" await self._client.aclose() class DryRunSiigoClient(SiigoClient): """Client that validates but doesn't execute write operations. - GET requests work normally (read-only, safe) - POST/PUT/DELETE log the operation and return mock responses """ def _log_operation(self, method: str, path: str, data: dict[str, Any] | None) -> None: """Log what would have been executed.""" logger.info(f"[DRY RUN] {method} {path}", extra={"data": data}) def _mock_response(self, action: str, path: str, data: dict[str, Any] | None) -> dict[str, Any]: """Generate a mock response for dry-run operations.""" return { "id": str(uuid.uuid4()), "dry_run": True, "action": action, "path": path, "validated_data": data, "message": f"Dry run: would {action} at {path}", } async def post(self, path: str, data: dict[str, Any]) -> dict[str, Any]: """Mock POST - validate and log without executing.""" self._log_operation("POST", path, data) return self._mock_response("create", path, data) async def put(self, path: str, data: dict[str, Any]) -> dict[str, Any]: """Mock PUT - validate and log without executing.""" self._log_operation("PUT", path, data) return self._mock_response("update", path, data) async def delete(self, path: str) -> dict[str, Any]: """Mock DELETE - log without executing.""" self._log_operation("DELETE", path, None) return self._mock_response("delete", path, None)

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/dsfaccini/siigo-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server