# ExMCP Configuration Guide

This guide covers all configuration options available in ExMCP, from basic setup to advanced production configurations.

## Table of Contents

1. [Basic Configuration](#basic-configuration)
2. [Protocol Version Configuration](#protocol-version-configuration)
3. [Transport Configuration](#transport-configuration)
4. [Security Configuration](#security-configuration)
5. [Logging Configuration](#logging-configuration)
6. [Performance Configuration](#performance-configuration)
7. [Production Configuration](#production-configuration)
8. [Environment-Specific Configuration](#environment-specific-configuration)

## Basic Configuration

### Application Configuration

Configure ExMCP in your `config/config.exs`:

```elixir
# config/config.exs
config :ex_mcp,
  # Default protocol version
  protocol_version: "2025-11-25",

  # Global timeout settings
  default_timeout: 30_000,
  request_timeout: 15_000,
  
  # Connection settings
  auto_reconnect: true,
  reconnect_backoff: [initial: 1000, max: 30_000],
  
  # Logging level
  log_level: :info
```

### Mix Project Configuration

In your `mix.exs`:

```elixir
def deps do
  [
    {:ex_mcp, "~> 1.0.0-rc.0"}
  ]
end
```

## Protocol Version Configuration

ExMCP supports multiple MCP protocol versions. Choose based on your needs:

### Available Versions

```elixir
config :ex_mcp,
  protocol_version: "2024-11-05"  # Maximum compatibility
  # OR
  protocol_version: "2025-03-26"  # Stable baseline
  # OR
  protocol_version: "2025-06-18"  # Structured output, elicitation, OAuth 2.1
  # OR
  protocol_version: "2025-11-25"  # Latest (recommended)
```

### Version Feature Matrix

| Feature | 2024-11-05 | 2025-03-26 | 2025-06-18 | 2025-11-25 |
|---------|:----------:|:----------:|:----------:|:----------:|
| **Core Features** | | | | |
| Tools, Resources, Prompts | ✅ | ✅ | ✅ | ✅ |
| Bi-directional requests | ✅ | ✅ | ✅ | ✅ |
| Request cancellation | ✅ | ✅ | ✅ | ✅ |
| Progress notifications | ✅ | ✅ | ✅ | ✅ |
| **2025-03-26 Features** | | | | |
| Resource subscriptions | -- | ✅ | ✅ | ✅ |
| Roots | -- | ✅ | ✅ | ✅ |
| Structured logging | -- | ✅ | ✅ | ✅ |
| Tool annotations | -- | ✅ | ✅ | ✅ |
| **2025-06-18 Features** | | | | |
| Structured tool output | -- | -- | ✅ | ✅ |
| Elicitation support | -- | -- | ✅ | ✅ |
| OAuth 2.1 Resource Server | -- | -- | ✅ | ✅ |
| **2025-11-25 Features** | | | | |
| Tasks (async long-running tools) | -- | -- | -- | experimental |
| Icons metadata | -- | -- | -- | ✅ |
| URL-mode elicitation | -- | -- | -- | ✅ |
| Tool calling in sampling | -- | -- | -- | ✅ |
| Enhanced OAuth/OIDC (incremental scope) | -- | -- | -- | ✅ |
| JWT client authentication (private_key_jwt) | -- | -- | -- | ✅ |
| Enterprise SSO / ID-JAG | -- | -- | -- | ✅ |

### Recommendations

- **Production**: Use `"2025-11-25"` for the latest features
- **Compatibility**: Use `"2024-11-05"` for maximum compatibility with older clients

## Transport Configuration

### stdio Transport

For subprocess communication:

```elixir
# Server configuration
{:ok, server} = MyServer.start_link(
  transport: :stdio
)

# Client configuration
{:ok, client} = ExMCP.Client.start_link(
  transport: :stdio,
  command: ["python", "mcp-server.py"],
  args: ["--config", "prod.json"],
  timeout: 30_000,
  
  # Optional environment variables
  env: [{"PYTHONPATH", "/opt/myapp"}],
  
  # Working directory
  cd: "/path/to/server"
)
```

### HTTP Transport (Streamable HTTP)

For network communication with optional Server-Sent Events:

```elixir
# Server configuration
{:ok, server} = MyServer.start_link(
  transport: :http,
  port: 8080,
  path: "/mcp",
  
  # SSE configuration
  sse_enabled: true,
  sse_path: "/events",
  
  # Security
  cors_enabled: true,
  allowed_origins: ["https://app.example.com"],
  
  # Connection limits
  max_connections: 1000,
  timeout: 60_000
)

# Client configuration
{:ok, client} = ExMCP.Client.start_link(
  transport: :http,
  url: "http://localhost:8080",
  endpoint: "/mcp/v1",
  
  # Authentication
  headers: [
    {"Authorization", "Bearer #{token}"},
    {"X-API-Key", api_key}
  ],
  
  # Connection options
  timeout: 30_000,
  request_timeout: 15_000,
  
  # SSE options
  use_sse: true,
  sse_timeout: 120_000
)
```

### BEAM-Local MCP

For high-performance intra-cluster communication:

```elixir
# Service configuration using macro
defmodule MyToolService do
  use ExMCP.Service, name: :my_tools
  
  # Service automatically registers with ExMCP.Native
  @impl true
  def handle_mcp_request(method, params, state) do
    # Handle MCP requests
    {:ok, response, state}
  end
end

# Start service
{:ok, _} = MyToolService.start_link()

# Direct calls
{:ok, result} = ExMCP.Native.call(:my_tools, "list_tools", %{})

# Cross-node calls
{:ok, result} = ExMCP.Native.call(
  {:my_service, :"node@cluster.local"}, 
  "tools/call", 
  %{"name" => "calculator", "arguments" => %{"a" => 1, "b" => 2}}
)

# For distributed clusters, opt in to Horde adapter:
# config :ex_mcp, :service_registry, ExMCP.ServiceRegistry.Horde
```

## Security Configuration

### Authentication Methods

#### Bearer Token Authentication

```elixir
# Client with bearer token
{:ok, client} = ExMCP.Client.start_link(
  transport: :http,
  url: "https://api.example.com",
  security: %{
    auth: {:bearer, "your-jwt-token"}
  }
)
```

#### API Key Authentication

```elixir
# Client with API key
{:ok, client} = ExMCP.Client.start_link(
  transport: :http,
  url: "https://api.example.com",
  headers: [{"X-API-Key", "your-api-key"}]
)
```

#### Basic Authentication

```elixir
# Client with basic auth
{:ok, client} = ExMCP.Client.start_link(
  transport: :http,
  url: "https://api.example.com",
  security: %{
    auth: {:basic, "username", "password"}
  }
)
```

#### OAuth 2.1 Configuration

```elixir
# OAuth 2.1 Resource Server (MCP 2025-06-18)
config :ex_mcp, :oauth,
  issuer: "https://auth.example.com",
  audience: "mcp-api",
  jwks_uri: "https://auth.example.com/.well-known/jwks.json",
  cache_jwks: true,
  cache_ttl: 3600
```

#### JWT Client Authentication (private_key_jwt)

For machine-to-machine auth using JWT client assertions (RFC 7523) instead of client secrets:

```elixir
# Load your private key
{:ok, private_key} = ExMCP.Authorization.JWT.load_key({:pem_file, "/path/to/key.pem"})

# Client credentials flow with JWT authentication
{:ok, token} = ExMCP.Authorization.OAuthFlow.client_credentials_jwt_flow(%{
  client_id: "my-client",
  private_key: private_key,
  token_endpoint: "https://auth.example.com/token",
  scopes: ["mcp:read", "mcp:write"]
})
```

#### Enterprise-Managed Authorization (ID-JAG)

For enterprise SSO via ID-JAG (RFC 8693 token exchange + RFC 7523 JWT bearer grant):

```elixir
# After obtaining an OIDC ID token from the enterprise IdP
{:ok, access_token} = ExMCP.Authorization.EnterpriseFlow.execute(%{
  id_token: id_token_from_oidc,
  idp_token_endpoint: "https://idp.enterprise.com/token",
  as_issuer: "https://auth.example.com",
  resource_url: "https://mcp.example.com",
  client_id: "my-client"
})
```

### TLS/SSL Configuration

```elixir
# Server with TLS
{:ok, server} = MyServer.start_link(
  transport: :http,
  port: 8443,
  
  # TLS options
  https: [
    port: 8443,
    keyfile: "/path/to/private.key",
    certfile: "/path/to/certificate.crt",
    cacertfile: "/path/to/ca-bundle.crt"
  ]
)

# Client with TLS verification
{:ok, client} = ExMCP.Client.start_link(
  transport: :http,
  url: "https://secure.example.com:8443",
  
  # TLS options
  ssl: [
    verify: :verify_peer,
    cacertfile: "/path/to/ca-bundle.crt",
    depth: 2
  ]
)
```

### CORS Configuration

```elixir
# Server with CORS
{:ok, server} = MyServer.start_link(
  transport: :http,
  
  # CORS settings
  cors_enabled: true,
  allowed_origins: [
    "https://app.example.com",
    "https://staging.example.com"
  ],
  allowed_methods: ["GET", "POST", "OPTIONS"],
  allowed_headers: ["Authorization", "Content-Type"],
  max_age: 3600
)
```

### Origin Validation

```elixir
# Client with origin validation
{:ok, client} = ExMCP.Client.start_link(
  transport: :http,
  url: "https://api.example.com",
  security: %{
    validate_origin: true,
    allowed_origins: ["https://app.example.com"]
  }
)
```

## Logging Configuration

### Global Logging

```elixir
# Set global ExMCP log level
ExMCP.Logging.set_global_level("debug")

# Available levels: "debug", "info", "warning", "error"
```

### Production Logger Configuration

ExMCP includes security audit logging with structured metadata. Configure appropriately for your environment:

#### Development Configuration

```elixir
# config/dev.exs
config :logger, :console,
  metadata: [:request_id, :tag, :audit, :client_id, :reason, :registration_type]
```

#### Production Configuration Options

**Option 1: JSON Structured Logging (Recommended)**

```elixir
# In mix.exs
{:logger_json, "~> 5.1"}

# In config/prod.exs
config :logger,
  backends: [LoggerJSON]

config :logger_json, :backend,
  metadata: :all,  # Captures ALL metadata automatically
  json_encoder: Jason,
  formatter: LoggerJSON.Formatters.GoogleCloudLogger
```

**Option 2: Separate Security Audit Logs**

```elixir
# config/prod.exs
config :logger,
  backends: [:console, {LoggerFileBackend, :security_audit}]

config :logger, :security_audit,
  path: "/var/log/ex_mcp/security_audit.log",
  level: :info,
  format: "$date $time [$level] $metadata $message\n",
  metadata: [:tag, :audit, :client_id, :reason, :registration_type],
  metadata_filter: [tag: :security_audit]  # Only security logs
```

**Option 3: External Log Aggregation**

```elixir
# For ELK Stack, Datadog, etc.
{:logstash_logger_backend, "~> 3.0"}

config :logger,
  backends: [{LogstashLoggerBackend, :logstash}]

config :logger, :logstash,
  host: "logstash.example.com",
  port: 5514,
  metadata: :all,
  type: "ex_mcp_security"
```

#### Logger Metadata Fields

ExMCP uses these metadata fields for security and debugging:

- **`:tag`** - Log categorization (e.g., `:security_audit`, `:client_registration`)
- **`:audit`** - Detailed audit log entries with timestamps and actions
- **`:client_id`** - Client identification for request tracking
- **`:reason`** - Failure reasons and error details
- **`:registration_type`** - Client registration type (`:static` or `:dynamic`)
- **`:request_id`** - Correlation ID for distributed tracing

### Structured Logging in Code

```elixir
# Server logging with automatic security sanitization
defmodule MyServer do
  use ExMCP.Server.Handler

  @impl true
  def handle_call_tool("login", params, state) do
    server = self()
    
    # This logs to both MCP clients AND Elixir Logger
    # Sensitive data is automatically sanitized
    ExMCP.Logging.info(server, "User login attempt", %{
      username: params["username"],
      password: params["password"],  # Will be sanitized to "***"
      timestamp: DateTime.utc_now()
    })
    
    # ... handle login logic
    {:ok, result, state}
  end
end

# All RFC 5424 log levels supported
ExMCP.Logging.debug(server, "Debug info", %{details: "..."})
ExMCP.Logging.info(server, "Operation completed") 
ExMCP.Logging.warning(server, "Deprecated feature used")
ExMCP.Logging.error(server, "Operation failed", %{error: "connection_timeout"})
ExMCP.Logging.critical(server, "System component failure")
```

## Performance Configuration

### Connection Pooling

```elixir
# HTTP client with connection pooling
{:ok, client} = ExMCP.Client.start_link(
  transport: :http,
  url: "https://api.example.com",
  
  # Connection pool settings
  pool_size: 10,
  pool_max_overflow: 5,
  pool_timeout: 5000,
  
  # Keep-alive settings
  recv_timeout: 30_000,
  keepalive_timeout: 60_000
)
```

### BEAM-Local Optimization

```elixir
# Default: local Registry (zero deps, single-node)
# config :ex_mcp, :service_registry, ExMCP.ServiceRegistry.Local

# For distributed clusters, use Horde adapter:
# config :ex_mcp, :service_registry, ExMCP.ServiceRegistry.Horde
```

### Progress Tracking Configuration

```elixir
# Configure progress tracking thresholds
config :ex_mcp, :progress,
  # Minimum interval between progress notifications (ms)
  min_interval: 100,
  
  # Maximum number of pending progress tokens
  max_pending: 1000,
  
  # Cleanup interval for expired tokens (ms)
  cleanup_interval: 30_000
```

## Production Configuration

### Complete Production Example

```elixir
# config/prod.exs
import Config

# ExMCP main configuration
config :ex_mcp,
  protocol_version: "2025-11-25",
  default_timeout: 30_000,
  request_timeout: 15_000,
  auto_reconnect: true,
  reconnect_backoff: [initial: 1000, max: 30_000],
  log_level: :info

# Security configuration
config :ex_mcp, :security,
  enforce_https: true,
  validate_origins: true,
  max_request_size: 10_485_760  # 10MB

# OAuth 2.1 configuration (if using)
config :ex_mcp, :oauth,
  issuer: {:system, "OAUTH_ISSUER"},
  audience: {:system, "OAUTH_AUDIENCE"},
  jwks_uri: {:system, "OAUTH_JWKS_URI"},
  cache_jwks: true,
  cache_ttl: 3600

# Logging for production
config :logger,
  backends: [LoggerJSON]

config :logger_json, :backend,
  metadata: :all,
  json_encoder: Jason,
  formatter: LoggerJSON.Formatters.GoogleCloudLogger

# BEAM-local registry (default: local, use Horde for distributed)
# config :ex_mcp, :service_registry, ExMCP.ServiceRegistry.Horde

# SSL/TLS configuration
config :ex_mcp, :ssl,
  verify: :verify_peer,
  depth: 2,
  versions: [:"tlsv1.2", :"tlsv1.3"],
  ciphers: [
    "ECDHE-RSA-AES256-GCM-SHA384",
    "ECDHE-RSA-AES128-GCM-SHA256"
  ]
```

### Environment Variables

Support for runtime configuration via environment variables:

```elixir
# config/runtime.exs
import Config

if config_env() == :prod do
  config :ex_mcp,
    protocol_version: System.get_env("MCP_PROTOCOL_VERSION", "2025-11-25"),
    default_timeout: String.to_integer(System.get_env("MCP_TIMEOUT", "30000")),
    log_level: String.to_atom(System.get_env("MCP_LOG_LEVEL", "info"))

  # OAuth configuration from environment
  if oauth_issuer = System.get_env("OAUTH_ISSUER") do
    config :ex_mcp, :oauth,
      issuer: oauth_issuer,
      audience: System.get_env("OAUTH_AUDIENCE"),
      jwks_uri: System.get_env("OAUTH_JWKS_URI")
  end
end
```

## Environment-Specific Configuration

### Development Configuration

```elixir
# config/dev.exs
import Config

config :ex_mcp,
  protocol_version: "2025-11-25",
  log_level: :debug,
  auto_reconnect: false  # Easier debugging

# Verbose logging for development
config :logger, :console,
  format: "$time $metadata[$level] $message\n",
  metadata: [:request_id, :tag, :audit, :client_id]
```

### Test Configuration

```elixir
# config/test.exs
import Config

config :ex_mcp,
  protocol_version: "2025-11-25",
  default_timeout: 5_000,  # Faster tests
  log_level: :warning,     # Reduce test noise
  auto_reconnect: false    # Predictable test behavior

# Test logging
config :logger,
  level: :warning,
  backends: []  # Disable logging in tests
```

### Staging Configuration

```elixir
# config/staging.exs
import Config

# Similar to production but with more lenient settings
config :ex_mcp,
  protocol_version: "2025-11-25",
  log_level: :debug,               # More verbose for debugging
  
  # Relaxed security for testing
  security: %{
    enforce_https: false,
    validate_origins: false
  }
```

## Configuration Validation

### Runtime Validation

```elixir
# Add to application startup
defmodule MyApp.Application do
  use Application

  def start(_type, _args) do
    # Validate ExMCP configuration on startup
    :ok = ExMCP.Config.validate!()
    
    children = [
      # ... your children
    ]
    
    Supervisor.start_link(children, strategy: :one_for_one)
  end
end
```

### Configuration Helpers

```elixir
# Check current configuration
ExMCP.Config.get(:protocol_version)
ExMCP.Config.get(:default_timeout)

# Validate specific settings
ExMCP.Config.validate_protocol_version("2025-11-25")
ExMCP.Config.validate_transport_config(:http, options)
```

## Troubleshooting Configuration

### Common Issues

1. **Protocol Version Mismatch**
   ```
   Error: Unsupported protocol version "invalid"
   Solution: Use "2024-11-05", "2025-03-26", "2025-06-18", or "2025-11-25"
   ```

2. **Transport Configuration**
   ```
   Error: Invalid transport options
   Solution: Check transport-specific configuration requirements
   ```

3. **Authentication Failures**
   ```
   Error: Authentication failed
   Solution: Verify tokens, certificates, and authentication method
   ```

### Configuration Testing

```elixir
# Test configuration in IEx
iex> ExMCP.Config.test_config()
%{
  protocol_version: "2025-11-25",
  transports: [:stdio, :http, :beam],
  security: %{...},
  valid: true
}
```

### Debug Configuration

Enable debug logging to troubleshoot configuration issues:

```elixir
# Temporarily enable debug logging
ExMCP.Logging.set_global_level("debug")

# Check what configuration is actually loaded
ExMCP.Config.dump()
```

For more configuration help, see:
- [Security Guide](SECURITY.md) for security-specific configuration
- [Transport Guide](TRANSPORT_GUIDE.md) for transport optimization
- [Development Guide](DEVELOPMENT.md) for development setup
