Initial commit: BunnyCDN MCP server with K8s deployment
- FastMCP server with 12 tools (pullzone, cache, statistics, shield) - Dockerfile with multi-stage build (python:3.11-slim + uv) - K8s manifests (Deployment + Service) - Gitea Actions CI/CD pipeline (build → push → deploy)
This commit is contained in:
66
bunnycdn_mcp/client.py
Normal file
66
bunnycdn_mcp/client.py
Normal file
@@ -0,0 +1,66 @@
|
||||
"""BunnyCDN REST API client using httpx."""
|
||||
|
||||
import httpx
|
||||
|
||||
from .config import BUNNY_API_BASE, BUNNY_API_KEY, REQUEST_TIMEOUT, logger
|
||||
|
||||
|
||||
class BunnyClient:
|
||||
"""Async HTTP client for BunnyCDN API."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._base = BUNNY_API_BASE
|
||||
self._headers = {
|
||||
"AccessKey": BUNNY_API_KEY,
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
async def get(self, path: str, params: dict | None = None) -> dict | list:
|
||||
async with httpx.AsyncClient(timeout=REQUEST_TIMEOUT) as c:
|
||||
resp = await c.get(
|
||||
f"{self._base}{path}",
|
||||
headers=self._headers,
|
||||
params=params,
|
||||
)
|
||||
return self._handle(resp)
|
||||
|
||||
async def post(self, path: str, json: dict | None = None) -> dict | list | str:
|
||||
async with httpx.AsyncClient(timeout=REQUEST_TIMEOUT) as c:
|
||||
resp = await c.post(
|
||||
f"{self._base}{path}",
|
||||
headers=self._headers,
|
||||
json=json,
|
||||
)
|
||||
return self._handle(resp)
|
||||
|
||||
async def delete(self, path: str) -> dict | str:
|
||||
async with httpx.AsyncClient(timeout=REQUEST_TIMEOUT) as c:
|
||||
resp = await c.delete(
|
||||
f"{self._base}{path}",
|
||||
headers=self._headers,
|
||||
)
|
||||
return self._handle(resp)
|
||||
|
||||
def _handle(self, resp: httpx.Response) -> dict | list | str:
|
||||
if resp.status_code == 401:
|
||||
raise BunnyAPIError("Authentication failed: invalid API key")
|
||||
if resp.status_code == 404:
|
||||
raise BunnyAPIError(f"Not found: {resp.url}")
|
||||
if resp.status_code >= 500:
|
||||
raise BunnyAPIError(f"Server error {resp.status_code}: {resp.text}")
|
||||
if resp.status_code >= 400:
|
||||
raise BunnyAPIError(f"Client error {resp.status_code}: {resp.text}")
|
||||
if not resp.content:
|
||||
return ""
|
||||
try:
|
||||
return resp.json()
|
||||
except Exception:
|
||||
return resp.text
|
||||
|
||||
|
||||
class BunnyAPIError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
client = BunnyClient()
|
||||
Reference in New Issue
Block a user