Configuration

This covers all the configuration options available for RubyLLM MCP clients, including transport settings, connection options, and advanced features.

Table of contents

  1. Global Configuration
  2. Client Configuration
    1. Basic Client Options
    2. Transport-Specific Configuration
      1. STDIO Transport
      2. SSE Transport
      3. Streamable HTTP Transport
  3. Advanced Configuration
    1. Request Timeout
    2. Manual Connection Control
    3. Complex Parameter Support
  4. Logging Configuration
    1. Basic Logging
    2. Custom Logger
    3. Log Levels
  5. Sampling Configuration
  6. Roots Configuration
  7. Elicitation Configuration
    1. OAuth Authentication
  8. Protocol Version Configuration
    1. Setting Protocol Version in Transport Config
    2. Available Protocol Versions
    3. Protocol Version Features
    4. Enhanced Metadata Support
  9. Error Handling Configuration
    1. Timeout Handling
    2. Connection Error Handling
  10. Next Steps

Global Configuration

Configure RubyLLM MCP globally before creating clients:

RubyLLM::MCP.configure do |config|
  # Enable complex parameter support
  config.support_complex_parameters!

  # Set logging options
  config.log_file = $stdout
  config.log_level = Logger::INFO

  # Or use a custom logger
  config.logger = Logger.new(STDOUT)

  # Paths to MCP servers
  config.mcps_config_path = "../mcps.yml"

  # Connection Pool for HTTP and SSE transports
  config.max_connections = 10
  config.pool_timeout = 5

  # Event handlers, these will be used for all clients, unless overridden on the client level
  config.on_progress do |progress|
    puts "Progress: #{progress}"
  end
  config.on_human_in_the_loop do |human_in_the_loop|
    puts "Human in the loop: #{human_in_the_loop}"
  end
  config.on_logging do |level, message|
    puts "Logging: #{level} - #{message}"
  end

  # Configure roots for filesystem access
  config.roots = ["/path/to/project", Rails.root]

  # Configure sampling
  # Enabled the clinet to support sampling requests,default: false
  config.sampling.enabled = true

  # Configure sampling preferred model
  config.sampling.preferred_model = "gpt-4"

  # Configure sampling guard, which can be used to filter out samples that are not wanted
  config.sampling.guard do |sample|
    sample.message.include?("Hello")
  end

  # Configure elicitation support (2025-06-18 protocol)
  config.on_elicitation do |elicitation|
    # Handle elicitation requests from MCP servers
    # Return structured response and true to accept
    puts "Server requests: #{elicitation.message}"
    elicitation.structured_response = { "response": "handled" }
    true
  end
end

Client Configuration

Basic Client Options

All MCP clients support these common options:

client = RubyLLM::MCP.client(
  name: "unique-client-name",          # Required: unique identifier
  transport_type: :stdio,              # Required: :stdio, :sse, or :streamable
  start: true,                         # Optional: auto-start connection (default: true)
  request_timeout: 8000,               # Optional: timeout in milliseconds (default: 8000)
  config: {                            # Required: transport-specific configuration
    # See transport sections below
  }
)

Transport-Specific Configuration

STDIO Transport

Best for local MCP servers or command-line tools:

client = RubyLLM::MCP.client(
  name: "local-server",
  transport_type: :stdio,
  config: {
    command: "python",                 # Required: command to run
    args: ["-m", "my_mcp_server"],    # Optional: command arguments
    env: {                            # Optional: environment variables
      "DEBUG" => "1",
      "PATH" => "/custom/path"
    }
  }
)

Common STDIO configurations:

# Node.js MCP server
config: {
  command: "node",
  args: ["server.js"],
  env: { "NODE_ENV" => "production" }
}

# Python MCP server
config: {
  command: "python",
  args: ["-m", "mcp_server"],
  env: { "PYTHONPATH" => "/path/to/modules" }
}

# NPX package
config: {
  command: "npx",
  args: ["@modelcontextprotocol/server-filesystem", "/path/to/directory"]
}

SSE Transport

Best for web-based MCP servers using Server-Sent Events:

client = RubyLLM::MCP.client(
  name: "web-server",
  transport_type: :sse,
  config: {
    url: "https://api.example.com/mcp/sse",  # Required: SSE endpoint
    headers: {                               # Optional: HTTP headers
      "Authorization" => "Bearer #{ENV['API_TOKEN']}",
      "User-Agent" => "MyApp/1.0"
    }
  }
)

Streamable HTTP Transport

Best for HTTP-based MCP servers that support streaming:

client = RubyLLM::MCP.client(
  name: "streaming-server",
  transport_type: :streamable,
  config: {
    url: "https://api.example.com/mcp",      # Required: HTTP endpoint
    headers: {                               # Optional: HTTP headers
      "Authorization" => "Bearer #{ENV['API_TOKEN']}",
      "Content-Type" => "application/json"
    }
  }
)

Advanced Configuration

Request Timeout

Control how long to wait for responses:

client = RubyLLM::MCP.client(
  name: "slow-server",
  transport_type: :stdio,
  request_timeout: 30000,  # 30 seconds
  config: { command: "slow-mcp-server" }
)

Manual Connection Control

Create clients without auto-starting:

client = RubyLLM::MCP.client(
  name: "manual-server",
  transport_type: :stdio,
  start: false,  # Don't start automatically
  config: { command: "mcp-server" }
)

# Start when ready
client.start

# Check status
puts client.alive?

# Restart if needed
client.restart!

# Stop when done
client.stop

Complex Parameter Support

Enable support for complex parameters like arrays and nested objects:

RubyLLM::MCP.configure do |config|
  config.support_complex_parameters!
end

