freshcrate
Skin:/
Home > MCP Servers > ruby-mcp-client

ruby-mcp-client

This is a Ruby implementation of MCP (Model Context Protocol) client

Why this rank:Strong adoptionRelease freshnessHealthy release cadence

Description

This is a Ruby implementation of MCP (Model Context Protocol) client

README

ruby-mcp-client

A Ruby client for the Model Context Protocol (MCP), enabling integration with external tools and services via a standardized protocol.

Installation

# Gemfile
gem 'ruby-mcp-client'
bundle install
# or
gem install ruby-mcp-client

Overview

MCP enables AI assistants to discover and invoke external tools via different transport mechanisms:

  • stdio - Local processes implementing the MCP protocol
  • SSE - Server-Sent Events with streaming support
  • HTTP - Simple request/response (non-streaming)
  • Streamable HTTP - HTTP POST with SSE-formatted responses

Built-in API conversions: to_openai_tools(), to_anthropic_tools(), to_google_tools()

MCP Protocol Support

Implements MCP 2025-11-25 specification:

  • Tools: list, call, streaming, annotations (hint-style), structured outputs, title
  • Prompts: list, get with parameters
  • Resources: list, read, templates, subscriptions, pagination, ResourceLink content
  • Elicitation: Server-initiated user interactions (stdio, SSE, Streamable HTTP)
  • Roots: Filesystem scope boundaries with change notifications
  • Sampling: Server-requested LLM completions with modelPreferences
  • Completion: Autocomplete for prompts/resources with context
  • Logging: Server log messages with level filtering
  • Tasks: Structured task management with progress tracking
  • Audio: Audio content type support
  • OAuth 2.1: PKCE, server discovery, dynamic registration

Quick Connect API (Recommended)

The simplest way to connect to an MCP server:

require 'mcp_client'

# Auto-detect transport from URL
client = MCPClient.connect('http://localhost:8000/sse')      # SSE
client = MCPClient.connect('http://localhost:8931/mcp')      # Streamable HTTP
client = MCPClient.connect('npx -y @modelcontextprotocol/server-filesystem /home')  # stdio

# With options
client = MCPClient.connect('http://api.example.com/mcp',
  headers: { 'Authorization' => 'Bearer TOKEN' },
  read_timeout: 60,
  retries: 3,
  logger: Logger.new($stdout)
)

# Multiple servers
client = MCPClient.connect(['http://server1/mcp', 'http://server2/sse'])

# Force specific transport
client = MCPClient.connect('http://custom.com/api', transport: :streamable_http)

# Use the client
tools = client.list_tools
result = client.call_tool('example_tool', { param: 'value' })
client.cleanup

Transport Detection:

URL Pattern Transport
Ends with /sse SSE
Ends with /mcp Streamable HTTP
stdio://command or Array stdio
npx, node, python, etc. stdio
Other HTTP URLs Auto-detect (Streamable HTTP → SSE → HTTP)

Working with Tools, Prompts & Resources

# Tools
tools = client.list_tools
result = client.call_tool('tool_name', { param: 'value' })
result = client.call_tool('tool_name', { param: 'value' }, server: 'server_name')

# Batch tool calls
results = client.call_tools([
  { name: 'tool1', parameters: { key: 'value' } },
  { name: 'tool2', parameters: { key: 'value' }, server: 'specific_server' }
])

# Streaming (SSE/Streamable HTTP)
client.call_tool_streaming('tool', { param: 'value' }).each do |chunk|
  puts chunk
end

# Prompts
prompts = client.list_prompts
result = client.get_prompt('greeting', { name: 'Alice' })

# Resources
result = client.list_resources
contents = client.read_resource('file:///example.txt')
contents.each do |content|
  puts content.text if content.text?
  data = Base64.decode64(content.blob) if content.binary?
end

MCP 2025-11-25 Features

Tool Annotations

tool = client.find_tool('delete_user')

# Hint-style annotations (MCP 2025-11-25)
tool.read_only_hint?      # Defaults to true; tool does not modify environment
tool.destructive_hint?    # Defaults to false; tool may perform destructive updates
tool.idempotent_hint?     # Defaults to false; repeated calls have no additional effect
tool.open_world_hint?     # Defaults to true; tool may interact with external entities

