# mcp_common API Reference

Complete Python API reference for the `mcp_common` package - the ACB-native foundation library for MCP servers.

## Installation

```bash
pip install mcp-common  # or via uv: uv add mcp-common
```

## Package Overview

`mcp_common` provides production-ready patterns for building MCP servers:

- **HTTP Client Adapter**: High-performance async HTTP client with connection pooling
- **Health Checks**: Production monitoring with ComponentHealth pattern
- **Configuration Management**: Type-safe settings with validation
- **UI Components**: Rich terminal UI panels for server information
- **Exception Hierarchy**: Structured error handling for MCP servers

**Version**: 2.0.0 (ACB-native)

______________________________________________________________________

## HTTP Client Adapter

### HTTPClientAdapter

High-performance async HTTP client built on httpx with ACB adapter lifecycle management.

**Import:**

```text
from mcp_common.adapters.http import HTTPClientAdapter
from acb.depends import depends
```

**Performance:**

- 11x faster than aiohttp for repeated requests
- Connection pool reuse reduces latency
- Automatic retry with exponential backoff

#### Getting the Adapter

```text
# Via ACB dependency injection (recommended)
from acb.depends import depends
from mcp_common.adapters.http.client import HTTPClientAdapter

http_adapter = depends.get_sync(HTTPClientAdapter)

# Direct instantiation (not recommended - breaks singleton pattern)
http_adapter = HTTPClientAdapter()
```

#### Making Requests

```text
# Using context manager (recommended)
async with http_adapter as client:
    response = await client.get("https://api.example.com/data")
    data = response.json()

# Direct client creation
client = await http_adapter._create_client()
response = await client.get("https://api.example.com/data")
await client.aclose()
```

#### Methods

##### `_create_client() -> httpx.AsyncClient`

Creates configured async HTTP client.

**Returns**: Configured `httpx.AsyncClient` instance

**Example:**

```text
client = await http_adapter._create_client()
try:
    response = await client.get("https://api.example.com/endpoint")
finally:
    await client.aclose()
```

##### `async __aenter__() -> httpx.AsyncClient`

Context manager entry - creates and returns HTTP client.

**Returns**: Configured `httpx.AsyncClient` instance

##### `async __aexit__(...) -> None`

Context manager exit - closes HTTP client connections.

##### `_cleanup_resources() -> None`

Cleanup method called during graceful shutdown to release connection pools.

**Example:**

```python
async def cleanup():
    http_adapter = depends.get_sync(HTTPClientAdapter)
    if http_adapter and hasattr(http_adapter, "_cleanup_resources"):
        await http_adapter._cleanup_resources()
```

______________________________________________________________________

### HTTPClientSettings

Configuration settings for HTTPClientAdapter.

**Import:**

```python
from mcp_common.adapters.http import HTTPClientSettings
```

#### Attributes

| Attribute | Type | Default | Description |
|-----------|------|---------|-------------|
| `max_connections` | `int` | `100` | Maximum concurrent connections |
| `max_keepalive_connections` | `int` | `20` | Maximum keep-alive connections |
| `timeout` | `float` | `30.0` | Request timeout in seconds |
| `retry_attempts` | `int` | `3` | Number of retry attempts |
| `retry_backoff` | `float` | `0.1` | Exponential backoff base (seconds) |
| `follow_redirects` | `bool` | `True` | Follow HTTP redirects |
| `verify_ssl` | `bool` | `True` | Verify SSL certificates |

#### Example Configuration

```python
from mcp_common.adapters.http import HTTPClientSettings, HTTPClientAdapter
from acb.depends import depends

# Create custom settings
settings = HTTPClientSettings(
    max_connections=200,
    max_keepalive_connections=50,
    timeout=60.0,
    retry_attempts=5,
    retry_backoff=0.5,
)

# Register with DI container
http_adapter = HTTPClientAdapter(settings=settings)
depends.set(HTTPClientAdapter, http_adapter)
```

______________________________________________________________________

## Health Checks

Production-ready health check system for monitoring MCP server components.

### HealthStatus

Enumeration of component health states.

**Import:**

```python
from mcp_common.health import HealthStatus
```

#### Values

| Status | Description | Use Case |
|--------|-------------|----------|
| `HEALTHY` | Component fully operational | Normal operation, all systems green |
| `DEGRADED` | Component functional but issues detected | Performance issues, warnings, non-critical errors |
| `UNHEALTHY` | Component not operational | Critical failures, service unavailable |

