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 888 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, SEP-2575): returns the modern supportedVersions,
capabilities, instructions, the required ttlMs/cacheScope cache hints, and the server identity as the optional
io.modelcontextprotocol/serverInfo stamp in the result _meta, and responds before initialize
and without an Mcp-Session-Id. The server also serves the full stateless modern lifecycle: requests carrying the SEP-2575 _meta envelope
(io.modelcontextprotocol/protocolVersion, clientInfo, and clientCapabilities) are validated per request,
and the Streamable HTTP transport serves them on a sessionless single-exchange path. On the client, MCP::Client#connect negotiates
the lifecycle automatically by default (probe server/discover, fall back to the initialize handshake), connect(mode: :modern) skips
the handshake entirely, connect(mode: :legacy) forces the classic handshake, and MCP::Client#discover exposes the raw discovery resultsubscriptions/listen - Long-lived notification subscription stream (MCP 2026-07-28, SEP-2575), replacing the legacy HTTP GET listening stream:
the client opts in via the notifications filter (toolsListChanged / promptsListChanged / resourcesListChanged / resourceSubscriptions),
the server acknowledges the honored subset with notifications/subscriptions/acknowledged as the first stream message,
and every delivered notification carries the correlating io.modelcontextprotocol/subscriptionId in _meta. Served on the Streamable HTTP modern path;
stdio answers -32601. Concurrent streams are capped by max_listen_subscriptions: (default 1000), and each stream receives an SSE keepalive
comment frame every listen_keepalive_interval: seconds (default 15) so a dropped connection frees its slot; pass listen_keepalive_interval: nil
when an upstream proxy already keeps the stream aliveinput_required results (MCP 2026-07-28, SEP-2322): a tools/call, prompts/get, or resources/read handler that
opts in to server_context: may return MCP::Server::InputRequiredResult.new(input_requests:, request_state:) to ask the client for
additional input (elicitation/create, sampling/createMessage, or roots/list shapes) instead of performing a server-initiated request,
which the modern lifecycle forbids. On the retried request the handler re-runs from the start and reads the answers via
server_context.input_responses / server_context.input_response(key) and the echoed opaque server_context.request_state
(deterministic replay; the server holds no memory between rounds). The SDK rejects issuance on legacy requests and returns -32021
when an embedded request needs a client capability the request did not declare. The echoed requestState arrives as
client-controlled input: pass MCP::Server::RequestStateSecurity.new(key:) (a 32-byte key) via Server.new(request_state_security:) to
have it sealed with AES-256-GCM and bound to a TTL plus the originating method, target, and arguments, all transparently to handlers.
Multi-process deployments must share the key across workers; without request_state_security: the state crosses the wire exactly as
the handler wrote it and protecting it is the handler author's responsibility. On the client, register handlers with
on_elicitation / on_sampling / on_roots - the same registrations that answer a real server-to-client request - and
declare the matching capabilities on connect (a server embeds only the request kinds the client declared);
call_tool / get_prompt / read_resource then resume input_required results automatically: each embedded request is fulfilled by
the matching handler and the original request is re-issued with inputResponses plus the echoed requestState
(with exponential backoff for requestState-only load-shedding legs). Without a matching handler they raise MCP::Client::InputRequiredError,
and the input_responses: / request_state: keyword arguments support manual drivingping - 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::Stream