# Legacy annotations
tool.read_only?              # Safe to execute?
tool.destructive?            # Warning: destructive operation
tool.requires_confirmation?  # Needs user confirmation

Structured Outputs

tool = client.find_tool('get_weather')
tool.structured_output?  # Has output schema?
tool.output_schema       # JSON Schema for output

result = client.call_tool('get_weather', { location: 'SF' })
data = result['structuredContent']  # Type-safe structured data

Roots

# Set filesystem scope boundaries
client.roots = [
  { uri: 'file:///home/user/project', name: 'Project' },
  { uri: 'file:///var/log', name: 'Logs' }
]

# Access current roots
client.roots

Sampling (Server-requested LLM completions)

# Configure handler when creating client
client = MCPClient.connect('http://server/mcp',
  sampling_handler: ->(messages, model_prefs, system_prompt, max_tokens) {
    # Process server's LLM request
    {
      'model' => 'gpt-4',
      'stopReason' => 'endTurn',
      'role' => 'assistant',
      'content' => { 'type' => 'text', 'text' => 'Response here' }
    }
  }
)

Completion (Autocomplete)

result = client.complete(
  ref: { type: 'ref/prompt', name: 'greeting' },
  argument: { name: 'name', value: 'A' }
)
# => { 'values' => ['Alice', 'Alex'], 'total' => 100, 'hasMore' => true }

Logging

# Set log level
client.log_level = 'debug'  # debug/info/notice/warning/error/critical

# Handle log notifications
client.on_notification do |server, method, params|
  if method == 'notifications/message'
    puts "[#{params['level']}] #{params['logger']}: #{params['data']}"
  end
end

Elicitation (Server-initiated user interactions)

client = MCPClient::Client.new(
  mcp_server_configs: [MCPClient.stdio_config(command: 'python server.py')],
  elicitation_handler: ->(message, schema) {
    puts "Server asks: #{message}"
    # Return: { 'action' => 'accept', 'content' => { 'field' => 'value' } }
    # Or: { 'action' => 'decline' } or { 'action' => 'cancel' }
  }
)

Advanced Configuration

For more control, use create_client with explicit configs:

client = MCPClient.create_client(
  mcp_server_configs: [
    MCPClient.stdio_config(command: 'npx server', name: 'local'),
    MCPClient.sse_config(
      base_url: 'https://api.example.com/sse',
      headers: { 'Authorization' => 'Bearer TOKEN' },
      read_timeout: 30, ping: 10, retries: 3
    ),
    MCPClient.http_config(
      base_url: 'https://api.example.com',
      endpoint: '/rpc',
      headers: { 'Authorization' => 'Bearer TOKEN' }
    ),
    MCPClient.streamable_http_config(
      base_url: 'https://api.example.com/mcp',
      read_timeout: 60, retries: 3
    )
  ],
  logger: Logger.new($stdout)
)

# Or load from JSON file
client = MCPClient.create_client(server_definition_file: 'servers.json')

Faraday Customization

MCPClient.http_config(base_url: 'https://internal.company.com') do |faraday|
  faraday.ssl.cert_store = custom_cert_store
  faraday.ssl.verify = true
end

Server Definition JSON

{
  "mcpServers": {
    "filesystem": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/home"]
    },
    "api": {
      "type": "streamable_http",
      "url": "https://api.example.com/mcp",
      "headers": { "Authorization": "Bearer TOKEN" }
    }
  }
}

AI Integration Examples

OpenAI

require 'mcp_client'
require 'openai'

mcp = MCPClient.connect('npx -y @modelcontextprotocol/server-filesystem .')
tools = mcp.to_openai_tools

client = OpenAI::Client.new(api_key: ENV['OPENAI_API_KEY'])
response = client.chat.completions.create(
  model: 'gpt-4',
  messages: [{ role: 'user', content: 'List files' }],
  tools: tools
)

Anthropic

require 'mcp_client'
require 'anthropic'

mcp = MCPClient.connect('npx -y @modelcontextprotocol/server-filesystem .')
tools = mcp.to_anthropic_tools