#### Example

```python
from mcp_common.health import HealthStatus, ComponentHealth


def check_service() -> ComponentHealth:
    try:
        # Check service health
        if service.is_ready():
            return ComponentHealth(
                name="my_service",
                status=HealthStatus.HEALTHY,
                message="Service operational",
            )
    except Exception as e:
        return ComponentHealth(
            name="my_service",
            status=HealthStatus.UNHEALTHY,
            message=f"Service failed: {e}",
        )
```

______________________________________________________________________

### ComponentHealth

Health check result for a single component.

**Import:**

```python
from mcp_common.health import ComponentHealth
from dataclasses import dataclass
```

#### Attributes

| Attribute | Type | Description |
|-----------|------|-------------|
| `name` | `str` | Component identifier (e.g., "database", "http_client") |
| `status` | `HealthStatus` | Current health status (HEALTHY/DEGRADED/UNHEALTHY) |
| `message` | `str` | Human-readable status description |
| `latency_ms` | `float \| None` | Optional latency measurement in milliseconds |
| `metadata` | `dict[str, Any]` | Additional context (counts, versions, errors) |

#### Constructor

```text
ComponentHealth(
    name: str,
    status: HealthStatus,
    message: str,
    latency_ms: float | None = None,
    metadata: dict[str, Any] = field(default_factory=dict),
)
```

#### Example: Database Health Check

```python
import time
from mcp_common.health import ComponentHealth, HealthStatus


async def check_database_health() -> ComponentHealth:
    """Check database connection health."""
    start_time = time.perf_counter()

    try:
        # Perform database health check
        result = await database.ping()
        latency_ms = (time.perf_counter() - start_time) * 1000

        return ComponentHealth(
            name="database",
            status=HealthStatus.HEALTHY,
            message="Database operational",
            latency_ms=latency_ms,
            metadata={
                "connections": result["active_connections"],
                "version": result["version"],
                "uptime_hours": result["uptime"] / 3600,
            },
        )

    except DatabaseError as e:
        return ComponentHealth(
            name="database",
            status=HealthStatus.UNHEALTHY,
            message=f"Database error: {e}",
            metadata={"error": str(e), "error_type": type(e).__name__},
        )
```

#### Example: HTTP Client Health Check

```text
from mcp_common.health import ComponentHealth, HealthStatus


async def check_http_health(test_url: str = None) -> ComponentHealth:
    """Check HTTP client health with optional connectivity test."""
    start_time = time.perf_counter()

    try:
        from acb.depends import depends
        from mcp_common.adapters.http.client import HTTPClientAdapter

        http_client = depends.get_sync(HTTPClientAdapter)

        if test_url:
            # Perform connectivity test
            async with http_client as client:
                response = await client.get(test_url)
                latency_ms = (time.perf_counter() - start_time) * 1000

                if response.status_code >= 400:
                    return ComponentHealth(
                        name="http_client",
                        status=HealthStatus.DEGRADED,
                        message=f"HTTP {response.status_code}",
                        latency_ms=latency_ms,
                        metadata={
                            "status_code": response.status_code,
                            "test_url": test_url,
                        },
                    )

                return ComponentHealth(
                    name="http_client",
                    status=HealthStatus.HEALTHY,
                    message="HTTP client operational",
                    latency_ms=latency_ms,
                    metadata={"test_url": test_url},
                )

        return ComponentHealth(
            name="http_client",
            status=HealthStatus.HEALTHY,
            message="HTTP client initialized",
        )

    except Exception as e:
        return ComponentHealth(
            name="http_client",
            status=HealthStatus.UNHEALTHY,
            message=f"Failed to initialize: {e}",
            metadata={"error": str(e)},
        )
```

______________________________________________________________________

### HealthCheckResponse

Aggregated health check response for multiple components.

**Import:**

```python
from mcp_common.health import HealthCheckResponse
```

#### Attributes

| Attribute | Type | Description |
|-----------|------|-------------|
| `status` | `HealthStatus` | Overall system status (worst component status) |
| `components` | `list[ComponentHealth]` | Individual component health results |
| `timestamp` | `datetime` | When health check was performed |

#### Constructor

```text
HealthCheckResponse(
    status: HealthStatus,
    components: list[ComponentHealth],
    timestamp: datetime = field(default_factory=datetime.now),
)
```

