ExMCP.Transport.ReliabilityWrapper (ex_mcp v0.10.0)

View Source

Transport wrapper that adds circuit breaker protection to any MCP transport.

This module provides a transparent reliability layer that can be wrapped around any transport implementation to add circuit breaker protection, health monitoring, and retry logic without modifying the underlying transport.

Features

  • Circuit breaker protection for transport operations
  • Health monitoring integration
  • Automatic error classification
  • Transport-specific configuration
  • Transparent pass-through for unaffected operations

Usage

# Wrap an existing transport with reliability features
{:ok, transport_state} = SomeTransport.connect(opts)

reliability_opts = [
  circuit_breaker: [
    failure_threshold: 5,
    reset_timeout: 30_000
  ],
  health_check: [
    check_interval: 60_000
  ]
]

{:ok, wrapped_state} = ReliabilityWrapper.wrap(
  SomeTransport, 
  transport_state, 
  reliability_opts
)

# Use wrapped transport normally
{:ok, new_state} = ReliabilityWrapper.send_message(message, wrapped_state)

Error Classification

The wrapper automatically classifies transport errors for circuit breaker decisions:

  • Connection errors: Always count as failures
  • Transport errors: Count as failures
  • Security violations: Do not count as failures (policy issue, not transport failure)
  • Validation errors: Do not count as failures (client issue, not transport failure)
  • Timeout errors: Count as failures
  • Protocol errors: Count as failures

Summary

Functions

Manually closes the circuit breaker if enabled.

Gets circuit breaker statistics if enabled.

Gets health check status if enabled.

Manually opens the circuit breaker if enabled.

Resets the circuit breaker if enabled.

Unwraps the reliability wrapper to get the original transport state.

Wraps an existing transport with reliability features.

Types

reliability_opts()

@type reliability_opts() :: [
  circuit_breaker: keyword() | false,
  health_check: keyword() | false
]

t()

@type t() :: %ExMCP.Transport.ReliabilityWrapper{
  circuit_breaker_pid: pid() | nil,
  config: map(),
  health_check_pid: pid() | nil,
  wrapped_module: module(),
  wrapped_state: any()
}

Functions

close_circuit(reliability_wrapper)

@spec close_circuit(t()) :: :ok | {:error, :not_enabled}

Manually closes the circuit breaker if enabled.

get_circuit_breaker_stats(reliability_wrapper)

@spec get_circuit_breaker_stats(t()) :: map() | nil

Gets circuit breaker statistics if enabled.

get_health_status(reliability_wrapper)

@spec get_health_status(t()) :: map() | nil

Gets health check status if enabled.

open_circuit(reliability_wrapper)

@spec open_circuit(t()) :: :ok | {:error, :not_enabled}

Manually opens the circuit breaker if enabled.

receive_message(state, timeout)

reset_circuit(reliability_wrapper)

@spec reset_circuit(t()) :: :ok | {:error, :not_enabled}

Resets the circuit breaker if enabled.

unwrap(state)

@spec unwrap(t()) :: {module(), any()}

Unwraps the reliability wrapper to get the original transport state.

Useful for accessing transport-specific functions not part of the Transport behaviour.

wrap(transport_module, transport_state, opts \\ [])

@spec wrap(module(), any(), reliability_opts()) :: {:ok, t()} | {:error, any()}

Wraps an existing transport with reliability features.

Options

  • :circuit_breaker - Circuit breaker configuration or false to disable
  • :health_check - Health check configuration or false to disable

Circuit Breaker Options

  • :failure_threshold - Number of failures before opening (default: 5)
  • :success_threshold - Number of successes to close half-open circuit (default: 3)
  • :reset_timeout - Time before transitioning from open to half-open (default: 30_000)
  • :timeout - Operation timeout in milliseconds (default: 5_000)

Health Check Options

  • :check_interval - Interval between health checks (default: 60_000)
  • :failure_threshold - Health check failures before marking unhealthy (default: 3)
  • :recovery_threshold - Health check successes before marking healthy (default: 2)