The official Ruby SDK for the Model Context Protocol.
# Add to your Claude Code skills
git clone https://github.com/modelcontextprotocol/ruby-sdkGuides for using mcp servers skills like ruby-sdk.
Last scanned: 8/4/2026
{
"issues": [],
"status": "PASSED",
"scannedAt": "2026-08-04T06:27:22.669Z",
"npmAuditRan": true,
"pipAuditRan": true,
"promptInjectionRan": true
}ruby-sdk is an open-source mcp servers skill for AI coding assistants such as Claude Code, Codex CLI, and ChatGPT, built by modelcontextprotocol. The official Ruby SDK for the Model Context Protocol. It has 876 GitHub stars.
Yes. ruby-sdk passed SkillsLLM's automated security scan — a dependency vulnerability audit plus prompt-injection heuristics — with no high-severity issues. You can read the full report in the Security Report section on this page.
Clone the repository with "git clone https://github.com/modelcontextprotocol/ruby-sdk" and add it to your Claude Code skills directory (see the Installation section above).
ruby-sdk is primarily written in Ruby. It is open-source under modelcontextprotocol on GitHub, so you can review or fork the full source.
Yes. SkillsLLM lists many other MCP Servers skills you can browse and compare side by side. Open the MCP Servers category from the badge at the top of this page, or use the Related Skills and comparison links further down to weigh ruby-sdk against similar tools.
No comments yet. Be the first to share your thoughts!
Top skills in this category by stars
The official Ruby SDK for Model Context Protocol servers and clients.
Add this line to your application's Gemfile:
gem 'mcp'
And then execute:
$ bundle install
Or install it yourself as:
$ gem install mcp
You may need to add additional dependencies depending on which features you wish to access.
The MCP::Server class is the core component that handles JSON-RPC requests and responses.
It implements the Model Context Protocol specification, handling model context requests and responses.
initialize - Initializes the protocol and returns server capabilitiesserver/discover - Sessionless capability discovery (MCP 2026-07-28 draft, SEP-2575): returns supportedVersions, capabilities, serverInfo,
and instructions, and responds before initialize and without an Mcp-Session-Idping - Simple health checklogging/setLevel - Configures the minimum log level for the servertools/list - Lists all registered tools and their schemastools/call - Invokes a specific tool with provided argumentsprompts/list - Lists all registered prompts and their schemasprompts/get - Retrieves a specific prompt by nameresources/list - Lists all registered resources and their schemasresources/read - Retrieves a specific resource by nameresources/templates/list - Lists all registered resource templates and their schemasresources/subscribe - Subscribes to updates for a specific resourceresources/unsubscribe - Unsubscribes from updates for a specific resourcecompletion/complete - Returns autocompletion suggestions for prompt arguments and resource URIsroots/list - Requests filesystem roots from the client (server-to-client)sampling/createMessage - Requests LLM completion from the client (server-to-client)elicitation/create - Requests user input from the client (server-to-client)If you want to build a local command-line application, you can use the stdio transport:
require "mcp"
# Create a simple tool
class ExampleTool < MCP::Tool
description "A simple example tool that echoes back its arguments"
input_schema(
properties: {
message: { type: "string" },
},
required: ["message"]
)
class << self
def call(message:, server_context:)
MCP::Tool::Response.new([{
type: "text",
text: "Hello from example tool! Message: #{message}",
}])
end
end
end
# Set up the server
server = MCP::Server.new(
name: "example_server",
tools: [ExampleTool],
)
# Create and start the transport
transport = MCP::Server::Transports::StdioTransport.new(server)
transport.open
StdioTransport.new accepts an optional max_line_bytes: keyword that caps the byte length of a single newline-delimited request frame. A frame that reaches this limit without a newline is rejected and the connection is closed, preventing unbounded memory growth from a peer that never emits a newline. It defaults to 4 * 1024 * 1024 (4 MiB).
You can run this script and then type in requests to the server at the command line.
$ ruby examples/stdio_server.rb
{"jsonrpc":"2.0","id":"1","method":"ping"}
{"jsonrpc":"2.0","id":"2","method":"tools/list"}
{"jsonrpc":"2.0","id":"3","method":"tools/call","params":{"name":"example_tool","arguments":{"message":"Hello"}}}
MCP::Server::Transports::StreamableHTTPTransport is a standard Rack app, so it can be mounted in any Rack-compatible framework.
The following examples show two common integration styles in Rails.
[!IMPORTANT]
MCP::Server::Transports::StreamableHTTPTransportstores session and SSE stream state in memory, so it must run in a single process. Use a single-process server (e.g., Puma withworkers 0). Multi-process configurations (Unicorn, or Puma withworkers > 0) fork separate processes that do not share memory, which breaks session management and SSE connections.When running multiple server instances behind a load balancer, configure your load balancer to use sticky sessions (session affinity) so that requests with the same
Mcp-Session-Idheader are always routed to the same instance.Stateless mode (
stateless: true) does not use sessions and works with any server configuration.
[!IMPORTANT] Per MCP 2025-11-25,
StreamableHTTPTransportvalidates theHostandOriginheaders by default to prevent DNS rebinding attacks against locally bound servers, rejecting unauthorized values with HTTP 403.Hostis allowed for the loopback defaults (127.0.0.1,::1,localhost), and anOriginheader, when present, must be same-origin or explicitly allow-listed. Non-browser clients that send noOriginheader are unaffected.Deployments behind a reverse proxy or bound to a non-loopback interface must widen the allow lists:
transport = MCP::Server::Transports::StreamableHTTPTransport.new( server, allowed_hosts: ["mcp.example.com"], allowed_origins: ["https://app.example.com"], )An
allowed_hosts:entry matches either the bare host name (any port) or the fullhost:portvalue, so both"mcp.example.com"and"mcp.example.com:8443"work. Passdns_rebinding_protection: falseto disable the check entirely (e.g., when an upstream proxy or middleware already validatesHost/Origin).
StreamableHTTPTransport is a Rack app that can be mounted directly in Rails routes:
# config/routes.rb
server = MCP::Server.new(
name: "my_server",
title: "Example Server Display Name",
version: "1.0.0",
instructions: "Use the tools of this server as a last resort",
tools: [SomeTool, AnotherTool],
prompts: [MyPrompt],
)
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server)
Rails.application.routes.draw do
mount transport => "/mcp"
end
mount directs all HTTP methods on /mcp to the transport. StreamableHTTPTransport internally dispatches
POST (client-to-server JSON-RPC messages, with responses optionally streamed via SSE),
GET (optional standalone SSE stream for server-to-client messages), and DELETE (session termination) per
the MCP Streamable HTTP transport spec,
so no additional route configuration is needed.
A complete runnable application using this approach is available in examples/rails.
While the mount approach creates a single server at boot time, the controller approach creates a new server per request. This allows you to customize tools, prompts, or configuration based on the request (e.g., different tools per route).
StreamableHTTPTransport#handle_request returns proper HTTP status codes (e.g., 202 Accepted for notifications):
class McpController < ActionController::API
def create
server = MCP::Server.new(
name: "my_server",
title: "Example Server Display Name",
version: "1.0.0",
instructions: "Use the tools of this server as a last resort",
tools: [SomeTool, AnotherTool],
prompts: [MyPrompt],
server_context: { user_id: current_user.id },
)
# Since the `MCP-Session-Id` is not shared across requests, `stateless: true` is set.
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server, stateless: true)
status, headers, body = transport.handle_request(request)
render(json: body.first, status: status, headers: headers)
end
end
The gem can be configured using the MCP.configure block:
MCP.configure do |config|
config.exception_reporter = ->(exception, server_context) {
# Your exception reporting logic here
# For example with Bugsnag:
Bugsnag.notify(exception) do |report|
report.add_metadata(:model_context_protocol, server_context)
end
}
config.around_request = ->(data, &request_handler) {
logger.info("Start: #{data[:method]}")
request_handler.call
logger.info("Done: #{data[:method]}, tool: #{data[:tool_name]}")
}
end
or by creating an explicit configuration and passing it into the server. This is useful for systems where an application hosts more than one MCP server but they might require different configurations.
configuration = MCP::Configuration.new
configuration.exception_reporter = ->(exception, server_context) {
# Your exception reporting logic here
# For example with Bugsnag:
Bugsnag.notify(exception) do |report|
report.add_metadata(:model_context_protocol, server_context)
end
}
configuration.around_request = ->(data, &request_handler) {
logger.info("Start: #{data[:method]}")
request_handler.call
logger.info("Done: #{dat