#### Example: Aggregated Health Check

```python
from datetime import datetime
from mcp_common.health import HealthCheckResponse, HealthStatus, ComponentHealth


async def system_health_check() -> HealthCheckResponse:
    """Perform system-wide health check."""

    # Run all component health checks concurrently
    component_checks = await asyncio.gather(
        check_database_health(),
        check_http_client_health(),
        check_file_system_health(),
        check_dependencies_health(),
        return_exceptions=True,
    )

    # Convert exceptions to UNHEALTHY ComponentHealth
    components = []
    for check in component_checks:
        if isinstance(check, Exception):
            components.append(
                ComponentHealth(
                    name="unknown",
                    status=HealthStatus.UNHEALTHY,
                    message=f"Health check crashed: {check}",
                    metadata={"error": str(check)},
                )
            )
        else:
            components.append(check)

    # Determine overall status (worst component status)
    statuses = [c.status for c in components]
    if HealthStatus.UNHEALTHY in statuses:
        overall_status = HealthStatus.UNHEALTHY
    elif HealthStatus.DEGRADED in statuses:
        overall_status = HealthStatus.DEGRADED
    else:
        overall_status = HealthStatus.HEALTHY

    return HealthCheckResponse(
        status=overall_status, components=components, timestamp=datetime.now()
    )
```

______________________________________________________________________

### check_http_client_health()

Check HTTP client adapter health with optional connectivity test.

**Import:**

```python
from mcp_common.http_health import check_http_client_health
```

#### Signature

```text
async def check_http_client_health(
    http_client: HTTPClientAdapter | None = None,
    test_url: str | None = None,
    timeout_ms: float = 5000,
) -> ComponentHealth:
```

#### Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `http_client` | `HTTPClientAdapter \| None` | `None` | HTTP client to check (uses DI if None) |
| `test_url` | `str \| None` | `None` | Optional URL for connectivity test |
| `timeout_ms` | `float` | `5000` | Latency threshold for DEGRADED status |

#### Returns

`ComponentHealth` with:

- **HEALTHY**: Client initialized and responsive
- **DEGRADED**: High latency or HTTP errors
- **UNHEALTHY**: Initialization failed or connectivity test failed

#### Examples

##### Basic Initialization Check

```python
from mcp_common.http_health import check_http_client_health

result = await check_http_client_health()
print(f"HTTP Client: {result.status.value}")  # HEALTHY
```

##### With Connectivity Test

```python
result = await check_http_client_health(
    test_url="https://api.example.com/health", timeout_ms=3000
)

if result.status == HealthStatus.HEALTHY:
    print(f"✅ HTTP client operational ({result.latency_ms:.0f}ms)")
elif result.status == HealthStatus.DEGRADED:
    print(f"⚠️ HTTP client degraded: {result.message}")
else:
    print(f"❌ HTTP client unhealthy: {result.message}")
```

##### With Custom HTTP Client

```python
from mcp_common.adapters.http import HTTPClientAdapter, HTTPClientSettings

# Create custom HTTP client
settings = HTTPClientSettings(max_connections=50, timeout=15.0)
http_client = HTTPClientAdapter(settings=settings)

# Check health
result = await check_http_client_health(http_client=http_client)
```

______________________________________________________________________

### check_http_connectivity()

Perform HTTP connectivity test to verify network access.

**Import:**

```python
from mcp_common.http_health import check_http_connectivity
```

#### Signature

```text
async def check_http_connectivity(
    test_url: str = "https://www.google.com",
    timeout_ms: float = 5000,
    http_client: HTTPClientAdapter | None = None,
) -> ComponentHealth:
```

#### Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `test_url` | `str` | `"https://www.google.com"` | URL to test connectivity |
| `timeout_ms` | `float` | `5000` | Latency threshold for DEGRADED status |
| `http_client` | `HTTPClientAdapter \| None` | `None` | HTTP client to use (uses DI if None) |

#### Returns

`ComponentHealth` with:

- **HEALTHY**: Successful HTTP connection within threshold
- **DEGRADED**: Connection succeeded but high latency
- **UNHEALTHY**: Connection failed or timeout

#### Examples

##### Basic Connectivity Test

```python
from mcp_common.http_health import check_http_connectivity

result = await check_http_connectivity()

if result.status == HealthStatus.HEALTHY:
    print(f"✅ Internet connectivity operational ({result.latency_ms:.0f}ms)")
```

