Skip to main content
Glama

USPTO Final Petition Decisions MCP Server

by john-walkoe
logging.pyβ€’5.21 kB
""" Logging utilities for USPTO Final Petition Decisions MCP. Provides secure request/response logging with API key sanitization. """ import httpx import logging import json from typing import Dict, Any logger = logging.getLogger('fpd_mcp.logging_transport') class LoggingTransport(httpx.AsyncBaseTransport): """ Custom HTTP transport that logs all requests and responses. Automatically sanitizes sensitive headers (API keys) to prevent exposure in logs. Useful for debugging API integration issues while maintaining security. """ def __init__(self, transport: httpx.AsyncBaseTransport): """ Initialize logging transport wrapper. Args: transport: The underlying HTTP transport to wrap """ self.transport = transport async def handle_async_request(self, request: httpx.Request) -> httpx.Response: """ Handle HTTP request with logging. Args: request: The HTTP request to process Returns: The HTTP response from the underlying transport """ # Log the request logger.debug(f"REQUEST: {request.method} {request.url}") # Sanitize headers to prevent API key exposure headers_copy = dict(request.headers) self._sanitize_headers(headers_copy) logger.debug(f"REQUEST HEADERS: {headers_copy}") # Log request body self._log_request_body(request) # Get the response response = await self.transport.handle_async_request(request) # Log the response logger.debug(f"RESPONSE: {response.status_code} from {request.url}") # Sanitize response headers as well response_headers_copy = dict(response.headers) self._sanitize_headers(response_headers_copy) logger.debug(f"RESPONSE HEADERS: {response_headers_copy}") return response def _sanitize_headers(self, headers: Dict[str, Any]) -> None: """ Remove sensitive headers from dictionary in-place. Args: headers: Dictionary of HTTP headers to sanitize """ sensitive_keys = [ 'X-API-KEY', 'x-api-key', 'Authorization', 'authorization', 'API-KEY', 'api-key' ] for key in sensitive_keys: headers.pop(key, None) def _log_request_body(self, request: httpx.Request) -> None: """ Log request body with JSON pretty-printing if possible. Args: request: The HTTP request containing the body to log """ try: if request.content: body = request.content try: # Decode bytes to string if isinstance(body, bytes): body = body.decode('utf-8') # Try to parse and pretty-print JSON try: json_body = json.loads(body) logger.debug(f"REQUEST BODY:\n{json.dumps(json_body, indent=2)}") except (json.JSONDecodeError, TypeError): logger.debug(f"REQUEST BODY: {body}") except Exception as e: logger.debug(f"REQUEST BODY (raw): {body}") except Exception as e: logger.debug(f"Error logging request body: {e}") def get_logger(name: str) -> logging.Logger: """ Get a logger instance for the FPD MCP. Args: name: Logger name (typically module name) Returns: Configured logger instance """ return logging.getLogger(f'fpd_mcp.{name}') def sanitize_api_key_in_message(message: str, api_key: str) -> str: """ Replace API key in message with masked version for safe logging. Args: message: The message that may contain the API key api_key: The API key to mask Returns: Message with API key replaced by "***KEY_MASKED***" """ if api_key and api_key in message: return message.replace(api_key, "***KEY_MASKED***") return message def log_api_call( logger_instance: logging.Logger, endpoint: str, method: str = "POST", params: Dict[str, Any] = None, status_code: int = None, error: str = None ) -> None: """ Log API call details in a structured format. Args: logger_instance: Logger to use endpoint: API endpoint called method: HTTP method used params: Request parameters (will be sanitized) status_code: Response status code (if available) error: Error message (if applicable) """ log_data = { "method": method, "endpoint": endpoint, } if params: # Sanitize params before logging safe_params = params.copy() safe_params.pop('api_key', None) safe_params.pop('apiKey', None) log_data["params"] = safe_params if status_code: log_data["status_code"] = status_code if error: log_data["error"] = error logger_instance.error(f"API Call Failed: {json.dumps(log_data, indent=2)}") else: logger_instance.info(f"API Call: {json.dumps(log_data)}")

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/john-walkoe/uspto_fpd_mcp'

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