# `ExMCP.ClientConfig`
[🔗](https://github.com/azmaveth/ex_mcp/blob/v1.0.0/lib/ex_mcp/client_config.ex#L1)

Configuration builder for ExMCP clients.

This module provides a fluent interface for building client configurations,
ensuring type safety and validation at compile time.

## Usage

    config = ExMCP.ClientConfig.new()
             |> ExMCP.ClientConfig.put_transport(:http)
             |> ExMCP.ClientConfig.put_url("https://api.example.com")
             |> ExMCP.ClientConfig.put_transport_options(
               timeout: 30_000,
               pool_size: 10
             )

    {:ok, client} = ExMCP.Client.connect(config)

## Transport Configuration

### stdio Transport

    config = ExMCP.ClientConfig.new()
             |> ExMCP.ClientConfig.put_transport(:stdio)
             |> ExMCP.ClientConfig.put_command(["python", "server.py"])
             |> ExMCP.ClientConfig.put_args(["--verbose"])
             |> ExMCP.ClientConfig.put_env([{"DEBUG", "1"}])

### HTTP Transport

    config = ExMCP.ClientConfig.new()
             |> ExMCP.ClientConfig.put_transport(:http)
             |> ExMCP.ClientConfig.put_url("https://api.example.com")
             |> ExMCP.ClientConfig.put_headers([{"Authorization", "Bearer token"}])
             |> ExMCP.ClientConfig.put_transport_options(
               use_sse: true,
               timeout: 10_000
             )

## Advanced Options

    config = ExMCP.ClientConfig.new()
             |> ExMCP.ClientConfig.put_name(:my_client)
             |> ExMCP.ClientConfig.put_handler(MyClientHandler)
             |> ExMCP.ClientConfig.put_retry_policy(
               max_attempts: 3,
               backoff: :exponential
             )

## Basic Usage

    # Create a simple HTTP configuration
    config = ExMCP.ClientConfig.new(:http, url: "http://localhost:8080")
    {:ok, client} = ExMCP.connect(config)

## Advanced Usage

    # Create a production configuration with full settings
    config = ExMCP.ClientConfig.new(:production)
    |> ExMCP.ClientConfig.put_transport(:http, url: "https://api.example.com")
    |> ExMCP.ClientConfig.put_retry_policy(max_attempts: 5, base_interval: 1000)
    |> ExMCP.ClientConfig.put_timeout(connect: 10_000, request: 30_000)
    |> ExMCP.ClientConfig.put_auth(:bearer, token: "...")

    {:ok, client} = ExMCP.connect(config)

## Configuration Profiles

Built-in profiles:
- `:development` - For local development with debugging
- `:test` - For testing with fast timeouts
- `:production` - For production with robust retry policies
- `:http` - HTTP transport with sensible defaults
- `:stdio` - Stdio transport configuration
- `:beam` - BEAM-local transport configuration

# `auth_config`

```elixir
@type auth_config() :: %{
  type: auth_type(),
  token: String.t() | nil,
  username: String.t() | nil,
  password: String.t() | nil,
  headers: %{required(String.t()) =&gt; String.t()},
  refresh_token: String.t() | nil,
  client_id: String.t() | nil,
  client_secret: String.t() | nil,
  custom_handler: {module(), atom(), [any()]} | nil
}
```

# `auth_type`

```elixir
@type auth_type() :: :none | :bearer | :basic | :oauth | :custom
```

# `log_level`

```elixir
@type log_level() :: :debug | :info | :warn | :error | :none
```

# `observability_config`

```elixir
@type observability_config() :: %{
  logging: %{
    enabled: boolean(),
    level: log_level(),
    format: :text | :json,
    include_request_id: boolean(),
    include_metadata: boolean()
  },
  telemetry: %{
    enabled: boolean(),
    prefix: [atom()],
    include_system_metrics: boolean()
  },
  tracing: %{
    enabled: boolean(),
    sampler: atom() | {module(), atom(), [any()]},
    propagators: [atom()]
  }
}
```

# `pool_config`

```elixir
@type pool_config() :: %{
  enabled: boolean(),
  size: pos_integer(),
  max_overflow: non_neg_integer(),
  checkout_timeout: pos_integer(),
  idle_timeout: pos_integer()
}
```

# `profile`

```elixir
@type profile() :: atom()
```

# `retry_policy`

```elixir
@type retry_policy() :: %{
  enabled: boolean(),
  max_attempts: pos_integer(),
  base_interval: pos_integer(),
  max_interval: pos_integer(),
  backoff_type: :linear | :exponential | :fixed,
  jitter: boolean()
}
```

# `t`

```elixir
@type t() :: %ExMCP.ClientConfig{
  auth: auth_config(),
  client_info: %{name: String.t(), version: String.t(), user_agent: String.t()},
  custom_options: %{required(atom()) =&gt; any()},
  fallback_transports: [transport_config()],
  observability: observability_config(),
  pool: pool_config(),
  profile: profile() | nil,
  retry_policy: retry_policy(),
  timeouts: timeout_config(),
  transport: transport_config()
}
```

# `timeout_config`

```elixir
@type timeout_config() :: %{
  total: pos_integer(),
  connect: pos_integer(),
  request: pos_integer(),
  stream: %{handshake: pos_integer(), idle: pos_integer()},
  pool: %{checkout: pos_integer(), idle: pos_integer()}
}
```

# `transport_config`

```elixir
@type transport_config() :: %{
  type: transport_type(),
  url: String.t() | nil,
  command: String.t() | [String.t()] | nil,
  host: String.t(),
  port: integer(),
  path: String.t(),
  ssl: boolean(),
  headers: %{required(String.t()) =&gt; String.t()},
  options: keyword()
}
```

# `transport_type`

```elixir
@type transport_type() :: :http | :stdio | :beam
```

# `__struct__`
*struct* 

Timeout configuration for ExMCP operations.

- `total`: Maximum time for an entire logical operation, including all retries (ms)
- `connect`: Time to establish initial TCP/TLS connection (ms)
- `request`: Time for a single request-response cycle (ms)
- `stream`: Timeouts specific to persistent streams like SSE
  - `handshake`: Time to wait for stream handshake after connection (ms)
  - `idle`: Time a stream can be idle before being considered dead (ms)
- `pool`: Connection pool related timeouts
  - `checkout`: Time to wait for a connection from the pool (ms)
  - `idle`: Time a connection can sit idle in the pool (ms)

# `add_fallback`

```elixir
@spec add_fallback(t(), transport_type(), keyword()) :: t()
```

Adds a fallback transport configuration.

## Examples

    config = ExMCP.ClientConfig.new(:http, url: "http://primary:8080")
    |> ExMCP.ClientConfig.add_fallback(:http, url: "http://backup:8080")
    |> ExMCP.ClientConfig.add_fallback(:stdio, command: "local-server")

# `get_all_transports`

```elixir
@spec get_all_transports(t()) :: [transport_config()]
```

Gets the list of all transport configurations (primary + fallbacks).

## Examples

    transports = ExMCP.ClientConfig.get_all_transports(config)
    # Try connecting to each transport in order

# `new`

```elixir
@spec new() :: t()
```

Creates a new client configuration.

## Examples

    # Use a predefined profile
    config = ExMCP.ClientConfig.new(:production)

    # Create HTTP configuration with custom options
    config = ExMCP.ClientConfig.new(:http, url: "http://localhost:8080")

    # Create stdio configuration
    config = ExMCP.ClientConfig.new(:stdio, command: ["python", "server.py"])

    # Start with empty configuration
    config = ExMCP.ClientConfig.new()

# `new`

```elixir
@spec new(profile() | transport_type()) :: t()
```

# `new`

```elixir
@spec new(
  transport_type(),
  keyword()
) :: t()
```

# `put_auth`

```elixir
@spec put_auth(t(), auth_type(), keyword()) :: t()
```

Configures authentication settings.

## Examples

    # Bearer token
    config = ExMCP.ClientConfig.new()
    |> ExMCP.ClientConfig.put_auth(:bearer, token: "your-token")

    # Basic auth
    config = ExMCP.ClientConfig.new()
    |> ExMCP.ClientConfig.put_auth(:basic, username: "user", password: "pass")

    # Custom headers
    config = ExMCP.ClientConfig.new()
    |> ExMCP.ClientConfig.put_auth(:custom, headers: %{"X-API-Key" => "key"})

# `put_client_info`

```elixir
@spec put_client_info(
  t(),
  keyword()
) :: t()
```

Sets client information.

## Examples

    config = ExMCP.ClientConfig.new()
    |> ExMCP.ClientConfig.put_client_info(
      name: "MyApp MCP Client",
      version: "1.0.0"
    )

# `put_custom`

```elixir
@spec put_custom(t(), atom(), any()) :: t()
```

Adds custom configuration options.

## Examples

    config = ExMCP.ClientConfig.new()
    |> ExMCP.ClientConfig.put_custom(:my_option, "value")
    |> ExMCP.ClientConfig.put_custom(:another_option, %{key: "value"})

# `put_observability`

```elixir
@spec put_observability(
  t(),
  keyword()
) :: t()
```

Configures observability settings.

## Examples

    config = ExMCP.ClientConfig.new()
    |> ExMCP.ClientConfig.put_observability(
      logging: [enabled: true, level: :info],
      telemetry: [enabled: true, prefix: [:my_app, :mcp]]
    )

# `put_pool`

```elixir
@spec put_pool(
  t(),
  keyword()
) :: t()
```

Configures connection pooling settings.

## Examples

    config = ExMCP.ClientConfig.new()
    |> ExMCP.ClientConfig.put_pool(
      enabled: true,
      size: 10,
      max_overflow: 5
    )

# `put_retry_policy`

```elixir
@spec put_retry_policy(
  t(),
  keyword()
) :: t()
```

Configures retry policy settings.

## Examples

    config = ExMCP.ClientConfig.new()
    |> ExMCP.ClientConfig.put_retry_policy(
      max_attempts: 5,
      base_interval: 1000,
      backoff_type: :exponential
    )

# `put_timeout`

```elixir
@spec put_timeout(
  t(),
  keyword()
) :: t()
```

Configures timeout settings.

## Examples

    # Basic timeouts
    config = ExMCP.ClientConfig.new()
    |> ExMCP.ClientConfig.put_timeout(
      total: 120_000,
      connect: 10_000,
      request: 30_000
    )

    # Advanced timeouts with stream and pool settings
    config = ExMCP.ClientConfig.new()
    |> ExMCP.ClientConfig.put_timeout(
      total: 120_000,
      connect: 10_000,
      request: 30_000,
      stream: [handshake: 15_000, idle: 60_000],
      pool: [checkout: 5_000, idle: 300_000]
    )

## Timeout Types

- `total`: Maximum time for entire operation including retries (ms)
- `connect`: Time to establish TCP/TLS connection (ms)
- `request`: Time for single request-response cycle (ms)
- `stream.handshake`: Time to wait for SSE handshake completion (ms)
- `stream.idle`: Time stream can be idle before considered dead (ms)
- `pool.checkout`: Time to wait for connection from pool (ms)
- `pool.idle`: Time connection can idle in pool before cleanup (ms)

# `put_transport`

```elixir
@spec put_transport(t(), transport_type(), keyword()) :: t()
```

Configures the transport settings.

## Examples

    config = ExMCP.ClientConfig.new()
    |> ExMCP.ClientConfig.put_transport(:http, url: "http://localhost:8080")

    config = ExMCP.ClientConfig.new()
    |> ExMCP.ClientConfig.put_transport(:stdio, command: ["python", "server.py"])

# `to_client_opts`

```elixir
@spec to_client_opts(t()) :: keyword()
```

Converts the configuration to a keyword list suitable for client APIs.

## Examples

    config = ExMCP.ClientConfig.new(:http, url: "http://localhost:8080")
    opts = ExMCP.ClientConfig.to_client_opts(config)
    {:ok, client} = ExMCP.Client.start_link(opts)

# `validate`

```elixir
@spec validate(t()) :: :ok | {:error, [String.t()]}
```

Validates the configuration and returns errors if any.

## Examples

    case ExMCP.ClientConfig.validate(config) do
      :ok -> {:ok, client} = ExMCP.connect(config)
      {:error, errors} -> handle_config_errors(errors)
    end

---

*Consult [api-reference.md](api-reference.md) for complete listing*
