Skip to content

Error Handling

This document describes the error handling patterns used in the MCP Registry Client and how to handle different types of errors in your applications.

Exception Hierarchy

The client uses a structured exception hierarchy that helps you handle different types of errors appropriately:

Exception
├── httpx.HTTPError (from httpx library)
│   ├── httpx.RequestError (network/transport issues)
│   │   ├── httpx.ConnectError (connection failures)
│   │   ├── httpx.TimeoutException (request timeouts)
│   │   └── httpx.NetworkError (other network issues)
│   └── httpx.HTTPStatusError (4xx/5xx responses)
├── ValidationError (from pydantic library)
└── RegistryClientError (custom exceptions)
    └── RegistryAPIError (API-specific errors)

Custom Exceptions

RegistryClientError

Base exception for all client-specific errors.

from mcp_registry_client import RegistryClientError

try:
    # client operations
    pass
except RegistryClientError as e:
    print(f"Client error: {e}")

RegistryAPIError

Raised when the registry API returns an error response. Includes the HTTP status code when available.

from mcp_registry_client import RegistryAPIError

try:
    server = await client.get_server_by_name("nonexistent")
except RegistryAPIError as e:
    if e.status_code == 404:
        print("Server not found")
    elif e.status_code >= 500:
        print("Registry service unavailable")
    else:
        print(f"API error: {e}")

Common Error Scenarios

Network Issues

Network connectivity problems are handled by httpx exceptions:

import httpx
from mcp_registry_client import RegistryClient

async def handle_network_errors():
    try:
        async with RegistryClient() as client:
            result = await client.search_servers()
    except httpx.ConnectError:
        print("Failed to connect to registry")
    except httpx.TimeoutException:
        print("Request timed out")
    except httpx.NetworkError as e:
        print(f"Network error: {e}")

API Response Errors

Handle different HTTP status codes appropriately:

import httpx
from mcp_registry_client import RegistryAPIError

async def handle_api_errors():
    try:
        async with RegistryClient() as client:
            server = await client.get_server_by_name("server-name")
    except RegistryAPIError as e:
        if e.status_code == 404:
            print("Server not found")
        elif e.status_code == 429:
            print("Rate limited - please try again later")
        elif e.status_code >= 500:
            print("Registry service temporarily unavailable")
    except httpx.HTTPStatusError as e:
        print(f"HTTP error: {e.response.status_code}")

Data Validation Errors

Pydantic validation errors occur when the API returns unexpected data:

from pydantic import ValidationError

async def handle_validation_errors():
    try:
        async with RegistryClient() as client:
            result = await client.search_servers()
    except ValidationError as e:
        print(f"Invalid response format: {e}")
        # Log the error for debugging
        logger.error("Validation error", exc_info=True)

Best Practices

Comprehensive Error Handling

Always handle the most specific exceptions first:

import httpx
from pydantic import ValidationError
from mcp_registry_client import RegistryAPIError, RegistryClientError

async def robust_client_usage():
    try:
        async with RegistryClient() as client:
            result = await client.search_servers(name="example")
            return result.servers
    except RegistryAPIError as e:
        if e.status_code == 404:
            return []  # No servers found
        elif e.status_code >= 500:
            raise  # Re-raise server errors
        else:
            logger.warning(f"API error: {e}")
            return []
    except httpx.RequestError as e:
        logger.error(f"Network error: {e}")
        raise  # Re-raise network errors
    except ValidationError as e:
        logger.error(f"Data validation error: {e}")
        raise  # Re-raise validation errors
    except RegistryClientError as e:
        logger.error(f"Client error: {e}")
        raise

Retry Logic

Implement retry logic for transient errors:

import asyncio
import httpx
from mcp_registry_client import RegistryAPIError

async def retry_on_transient_errors(max_retries=3):
    for attempt in range(max_retries):
        try:
            async with RegistryClient() as client:
                return await client.search_servers()
        except (httpx.TimeoutException, httpx.NetworkError) as e:
            if attempt == max_retries - 1:
                raise  # Re-raise on final attempt
            await asyncio.sleep(2 ** attempt)  # Exponential backoff
        except RegistryAPIError as e:
            if e.status_code and e.status_code >= 500:
                if attempt == max_retries - 1:
                    raise
                await asyncio.sleep(2 ** attempt)
            else:
                raise  # Don't retry client errors (4xx)

Logging

Use appropriate logging levels for different error types:

import logging
from mcp_registry_client import RegistryAPIError, RegistryClientError

logger = logging.getLogger(__name__)

async def log_errors_appropriately():
    try:
        async with RegistryClient() as client:
            result = await client.search_servers()
    except RegistryAPIError as e:
        if e.status_code == 404:
            logger.info("Server not found")
        elif e.status_code >= 500:
            logger.error(f"Registry service error: {e}")
        else:
            logger.warning(f"API error: {e}")
    except RegistryClientError as e:
        logger.error(f"Client error: {e}")
    except Exception as e:
        logger.exception("Unexpected error")

Context Managers

Always use the client as a context manager to ensure proper cleanup:

# Good
async with RegistryClient() as client:
    result = await client.search_servers()

# Avoid
client = RegistryClient()
try:
    result = await client.search_servers()
finally:
    await client.close()

CLI Error Handling

The CLI interface handles errors gracefully and provides user-friendly messages:

  • 404 errors: "Server not found"
  • 5xx errors: "Registry service unavailable. Please try again later."
  • Network errors: Specific error messages based on the failure type
  • Validation errors: "Failed to process response"

All CLI errors are logged with appropriate detail levels for debugging.