##### Custom Test URL

```python
# Test connectivity to specific service
result = await check_http_connectivity(
    test_url="https://api.myservice.com/health", timeout_ms=2000
)

print(f"Service connectivity: {result.status.value}")
print(f"Latency: {result.latency_ms:.2f}ms")
print(f"Metadata: {result.metadata}")
```

##### Combined Health Check

```python
async def full_network_health() -> list[ComponentHealth]:
    """Check both HTTP client and connectivity."""
    return await asyncio.gather(
        check_http_client_health(),
        check_http_connectivity(test_url="https://api.example.com"),
    )


checks = await full_network_health()
for check in checks:
    print(f"{check.name}: {check.status.value} - {check.message}")
```

______________________________________________________________________

## Configuration Management

Type-safe configuration with YAML and environment variable support.

### MCPBaseSettings

Base settings class for MCP servers with ACB integration.

**Import:**

```python
from mcp_common.config import MCPBaseSettings
```

#### Features

- **YAML Configuration**: Load from `config.yaml` or `config.yml`
- **Environment Variables**: Override YAML with env vars
- **Type Validation**: Automatic Pydantic validation
- **ACB Integration**: Uses ACB Settings resolution

#### Example

```python
from mcp_common.config import MCPBaseSettings
from pydantic import Field


class MyServerSettings(MCPBaseSettings):
    """Custom MCP server settings."""

    # Server configuration
    server_name: str = Field(default="my-mcp-server", description="Server name")
    server_port: int = Field(default=8000, ge=1, le=65535)

    # API configuration
    api_key: str = Field(..., description="Required API key")
    api_endpoint: str = Field(default="https://api.example.com")

    # Feature flags
    enable_caching: bool = Field(default=True)
    cache_ttl_seconds: int = Field(default=300, ge=0)

    class Config:
        env_prefix = "MY_SERVER_"  # Environment variable prefix


# Usage
settings = MyServerSettings()
print(f"Server: {settings.server_name}")
print(f"Port: {settings.server_port}")
print(f"API Key: {'*' * 8}")  # Never log API keys!
```

#### Configuration Priority

1. **Environment Variables** (highest priority): `MY_SERVER_API_KEY=xyz`
1. **YAML Files**: `config.yaml` or `config.yml`
1. **Default Values** (lowest priority): Field defaults

#### Example YAML Configuration

```yaml
# config.yaml
server_name: my-production-server
server_port: 443
api_endpoint: https://api.production.com
enable_caching: true
cache_ttl_seconds: 600
```

______________________________________________________________________

### ValidationMixin

Mixin providing validation utilities for settings classes.

**Import:**

```python
from mcp_common.config import ValidationMixin
```

#### Methods

##### `validate_api_key(api_key: str, name: str = "API_KEY") -> str`

Validate API key format and length.

**Parameters:**

- `api_key` (`str`): API key to validate
- `name` (`str`): Key name for error messages (default: "API_KEY")

**Returns**: Validated API key (stripped)

**Raises:**

- `APIKeyMissingError`: If key is None or empty
- `APIKeyFormatError`: If key contains invalid characters
- `APIKeyLengthError`: If key length is invalid

**Example:**

```python
from mcp_common.config import MCPBaseSettings, ValidationMixin
from pydantic import Field, field_validator


class MyServerSettings(MCPBaseSettings, ValidationMixin):
    """Server settings with API key validation."""

    api_key: str = Field(..., description="API key for authentication")

    @field_validator("api_key")
    @classmethod
    def validate_api_key_field(cls, v: str) -> str:
        """Validate API key format and length."""
        return cls.validate_api_key(v, name="API_KEY")


# Usage
try:
    settings = MyServerSettings(api_key="sk-1234567890abcdef")
except APIKeyFormatError as e:
    print(f"Invalid API key: {e}")
```

______________________________________________________________________

## UI Components

Rich terminal UI components for MCP servers.

### ServerPanels

Rich panels for displaying server information with styled output.

**Import:**

```python
from mcp_common.ui import ServerPanels
```

#### Methods

##### `welcome(server_name: str, features: list[str]) -> None`

Display welcome panel with server features.

**Parameters:**

- `server_name` (`str`): Name of the MCP server
- `features` (`list[str]`): List of server features/capabilities

**Example:**

