Adapters & Transports
1.0+
RubyLLM MCP 1.0 provides a mature, stable adapter system with multiple SDK implementations and transport types, giving you complete control over how your application communicates with MCP servers.
Table of contents
- Overview
- Available Adapters
- Feature Comparison
- Transport Compatibility
- Built-in Transport Types
- Configuration
- Using the MCP SDK Adapter
- Mixed Adapter Usage
- Custom Transports
- Best Practices
- Troubleshooting
- Next Steps
Overview
RubyLLM MCP provides two key architectural components:
Adapters - Choose which SDK implementation powers your MCP clients:
- Use the native
:ruby_llmadapter for full MCP feature support built inside the gem - Use the official
:mcp_sdkadapter maintained by Anthropic (requires Ruby 3.1+) - Mix both adapters in the same application for different servers
Transports - Handle the communication layer between your Ruby client and MCP servers:
- Establish connections
- Send requests and receive responses
- Manage the connection lifecycle
- Handle protocol-specific details
Available Adapters
RubyLLM Adapter (:ruby_llm)
The default, full-featured adapter that implements the complete MCP protocol with extensions.
Key Features:
- ✅ Complete MCP protocol implementation with advanced features (sampling, roots, progress tracking, elicitation)
- ✅ All transport types supported (stdio, SSE, streamable HTTP)
- ✅ Custom transport support - Register and use your own transport implementations
- ✅ Ruby 2.7+ compatible
Best for: Full-featured MCP integrations, custom transport requirements, and advanced protocol features.
MCP SDK Adapter (:mcp_sdk)
Wraps the official MCP SDK maintained by Anthropic.
Ruby 3.1+ Required The official
mcpgem requires Ruby 2.7+, and RubyLLM MCP requires Ruby 3.1.3+. If you’re using an older Ruby version, use the:ruby_llmadapter instead.
Key Features:
- ✅ Official Anthropic-maintained implementation
- ✅ Core MCP features (tools, resources, prompts, resource templates, logging)
- ✅ Basic transports (stdio, HTTP) with custom wrapper support
- ⚠️ No custom transport registration - requires Ruby 3.1+
Best for: Reference implementation compatibility and core MCP features only.
Feature Comparison
| Feature | RubyLLM Adapter | MCP SDK Adapter |
|---|---|---|
| Core Features | ||
| Tools (list/call) | ✅ | ✅ |
| Resources (list/read) | ✅ | ✅ |
| Prompts (list/get) | ✅ | ✅ |
| Resource Templates | ✅ | ✅ |
| Transports | ||
| stdio | ✅ | ✅ |
| HTTP/Streamable | ✅ | ✅ |
| SSE | ✅ | ✅ |
| Advanced Features | ||
| Completions | ✅ | ❌ |
| Logging | ✅ | ✅ |
| Sampling | ✅ | ❌ |
| Roots | ✅ | ❌ |
| Notifications | ✅ | ❌ |
| Progress Tracking | ✅ | ❌ |
| Human-in-the-Loop | ✅ | ❌ |
| Elicitation | ✅ | ❌ |
| Resource Subscriptions | ✅ | ❌ |
Transport Compatibility
Custom transports are implemented by the adapter and are not part of the official MCP SDK and are based on the native transports.
| Transport | RubyLLM Adapter | MCP SDK Adapter |
|---|---|---|
:stdio | ✅ | Custom |
:http | ✅ | ✅ |
:streamable | ✅ | Custom |
:streamable_http | ✅ | Custom |
:sse | ✅ | Custom |
Built-in Transport Types
STDIO Transport
Best for local MCP servers that communicate via standard input/output:
client = RubyLLM::MCP.client(
name: "local-server",
transport_type: :stdio,
config: {
command: "python",
args: ["-m", "my_mcp_server"],
env: { "DEBUG" => "1" }
}
)
Use cases:
- Local development
- Command-line MCP servers
- Subprocess-based servers
SSE Transport (Server-Sent Events)
Best for web-based MCP servers using HTTP with server-sent events:
client = RubyLLM::MCP.client(
name: "web-server",
transport_type: :sse,
config: {
url: "https://api.example.com/mcp/sse",
version: :http2, # You can force HTTP/1.1 by setting this to :http1, default will try to setup HTTP/2 connection
headers: { "Authorization" => "Bearer token" }
}
)
Use cases:
- Web-based MCP services
- Real-time communication needs
- HTTP-based infrastructure
Streamable HTTP Transport
Best for HTTP-based MCP servers that support streaming responses:
client = RubyLLM::MCP.client(
name: "streaming-server",
transport_type: :streamable,
config: {
url: "https://api.example.com/mcp",
version: :http2, # You can force HTTP/1.1 by setting this to :http1, default will try to setup HTTP/2 connection
headers: { "Content-Type" => "application/json" }
}
)
OAuth Authentication
OAuth authentication is available in MCP Protocol 2025-06-18 for Streamable HTTP transport.
For servers requiring OAuth authentication:
client = RubyLLM::MCP.client(
name: "oauth-server",
transport_type: :streamable,
config: {
url: "https://api.example.com/mcp",
oauth: {
issuer: "https://oauth.provider.com",
client_id: "your-client-id",
client_secret: "your-client-secret",
scope: "mcp:read mcp:write" # Optional
}
}
)
OAuth Configuration:
| Option | Description | Required |
|---|---|---|
issuer | OAuth provider’s issuer URL | Yes |
client_id | OAuth client identifier | Yes |
client_secret | OAuth client secret | Yes |
scope | Requested OAuth scopes | No |
The client automatically handles token acquisition, refresh, and authorization headers.
Use cases:
- REST API-based MCP servers
- HTTP-first architectures
- Cloud-based MCP services
- Enterprise servers requiring OAuth
Configuration
Global Default Adapter
Set the default adapter for all clients in your configuration:
RubyLLM::MCP.configure do |config|
config.default_adapter = :ruby_llm # or :mcp_sdk
end
Per-Client Adapter
Override the adapter for individual clients:
# Using RubyLLM adapter
client = RubyLLM::MCP.client(
name: "filesystem",
adapter: :ruby_llm,
transport_type: :stdio,
config: {
command: "npx",
args: ["@modelcontextprotocol/server-filesystem", "/path"]
}
)
# Using MCP SDK adapter
client = RubyLLM::MCP.client(
name: "weather",
adapter: :mcp_sdk,
transport_type: :http,
config: {
url: "https://api.example.com/mcp"
}
)
YAML Configuration
In config/mcps.yml:
mcp_servers:
filesystem:
adapter: ruby_llm
transport_type: stdio
command: npx
args:
- "@modelcontextprotocol/server-filesystem"
- "/path/to/directory"
api_server:
adapter: mcp_sdk
transport_type: http
url: "https://api.example.com/mcp"
headers:
Authorization: "Bearer <%= ENV['API_KEY'] %>"
Using the MCP SDK Adapter
Installation
Ruby 3.1+ Required The official
mcpgem supports Ruby 2.7+, and RubyLLM MCP supports Ruby 3.1.3+.
The official MCP SDK is an optional dependency. Add it to your Gemfile when using the :mcp_sdk adapter:
gem 'ruby_llm-mcp', '~> 1.0'
gem 'mcp', '~> 0.7' # Required for mcp_sdk adapter
Then run:
bundle install
Basic Usage
# Configure to use MCP SDK
client = RubyLLM::MCP.client(
name: "my_server",
adapter: :mcp_sdk,
transport_type: :stdio,
config: {
command: "python",
args: ["-m", "my_mcp_server"]
}
)
# Core features work the same
tools = client.tools
resources = client.resources
prompts = client.prompts
# Call tools normally
tool = client.tool("calculator")
result = tool.execute(operation: "add", a: 5, b: 3)
SSE Transport
The :mcp_sdk adapter supports SSE (Server-Sent Events) transport for HTTP-based servers:
# Configure MCP SDK with SSE transport
client = RubyLLM::MCP.client(
name: "remote_server",
adapter: :mcp_sdk,
transport_type: :sse,
config: {
url: "https://api.example.com/mcp/sse",
headers: {
"Authorization" => "Bearer #{ENV['API_KEY']}"
}
}
)
# Use the client normally
tools = client.tools
tool = client.tool("process_data")
result = tool.execute(data: "example")
In YAML configuration:
mcp_servers:
remote_sse_server:
adapter: mcp_sdk
transport_type: sse
url: "https://api.example.com/mcp/sse"
headers:
Authorization: "Bearer <%= ENV['API_KEY'] %>"
Feature Limitations
When using :mcp_sdk, attempting to use unsupported features will raise helpful errors:
client = RubyLLM::MCP.client(
name: "server",
adapter: :mcp_sdk,
transport_type: :stdio,
config: { command: "server" }
)
# This will raise UnsupportedFeature error
client.on_progress do |progress|
# Progress tracking not available in mcp_sdk
end
# => RubyLLM::MCP::Errors::UnsupportedFeature:
# Feature 'progress_tracking' is not supported by the mcp_sdk adapter.
# This feature requires the :ruby_llm adapter.
Mixed Adapter Usage
You can use different adapters for different servers in the same application:
RubyLLM::MCP.configure do |config|
config.default_adapter = :ruby_llm
config.mcp_configuration = [
# Use RubyLLM adapter for local filesystem (needs roots)
{
name: "filesystem",
adapter: :ruby_llm,
transport_type: :stdio,
config: {
command: "npx",
args: ["@modelcontextprotocol/server-filesystem", Rails.root]
}
},
# Use MCP SDK for external API (simple HTTP)
{
name: "weather",
adapter: :mcp_sdk,
transport_type: :http,
config: {
url: "https://weather-api.example.com/mcp"
}
}
]
end
# Both clients work together
RubyLLM::MCP.establish_connection do |clients|
fs_client = clients["filesystem"] # Using ruby_llm adapter
weather_client = clients["weather"] # Using mcp_sdk adapter
# Both provide tools to RubyLLM
all_tools = RubyLLM::MCP.tools
end
Custom Transports
RubyLLM Adapter Only
The :ruby_llm adapter supports registering custom transport implementations, allowing you to extend the gem with your own communication protocols.
Transport Interface
All transport implementations must implement the following interface:
class CustomTransport
# Initialize the transport
def initialize(coordinator:, **config)
@coordinator = coordinator
@config = config
end
# Send a request and optionally wait for response
def request(body, add_id: true, wait_for_response: true)
# Implementation specific
end
# Check if transport is alive/connected
def alive?
# Implementation specific
end
# Start the transport connection
def start
# Implementation specific
end
# Close the transport connection
def close
# Implementation specific
end
# Set the MCP protocol version
def set_protocol_version(version)
@protocol_version = version
end
end
Registering Custom Transports
Once you’ve created a custom transport, register it with the transport factory:
# Register your custom transport
RubyLLM::MCP::Native::Transport.register_transport(:websocket, WebSocketTransport)
RubyLLM::MCP::Native::Transport.register_transport(:redis_pubsub, RedisPubSubTransport)
# Now you can use it with any client using the ruby_llm adapter
client = RubyLLM::MCP.client(
name: "websocket-server",
adapter: :ruby_llm, # Custom transports only work with ruby_llm adapter
transport_type: :websocket,
config: {
url: "ws://localhost:8080/mcp",
headers: { "Authorization" => "Bearer token" }
}
)
Best Practices
Choosing an Adapter
- Start with
:ruby_llmif you’re unsure - it supports all features - Use
:mcp_sdkwhen you specifically need the official implementation - Check feature requirements before choosing an adapter
- Consider transport and feature needs - advanced client features still require
:ruby_llm - Check Ruby version -
:mcp_sdkrequires Ruby 3.1+
Upgrading from 1.0
If you’re upgrading from version 1.0:
- The default adapter is
:ruby_llm- no changes needed for existing code - All existing features continue to work as before
- Optionally migrate specific clients to
:mcp_sdkif desired
Troubleshooting
“Feature not supported” errors
If you see errors about unsupported features:
- Check which adapter you’re using
- Verify the feature is supported (see feature comparison table)
- Switch to
:ruby_llmadapter if you need the feature
“Transport not supported” errors
If you see transport errors:
- Verify the transport is compatible with your adapter
- Prefer
:stdioor:streamablefor maximum compatibility - Use
:httpfor simple JSON request/response servers
Missing MCP gem
If you see “LoadError: cannot load such file – mcp”:
- Add
gem 'mcp', '~> 0.7'to your Gemfile - Run
bundle install - Ensure you’re running Ruby 3.1 or higher
- This is only needed when using
adapter: :mcp_sdk
Ruby Version Compatibility
If you encounter issues with the :mcp_sdk adapter:
- Check your Ruby version:
ruby -v - The
mcpgem requires Ruby 2.7 or higher (RubyLLM MCP requires 3.1.3+) - Switch to
:ruby_llmadapter if you’re on an older Ruby version - Consider upgrading Ruby if you need the official SDK
Next Steps
- Configuration - Detailed configuration options
- Getting Started - Quick start guide
- Tools - Working with MCP tools
- Resources - Managing resources
- Notifications - Handling real-time updates
- Upgrading from 0.8 to 1.0 - Migration guide