client = Anthropic::Client.new(access_token: ENV['ANTHROPIC_API_KEY'])
# Use tools with Claude API

RubyLLM

require 'mcp_client'
require 'ruby_llm'

RubyLLM.configure { |c| c.openai_api_key = ENV['OPENAI_API_KEY'] }
mcp = MCPClient.connect('http://localhost:8931/mcp')  # Playwright MCP

# Wrap each MCP tool as a RubyLLM tool
tools = mcp.list_tools.map do |t|
  tool_name = t.name
  Class.new(RubyLLM::Tool) do
    description t.description
    params t.schema
    define_method(:name) { tool_name }
    define_method(:execute) { |**args| mcp.call_tool(tool_name, args) }
  end.new
end

chat = RubyLLM.chat(model: 'gpt-4o-mini')
tools.each { |tool| chat.with_tool(tool) }
response = chat.ask('Navigate to google.com and tell me the page title')

See examples/ for complete implementations:

  • ruby_openai_mcp.rb, openai_ruby_mcp.rb - OpenAI integration
  • ruby_anthropic_mcp.rb - Anthropic integration
  • gemini_ai_mcp.rb - Google Vertex AI integration
  • ruby_llm_mcp.rb - RubyLLM integration (OpenAI provider)

OAuth 2.1 Authentication

require 'mcp_client/auth/browser_oauth'

oauth = MCPClient::Auth::OAuthProvider.new(
  server_url: 'https://api.example.com/mcp',
  redirect_uri: 'http://localhost:8080/callback',
  scope: 'mcp:read mcp:write'
)

browser_oauth = MCPClient::Auth::BrowserOAuth.new(oauth)
token = browser_oauth.authenticate  # Opens browser, handles callback

client = MCPClient::Client.new(
  mcp_server_configs: [{
    type: 'streamable_http',
    base_url: 'https://api.example.com/mcp',
    oauth_provider: oauth
  }]
)

Features: PKCE, server discovery (.well-known), dynamic registration, token refresh.

See OAUTH.md for full documentation.

Server Notifications

client.on_notification do |server, method, params|
  case method
  when 'notifications/tools/list_changed'
    client.clear_cache  # Auto-handled
  when 'notifications/message'
    puts "Log: #{params['data']}"
  when 'notifications/roots/list_changed'
    puts "Roots changed"
  end
end

Session Management

Both HTTP and Streamable HTTP transports automatically handle session-based servers:

  • Session capture: Extracts Mcp-Session-Id from initialize response
  • Session persistence: Includes session header in subsequent requests
  • Session termination: Sends DELETE request during cleanup
  • Resumability (Streamable HTTP): Tracks event IDs for message replay

No configuration required - works automatically.

Server Compatibility

Works with any MCP-compatible server:

FastMCP Example

# Start server
python examples/echo_server_streamable.py
# Connect and use
client = MCPClient.connect('http://localhost:8931/mcp')
tools = client.list_tools
result = client.call_tool('echo', { message: 'Hello!' })

Requirements

  • Ruby >= 3.2.0
  • No runtime dependencies

License

Available as open source under the MIT License.

Contributing

Bug reports and pull requests welcome at https://github.com/simonx1/ruby-mcp-client.

Release History