```text
from mcp_common.ui import ServerPanels

ServerPanels.welcome(
    server_name="My MCP Server",
    features=[
        "📊 Health Monitoring",
        "🔄 Session Management",
        "🔍 Semantic Search",
        "🔐 Secure Authentication",
    ],
)
```

**Output:**

```
╭─────────── My MCP Server ───────────╮
│                                     │
│ Features:                           │
│  📊 Health Monitoring              │
│  🔄 Session Management             │
│  🔍 Semantic Search                │
│  🔐 Secure Authentication          │
│                                     │
╰─────────────────────────────────────╯
```

##### `status(components: list[ComponentHealth]) -> None`

Display health status panel for multiple components.

**Parameters:**

- `components` (`list[ComponentHealth]`): List of component health checks

**Example:**

```text
from mcp_common.ui import ServerPanels
from mcp_common.health import ComponentHealth, HealthStatus

components = [
    ComponentHealth(
        "database", HealthStatus.HEALTHY, "DuckDB operational", latency_ms=5.2
    ),
    ComponentHealth(
        "http_client", HealthStatus.HEALTHY, "HTTP client ready", latency_ms=12.1
    ),
    ComponentHealth(
        "cache", HealthStatus.DEGRADED, "High memory usage", metadata={"usage": "85%"}
    ),
]

ServerPanels.status(components)
```

**Output:**

```
╭─────────── System Health ───────────╮
│                                     │
│ ✅ database: DuckDB operational    │
│    Latency: 5.2ms                  │
│                                     │
│ ✅ http_client: HTTP client ready  │
│    Latency: 12.1ms                 │
│                                     │
│ ⚠️  cache: High memory usage       │
│    usage: 85%                      │
│                                     │
╰─────────────────────────────────────╯
```

______________________________________________________________________

## Exception Hierarchy

Structured exception hierarchy for MCP server error handling.

### Base Exception

#### MCPServerError

Base exception for all MCP server errors.

**Import:**

```python
from mcp_common.exceptions import MCPServerError
```

**Usage:**

```python
try:
    # MCP server operation
    pass
except MCPServerError as e:
    print(f"MCP server error: {e}")
    # Handle any MCP-related error
```

______________________________________________________________________

### Configuration Exceptions

#### ServerConfigurationError

Raised when server configuration is invalid.

**Import:**

```python
from mcp_common.exceptions import ServerConfigurationError
```

**Example:**

```python
from mcp_common.exceptions import ServerConfigurationError


def validate_config(config: dict) -> None:
    if "api_key" not in config:
        raise ServerConfigurationError("Missing required 'api_key' in configuration")

    if config["max_connections"] < 1:
        raise ServerConfigurationError("max_connections must be >= 1")
```

______________________________________________________________________

#### ServerInitializationError

Raised when server fails to initialize.

**Import:**

```python
from mcp_common.exceptions import ServerInitializationError
```

**Example:**

```python
from mcp_common.exceptions import ServerInitializationError


async def initialize_server():
    try:
        # Initialize components
        await database.connect()
        await http_client.initialize()
    except Exception as e:
        raise ServerInitializationError(f"Server initialization failed: {e}") from e
```

______________________________________________________________________

### Dependency Exceptions

#### DependencyMissingError

Raised when required dependency is not installed.

**Import:**

```python
from mcp_common.exceptions import DependencyMissingError
```

**Example:**

```python
from mcp_common.exceptions import DependencyMissingError

try:
    import onnxruntime
except ImportError as e:
    raise DependencyMissingError(
        "onnxruntime is required for embedding generation. "
        "Install with: pip install onnxruntime"
    ) from e
```

______________________________________________________________________

### Credential Validation Exceptions

#### CredentialValidationError

Base exception for credential validation failures.

**Import:**

```python
from mcp_common.exceptions import CredentialValidationError
```

**Example:**

```python
from mcp_common.exceptions import CredentialValidationError


def validate_credentials(username: str, password: str) -> None:
    if not username or not password:
        raise CredentialValidationError("Username and password are required")

    if len(password) < 8:
        raise CredentialValidationError("Password must be at least 8 characters")
```

______________________________________________________________________

#### APIKeyMissingError

Raised when required API key is missing.

**Import:**

```python
from mcp_common.exceptions import APIKeyMissingError
```

**Example:**

