myrmidon / python /src /mcp_server /utils /http_client.py
tek Atrust
chore(deploy): build monolithic server for Hugging Face
d5ef46f
Raw
History Blame Contribute Delete
2.45 kB
"""
HTTP client utilities for MCP Server.
Provides consistent HTTP client configuration and API call helpers.
"""
import logging
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from typing import Any
from urllib.parse import urljoin
import httpx
from src.server.config.service_discovery import get_api_url
from .timeout_config import get_default_timeout, get_polling_timeout
logger = logging.getLogger(__name__)
@asynccontextmanager
async def get_http_client(
timeout: httpx.Timeout | None = None, for_polling: bool = False
) -> AsyncIterator[httpx.AsyncClient]:
"""
Create an HTTP client with consistent configuration.
"""
if timeout is None:
timeout = get_polling_timeout() if for_polling else get_default_timeout()
async with httpx.AsyncClient(timeout=timeout) as client:
yield client
async def call_api(
method: str,
path: str,
timeout: httpx.Timeout | None = None,
for_polling: bool = False,
**kwargs: Any,
) -> dict[str, Any]:
"""
Consolidated helper to call backend API from MCP features.
Args:
method: HTTP method (GET, POST, etc.)
path: API path (relative to base URL)
timeout: Optional custom timeout
for_polling: Whether this is a polling request
**kwargs: Additional arguments for httpx request (json, params, etc.)
Returns:
JSON result as a dictionary
"""
try:
api_url = get_api_url()
url = urljoin(api_url, path)
# Inject service key for internal auth
import os
service_key = os.getenv("SUPABASE_SERVICE_KEY")
headers = kwargs.pop("headers", {})
if service_key:
headers["Authorization"] = f"Bearer {service_key}"
async with get_http_client(timeout=timeout, for_polling=for_polling) as client:
response = await client.request(method, url, headers=headers, **kwargs)
if response.status_code in (200, 201):
return {"success": True, **response.json()}
else:
error_detail = response.text
logger.error(f"API Error {response.status_code} on {path}: {error_detail}")
return {"success": False, "error": f"HTTP {response.status_code}: {error_detail}"}
except Exception as e:
logger.error(f"Failed to call API {path}: {e}")
return {"success": False, "error": str(e)}