VersionChangesUrgencyDate
1.0.1## 1.0.1 (2026-03-22) ### New Features #### OAuth 2.1 Enhancements - **Supported Scopes Discovery**: New `supported_scopes` method on `OAuthProvider` and `scope: :all` shorthand to request all server-advertised scopes (#109) - **Extra Client Metadata in DCR**: Dynamic client registration now supports optional OIDC metadata fields (`client_name`, `client_uri`, `logo_uri`, `tos_uri`, `policy_uri`, `contacts`) (#110) - **PKCE Serialization**: `PKCE#to_h` and `PKCE.from_h` methods for persiMedium3/22/2026
1.0.0## 1.0.0 (2026-02-15) ### MCP 2025-11-25 Protocol Support Full implementation of the **MCP 2025-11-25** specification, upgrading from 2025-06-18. #### New Protocol Features - **Audio Content**: Support for audio content type in tool results and messages (#82) - **Resource Annotations**: Added `lastModified` field to resource annotations (#83) - **Enhanced Tool Annotations**: Hint-style annotation API (`readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`) alongside legLow2/15/2026
0.9.1### New Features #### Simplified API - `MCPClient.connect(url)` - **New single entry point** that auto-detects transport based on URL patterns (#62) - `MCPClient.connect('http://localhost:8000/sse')` → SSE transport - `MCPClient.connect('http://localhost:8931/mcp')` → Streamable HTTP transport - `MCPClient.connect('npx -y @modelcontextprotocol/server-filesystem /home')` → stdio transport - Supports options: `headers`, `read_timeout`, `sampling_handler`, etc. - Multiple serversLow12/10/2025
0.9.0## 0.9.0 (2025-11-05) ### MCP Protocol Update - **Updated to MCP 2025-06-18**: Latest protocol specification - Protocol version constant updated from `2025-03-26` to `2025-06-18` - All documentation and code comments updated to reference 2025-06-18 - Maintains full backward compatibility with previous versions ### New Features #### Streamable HTTP Gzip Support - Added gzip compression support for streamable HTTP transport (by @purposemc) (#46) #### Browser-based OAuth flowLow11/5/2025
0.8.1## 0.8.1 (2025-09-17) ### Breaking Changes - **Resources API**: Updated resources implementation to fully comply with MCP specification - `list_resources` now returns `{ 'resources' => [...], 'nextCursor' => ... }` hash format on both client and server levels - `read_resource` now returns array of `ResourceContent` objects instead of hash with 'contents' key ### New Features - **Full MCP Resources Specification Compliance**: - Added `ResourceContent` class for structured contentLow9/17/2025
0.8.0## 0.8.0 (2025-09-16) ### New Features - **MCP Prompts and Resources Support**: Added full support for MCP prompts and resources (#31) - Implemented `list_prompts` and `get_prompt` methods for prompt management - Implemented `list_resources` and `read_resource` methods for resource access - Added support for both text and blob resource types ### Bug Fixes - **Tool Caching**: Fixed issue with caching tools that have the same name from different servers (#342ff55) - Tools are nLow9/16/2025
0.7.3## 0.7.3 (2025-09-01) ### Bug Fixes - **Streaming JSON Parsing**: Fixed streaming JSON parsing improvements for better handling of partial data chunks - **SSE Connection**: Enhanced server-sent events connection reliability for real-time notifications (ty @dsablic ) ### Dependencies - Updated faraday from 2.13.1 to 2.13.4 - Updated ruby-openai from 8.1.0 to 8.3.0 (dev dependency) - Updated openai gem to latest version (dev dependency) - Updated rdoc from 6.14.1 to 6.14.2 (dev dependeLow9/1/2025
0.7.2### Bug Fixes - **JSON-RPC Parameter Handling**: Fixed SSE transport compatibility with Playwright MCP servers by reverting JSON-RPC parameter handling to not send `null` for empty parameters - **Logger Formatter Preservation**: Fixed issue where custom logger formatters were being overridden in server implementations ### Transport Improvements - **HTTP Redirect Support**: Added automatic redirect following (up to 3 hops) for both SSE and HTTP transports via faraday-follow_redirects gem Low7/14/2025
0.7.1## 0.7.1 (2025-06-20) ### OAuth 2.1 Authentication Framework - Added comprehensive OAuth 2.1 support with PKCE for secure authentication - Implemented automatic authorization server discovery via `.well-known` endpoints - Added dynamic client registration when supported by servers - Implemented token refresh and automatic token management - Added pluggable storage backends for tokens and client credentials - Created `MCPClient::OAuthClient` utility class for easy OAuth-enabled server crLow6/20/2025
0.7.0## 0.7.0 (2025-05-20) ### What's New - **StreamableHTTP transport type handling** - Enhanced HTTP transport layer with improved streaming capabilities - **Connection reliability improvements** - Fixed reconnection attempt resets on successful connections - **Test coverage enhancements** - Added verification for nested array removal operations - **Integration testing updates** - Improved integration test specifications ### Bug Fixes - Fixed reset reconnect attempts on success to enLow6/18/2025
0.6.2## 0.6.2 (2025-05-20) - Fixed reconnect attempts not being reset after successful ping - Added test verification for nested array $schema removal - Improved integration tests with Ruby-based test server instead of Node.js dependencies Low5/20/2025
0.6.1## 0.6.1 (2025-05-18) - Improved connection handling with automatic reconnection before RPC calls - Extracted common JSON-RPC functionality - Enhanced and unified error handling in SSE and stdio transports - Improved stdio command handlingLow5/18/2025
0.6.0## 0.6.0 (2025-05-16) - Added `find_server` method to retrieve servers by name - Added server association in each tool for better traceability - Added tool call disambiguation by specifying server name - Improved logger propagation from Client to all Server instances - Fixed ping errors in SSE connection by adding proper connection state validation - Improved connection state handling to prevent ping attempts on closed connections - Enhanced thread safety with more consistent connectionLow5/16/2025
0.5.3## 0.5.3 (2025-05-13) - Added `to_google_tools` method for Google Vertex AI API integration (by @IMhide) - Added Google Vertex Gemini example with full integration demonstration - Enhanced SSE connection management with automatic ping and inactivity tracking - Improved connection reliability with automatic reconnection on idle connections - Expanded README.md with updated documentation for SSE features Low5/13/2025
0.5.2## 0.5.2 (2025-05-09) - Improved authentication error handling in SSE connections - Better error messages for authentication failures - Code refactoring to improve maintainability and reduce complexityLow5/9/2025
0.5.1## 0.5.1 (2025-04-26) - Support for server definition files in JSON formatLow4/26/2025
0.5.0## 0.5.0 (2025-04-25) - Enhanced SSE implementation and added Faraday HTTP support - Updates for the HTTP client and endpoints - Updates session handling - Remove parameters from ping - Code improvementsLow4/25/2025
0.4.1## 0.4.1 (2025-04-24) - Server ping functionality - Fix SSE connection handling and add graceful fallbacksLow4/24/2025
0.4.0## 0.4.0 (2025-04-23) - Added full "initialize" hand-shake support to the SSE transport - Added an @initialized flag and ensure_initialized helper - Hooked into list_tools and call_tool for JSON-RPC "initialize" to be sent once - Implemented perform_initialize to send the RPC, capture server info and capabilities - Exposed server_info and capabilities readers on ServerSSE - Added JSON-RPC notifications dispatcher - ServerBase#on_notification to register blocks for incoming JLow4/24/2025
0.3.0## 0.3.0 (2025-04-23) - Removed HTTP server implementation - Code cleanupLow4/23/2025
0.2.0## 0.2.0 (2025-04-23) - Client schema validation - Client streaming API fallback/delegation - ServerHTTP initialization - Added list_tools, call_tool with streaming fallback - HTTP error handling - Support for calling multiple functions in batch - Implement find_tool - Tool cache control - Added ability to filter tools by name in to_openai_tools and to_anthropic_toolsLow4/23/2025
0.1.0**Full Changelog**: https://github.com/simonx1/ruby-mcp-client/commits/0.1.0Low4/23/2025

Dependencies & License Audit

Loading dependencies...

Similar Packages

action_mcpRails Engine with MCP compliant Spec.action_mcp/v0.110.2
rails-ai-contextAuto-introspect your Rails app and expose it to AI assistants. 38 tools, zero config, works with Claude, Cursor, Copilot, and any MCP client.v5.11.1
aiA productive AI coworker that learns, self-improves, and ships work.main@2026-06-06
claude-plugins-officialOfficial, Anthropic-managed directory of high quality Claude Code Plugins.main@2026-06-06
justoneapi-mcpProduction-ready MCP server exposing JustOneAPI endpoints to AI agents with raw JSON responses.main@2026-06-06

More in MCP Servers

AstrBotAgentic IM Chatbot infrastructure that integrates lots of IM platforms, LLMs, plugins and AI feature, and can be your openclaw alternative. ✨
agentscopeBuild and run agents you can see, understand and trust.
claude-plugins-officialOfficial, Anthropic-managed directory of high quality Claude Code Plugins.
langchain4jLangChain4j is an open-source Java library that simplifies the integration of LLMs into Java applications through a unified API, providing access to popular LLMs and vector databases. It makes impleme