```python
from mcp_common.exceptions import APIKeyMissingError


def get_api_key(key_name: str) -> str:
    key = os.environ.get(key_name)
    if not key:
        raise APIKeyMissingError(f"{key_name} environment variable not set")
    return key
```

______________________________________________________________________

#### APIKeyFormatError

Raised when API key format is invalid.

**Import:**

```python
from mcp_common.exceptions import APIKeyFormatError
```

**Example:**

```python
from mcp_common.exceptions import APIKeyFormatError
import re


def validate_api_key_format(key: str, key_name: str = "API_KEY") -> str:
    # Check for invalid characters
    if not re.match(r"^[A-Za-z0-9_-]+$", key):
        raise APIKeyFormatError(
            f"{key_name} contains invalid characters. "
            f"Only alphanumeric, underscore, and dash allowed."
        )
    return key
```

______________________________________________________________________

#### APIKeyLengthError

Raised when API key length is invalid.

**Import:**

```python
from mcp_common.exceptions import APIKeyLengthError
```

**Example:**

```python
from mcp_common.exceptions import APIKeyLengthError


def validate_api_key_length(key: str, key_name: str = "API_KEY") -> str:
    if len(key) < 16:
        raise APIKeyLengthError(
            f"{key_name} must be at least 16 characters (got {len(key)})"
        )

    if len(key) > 256:
        raise APIKeyLengthError(
            f"{key_name} exceeds maximum length of 256 characters (got {len(key)})"
        )

    return key
```

______________________________________________________________________

## Complete Usage Example

Here's a complete example showing how to use mcp_common to build a production-ready MCP server:

```python
"""Example MCP server using mcp_common foundation."""

from __future__ import annotations

import asyncio
import typing as t
from dataclasses import dataclass

from acb.depends import depends
from fastmcp import FastMCP
from pydantic import Field, field_validator

from mcp_common import (
    HTTPClientAdapter,
    HTTPClientSettings,
    MCPBaseSettings,
    ServerPanels,
    ValidationMixin,
)
from mcp_common.exceptions import (
    APIKeyMissingError,
    DependencyMissingError,
    ServerInitializationError,
)
from mcp_common.health import ComponentHealth, HealthStatus
from mcp_common.http_health import check_http_client_health, check_http_connectivity


# 1. Define server settings with validation
class MyServerSettings(MCPBaseSettings, ValidationMixin):
    """My MCP server configuration."""

    server_name: str = Field(default="my-mcp-server", description="Server name")
    api_key: str = Field(..., description="Required API key for external service")
    api_endpoint: str = Field(default="https://api.example.com")
    enable_health_checks: bool = Field(default=True)

    @field_validator("api_key")
    @classmethod
    def validate_api_key_field(cls, v: str) -> str:
        """Validate API key format."""
        return cls.validate_api_key(v, name="MY_API_KEY")

    class Config:
        env_prefix = "MY_SERVER_"


# 2. Initialize server and adapters
mcp = FastMCP("my-mcp-server")
settings = MyServerSettings()

# Setup HTTP client adapter with custom settings
http_settings = HTTPClientSettings(
    max_connections=50,
    timeout=30.0,
    retry_attempts=3,
)
http_adapter = HTTPClientAdapter(settings=http_settings)
depends.set(HTTPClientAdapter, http_adapter)


# 3. Implement health checks
async def check_external_api_health() -> ComponentHealth:
    """Check external API connectivity."""
    try:
        async with http_adapter as client:
            response = await client.get(f"{settings.api_endpoint}/health")

            if response.status_code == 200:
                return ComponentHealth(
                    name="external_api",
                    status=HealthStatus.HEALTHY,
                    message="API operational",
                    metadata={"endpoint": settings.api_endpoint},
                )
            else:
                return ComponentHealth(
                    name="external_api",
                    status=HealthStatus.DEGRADED,
                    message=f"HTTP {response.status_code}",
                    metadata={"status_code": response.status_code},
                )

    except Exception as e:
        return ComponentHealth(
            name="external_api",
            status=HealthStatus.UNHEALTHY,
            message=f"API unreachable: {e}",
            metadata={"error": str(e)},
        )


# 4. Register MCP tools
@mcp.tool()
async def health_check() -> dict[str, t.Any]:
    """System health check."""

    if not settings.enable_health_checks:
        return {
            "status": "disabled",
            "message": "Health checks disabled in configuration",
        }

    # Run all health checks concurrently
    checks = await asyncio.gather(
        check_http_client_health(),
        check_http_connectivity(),
        check_external_api_health(),
        return_exceptions=True,
    )

    # Convert to ComponentHealth list
    components = []
    for check in checks:
        if isinstance(check, Exception):
            components.append(
                ComponentHealth(
                    name="unknown",
                    status=HealthStatus.UNHEALTHY,
                    message=f"Check failed: {check}",
                )
            )
        else:
            components.append(check)

    # Display health status
    ServerPanels.status(components)

    # Determine overall status
    statuses = [c.status for c in components]
    if HealthStatus.UNHEALTHY in statuses:
        overall = "unhealthy"
    elif HealthStatus.DEGRADED in statuses:
        overall = "degraded"
    else:
        overall = "healthy"

    return {
        "status": overall,
        "components": [
            {
                "name": c.name,
                "status": c.status.value,
                "message": c.message,
                "latency_ms": c.latency_ms,
                "metadata": c.metadata,
            }
            for c in components
        ],
    }


@mcp.tool()
async def fetch_data(query: str) -> dict[str, t.Any]:
    """Fetch data from external API."""

    try:
        async with http_adapter as client:
            response = await client.get(
                f"{settings.api_endpoint}/data",
                params={"q": query},
                headers={"Authorization": f"Bearer {settings.api_key}"},
            )
            response.raise_for_status()

            return {
                "success": True,
                "data": response.json(),
            }

    except Exception as e:
        return {
            "success": False,
            "error": str(e),
        }


# 5. Server startup
async def startup():
    """Initialize server components."""

    try:
        # Display welcome panel
        ServerPanels.welcome(
            server_name=settings.server_name,
            features=[
                "🌐 HTTP Client with Connection Pooling",
                "🏥 Production Health Checks",
                "🔐 Secure API Authentication",
                "⚙️  Type-Safe Configuration",
            ],
        )

        # Initialize components
        print("✅ Server initialized successfully")

    except Exception as e:
        raise ServerInitializationError(f"Failed to initialize server: {e}") from e


# Run server
if __name__ == "__main__":
    asyncio.run(startup())
    mcp.run()
```

