ExMCP.Client.Configuration (ex_mcp v0.9.2)
View SourceConfiguration options for ExMCP.Client implementation switching.
ExMCP provides two client implementations:
- Legacy Implementation (
ExMCP.Client.LegacyAdapter) - The original GenServer-based client - State Machine Implementation (
ExMCP.Client.StateMachineAdapter) - New GenStateMachine-based client
Application-Level Configuration
Set the default adapter for all clients in your application:
# config/config.exs
config :ex_mcp, :client_adapter, ExMCP.Client.StateMachineAdapterAvailable adapters:
ExMCP.Client.LegacyAdapter(default) - Stable, battle-tested implementationExMCP.Client.StateMachineAdapter- New implementation with formal state management
Per-Client Configuration
Override the adapter for specific clients:
# Use state machine for this client
{:ok, client} = ExMCP.Client.start_link(
transport: :stdio,
command: "mcp-server",
adapter: ExMCP.Client.StateMachineAdapter
)
# Use legacy implementation
{:ok, client} = ExMCP.Client.start_link(
transport: :stdio,
command: "mcp-server",
adapter: ExMCP.Client.LegacyAdapter
)Configuration Priority
The adapter is selected in this order of precedence:
:adapteroption instart_link/2opts:adapterkey in config map passed tostart_link/2- Application environment
:client_adaptersetting - Default (
ExMCP.Client.LegacyAdapter)
Implementation Differences
State Machine Implementation Benefits
- Formal state management: Uses GenStateMachine for explicit state transitions
- Reduced complexity: State-specific data structures instead of 21 monolithic fields
- Better error handling: Clear state transition guards prevent invalid operations
- Enhanced observability: Comprehensive telemetry events for monitoring
- Progress tracking integration: Built-in ExMCP.ProgressTracker integration
- Improved reconnection: Exponential backoff with configurable limits
Legacy Implementation
- Stability: Proven in production environments
- Backward compatibility: Maintains exact API compatibility
- Simple architecture: Single GenServer process
- Resource efficient: Lower memory footprint
Migration Strategy
Phase 1: Opt-in Testing
Test the state machine implementation on non-critical clients:
# Test clients only
{:ok, test_client} = ExMCP.Client.start_link(
config,
adapter: ExMCP.Client.StateMachineAdapter
)Phase 2: Application Default
Once tested, set as application default:
# config/config.exs
config :ex_mcp, :client_adapter, ExMCP.Client.StateMachineAdapterPhase 3: Migration Complete
Remove explicit adapter configurations to use the new default.
Telemetry Events
The state machine implementation emits telemetry events for observability:
# State transitions
[:ex_mcp, :client, :state_transition]
# Request lifecycle
[:ex_mcp, :client, :request, :start]
[:ex_mcp, :client, :request, :success]
[:ex_mcp, :client, :request, :error]
# Connection events
[:ex_mcp, :client, :connection, :success]
[:ex_mcp, :client, :transport, :error]
[:ex_mcp, :client, :transport, :closed]
# Handshake events
[:ex_mcp, :client, :handshake, :start]
[:ex_mcp, :client, :handshake, :success]
[:ex_mcp, :client, :handshake, :error]
# Reconnection events
[:ex_mcp, :client, :reconnect, :attempt]
[:ex_mcp, :client, :reconnect, :success]
[:ex_mcp, :client, :reconnect, :error]
[:ex_mcp, :client, :reconnect, :timeout]
# Progress tracking events
[:ex_mcp, :client, :progress, :update]
[:ex_mcp, :client, :progress, :unknown_token]
[:ex_mcp, :client, :progress, :rate_limited]
[:ex_mcp, :client, :progress, :not_increasing]
[:ex_mcp, :client, :progress, :error]
[:ex_mcp, :client, :progress, :untracked]Set up telemetry handlers to monitor client behavior:
:telemetry.attach_many(
"ex_mcp_client_metrics",
[
[:ex_mcp, :client, :state_transition],
[:ex_mcp, :client, :request, :success],
[:ex_mcp, :client, :request, :error]
],
&MyApp.Telemetry.handle_client_event/4,
%{}
)Configuration Examples
Production: High Reliability
config :ex_mcp, :client_adapter, ExMCP.Client.StateMachineAdapter
# Client with enhanced monitoring
{:ok, client} = ExMCP.Client.start_link(
transport: :stdio,
command: "critical-mcp-server",
max_reconnect_attempts: 10,
reconnect_backoff_ms: 1000,
callbacks: %{
on_disconnect: &MyApp.Monitoring.handle_disconnect/1,
on_initialize: &MyApp.Callbacks.on_initialize/1
}
)Development: Legacy Compatibility
# Use legacy for development/testing
config :ex_mcp, :client_adapter, ExMCP.Client.LegacyAdapterHybrid: Mixed Environment
# Most clients use state machine
config :ex_mcp, :client_adapter, ExMCP.Client.StateMachineAdapter
# Specific legacy client for compatibility
{:ok, legacy_client} = ExMCP.Client.start_link(
config,
adapter: ExMCP.Client.LegacyAdapter
)Troubleshooting
Check Current Adapter
adapter = ExMCP.Client.Wrapper.get_adapter(config, opts)Verify Configuration
Application.get_env(:ex_mcp, :client_adapter)Monitor State Transitions
:telemetry.attach(
"debug_states",
[:ex_mcp, :client, :state_transition],
fn event, measurements, metadata, _config ->
IO.inspect({event, measurements, metadata}, label: "State Transition")
end,
%{}
)
Summary
Functions
Returns all available client adapter modules.
Returns the default client adapter module.
Returns telemetry events emitted by the state machine adapter.
Validates that an adapter module implements the required behavior.