# Now you can use complex parameters in tools
result = client.execute_tool(
  name: "complex_tool",
  parameters: {
    items: [
      { name: "item1", value: 100 },
      { name: "item2", value: 200 }
    ],
    options: {
      sort: true,
      filter: { category: "active" }
    }
  }
)

Logging Configuration

Basic Logging

RubyLLM::MCP.configure do |config|
  config.log_file = $stdout
  config.log_level = Logger::INFO
end

Custom Logger

# File-based logging
logger = Logger.new("mcp.log")
logger.level = Logger::DEBUG

RubyLLM::MCP.configure do |config|
  config.logger = logger
end

Log Levels

Available log levels:

  • Logger::DEBUG - Detailed debugging information
  • Logger::INFO - General information
  • Logger::WARN - Warning messages
  • Logger::ERROR - Error messages only
  • Logger::FATAL - Fatal errors only

Sampling Configuration

Enable MCP servers to use your LLM for their own requests:

RubyLLM::MCP.configure do |config|
  config.sampling.enabled = true
  config.sampling.preferred_model = "gpt-4"

  # Or use dynamic model selection
  config.sampling.preferred_model do |model_preferences|
    # Use the server's preferred model if available
    model_preferences.hints.first || "gpt-4"
  end

  # Add guards to control what gets processed
  config.sampling.guard do |sample|
    # Only allow samples containing "Hello"
    sample.message.include?("Hello")
  end
end

Roots Configuration

Provide filesystem access to MCP servers:

RubyLLM::MCP.configure do |config|
  config.roots = [
    "/path/to/project",
    Rails.root,
    Pathname.new("/another/path")
  ]
end

# Access roots in your client
client = RubyLLM::MCP.client(...)
puts client.roots.paths
# => ["/path/to/project", "/path/to/rails/root", "/another/path"]

# Modify roots at runtime
client.roots.add("/new/path")
client.roots.remove("/old/path")

Elicitation Configuration

Configure how your client handles elicitation requests from servers:

RubyLLM::MCP.configure do |config|
  # Global elicitation handler
  config.on_elicitation do |elicitation|
    puts "Server message: #{elicitation.message}"

    # Auto-approve simple requests
    if elicitation.message.include?("confirmation")
      elicitation.structured_response = { "confirmed": true }
      true
    else
      # Reject complex requests
      false
    end
  end
end

# Or configure per-client
client.on_elicitation do |elicitation|
  # Interactive handler
  puts elicitation.message
  puts "Expected response format: #{elicitation.requested_schema}"

  # Collect user input
  response = collect_user_response(elicitation.requested_schema)
  elicitation.structured_response = response
  true
end

OAuth Authentication

Configure OAuth for Streamable HTTP transport:

client = RubyLLM::MCP.client(
  name: "oauth-server",
  transport_type: :streamable,
  config: {
    url: "https://api.example.com/mcp",
    oauth: {
      issuer: ENV['OAUTH_ISSUER'],
      client_id: ENV['OAUTH_CLIENT_ID'],
      client_secret: ENV['OAUTH_CLIENT_SECRET'],
      scope: "mcp:read mcp:write"
    }
  }
)

Protocol Version Configuration

You can configure which MCP protocol version the client should use when connecting to servers. This is useful for testing newer protocol features or ensuring compatibility with specific server versions.

Setting Protocol Version in Transport Config

# Force client to use a specific protocol version
client = RubyLLM::MCP::Client.new(
  name: "my-server",
  transport_type: :stdio,
  config: {
    command: ["node", "server.js"],
    protocol_version: "2025-06-18"  # Override default version
  }
)

Available Protocol Versions

The RubyLLM MCP client supports multiple protocol versions. You can access these through the protocol constants:

# Latest supported protocol version
puts RubyLLM::MCP::Protocol.latest_version
# => "2025-06-18"

# Default version used for negotiation
puts RubyLLM::MCP::Protocol.default_negotiated_version
# => "2025-03-26"

# All supported versions
puts RubyLLM::MCP::Protocol.supported_versions
# => ["2025-06-18", "2025-03-26", "2024-11-05", "2024-10-07"]

# Check if a version is supported
RubyLLM::MCP::Protocol.supported_version?("2025-06-18")
# => true

Protocol Version Features

Different protocol versions support different features:

  • 2025-06-18 (Latest): Structured tool output, OAuth authentication, elicitation support, resource links, enhanced metadata
  • 2025-03-26 (Default): Tool calling, resources, prompts, completions, notifications
  • 2024-11-05: Basic tool and resource support
  • 2024-10-07: Initial MCP implementation

Enhanced Metadata Support

Progress tracking automatically includes metadata when enabled:

RubyLLM::MCP.configure do |config|
  # Enable progress tracking with metadata
  config.on_progress do |progress|
    puts "Operation ID: #{progress.operation_id}"
    puts "Progress: #{progress.progress}%"
    puts "Metadata: #{progress.metadata}"
  end
end

# Tool calls will automatically include progress tokens
client = RubyLLM::MCP.client(...)
tool = client.tool("long_operation")
result = tool.execute(data: "large_dataset")  # Includes progress metadata

Error Handling Configuration

Timeout Handling

client = RubyLLM::MCP.client(
  name: "timeout-server",
  transport_type: :stdio,
  request_timeout: 5000,
  config: { command: "slow-server" }
)

begin
  result = client.execute_tool(name: "slow_tool", parameters: {})
rescue RubyLLM::MCP::Errors::TimeoutError => e
  puts "Request timed out: #{e.message}"
end

Connection Error Handling

begin
  client = RubyLLM::MCP.client(
    name: "failing-server",
    transport_type: :stdio,
    config: { command: "nonexistent-command" }
  )
rescue RubyLLM::MCP::Errors::TransportError => e
  puts "Failed to start server: #{e.message}"
end

Next Steps