______________________________________________________________________

## Best Practices

### 1. Use ACB Dependency Injection

```text
# ✅ Good: Use DI container
from acb.depends import depends

http_adapter = depends.get_sync(HTTPClientAdapter)

# ❌ Bad: Direct instantiation
http_adapter = HTTPClientAdapter()
```

### 2. Always Measure Health Check Latency

```text
# ✅ Good: Include latency measurement
start_time = time.perf_counter()
# ... perform check ...
latency_ms = (time.perf_counter() - start_time) * 1000

return ComponentHealth(
    name="service",
    status=HealthStatus.HEALTHY,
    message="Operational",
    latency_ms=latency_ms,
)
```

### 3. Provide Actionable Metadata

```text
# ✅ Good: Detailed metadata
return ComponentHealth(
    name="database",
    status=HealthStatus.DEGRADED,
    message="High connection count",
    metadata={
        "active_connections": 95,
        "max_connections": 100,
        "recommendation": "Consider scaling database or optimizing queries",
    },
)
```

### 4. Use Context Managers for HTTP Clients

```text
# ✅ Good: Automatic cleanup
async with http_adapter as client:
    response = await client.get(url)

# ❌ Bad: Manual cleanup
client = await http_adapter._create_client()
response = await client.get(url)
await client.aclose()
```

### 5. Handle Errors Gracefully

```python
# ✅ Good: Never let health checks raise exceptions
async def check_service() -> ComponentHealth:
    try:
        # Check logic
        return ComponentHealth(status=HealthStatus.HEALTHY)
    except Exception as e:
        return ComponentHealth(
            status=HealthStatus.UNHEALTHY,
            message=f"Check failed: {e}",
            metadata={"error": str(e)},
        )
```

______________________________________________________________________

## Related Documentation

- [ARCHITECTURE.md](../developer/ARCHITECTURE.md) - Complete architecture guide including ACB integration
- [MCP_SCHEMA_REFERENCE.md](MCP_SCHEMA_REFERENCE.md) - MCP tool schemas for AI agents
- [mcp-common GitHub Repository](https://github.com/lesleslie/mcp-common) - Source code and examples

______________________________________________________________________

**Version**: 2.0.0 (ACB-native)
**Last Updated**: Phase 10.2 (Production Hardening)
