MCP is a protocol for building AI agents.
https://modelcontextprotocol.io/introduction
During the LLM boom that started with ChatGPT, LLMs were integrated as features in tools like GitHub Copilot. In the recent AI Agent trend, LLMs are expected and implemented to operate external resources and tools. However, unfortunately, the methods varied depending on the LLM. MCP aims to abstract these differences and enable similar operations across multiple LLMs.
Reference implementations were published in TypeScript and Python:
https://github.com/modelcontextprotocol/typescript-sdk
https://github.com/modelcontextprotocol/python-sdk
As a Ruby enthusiast, I created an SDK for Rubyists to use.
https://github.com/funwarioisii/mcp-rb
This article introduces mcp-rb.
Introduction to MCP Concepts
The expectation for AI Agents is to read external information and use it to manipulate the external environment. To achieve this, MCP defines two concepts: Tool and Resource. For web service developers, it might be easier to think of these as GET and POST.
mcp-rb provides a DSL to make implementing these concepts easier.
How to Write
I adopted a DSL influenced by Sinatra and graphql-ruby.
Let's review a bit.
In Sinatra, writing the following code returns the string 'Put this in your pipe & smoke it!' when accessing /frank-says
. This not only defines the get
method but also starts a web server at runtime.
require 'sinatra'
get '/frank-says' do
'Put this in your pipe & smoke it!'
end
Also, in graphql-ruby
, mutations arguments were defined like this. The following code is partially modified from https://graphql-ruby.org/mutations/mutation_classes:
class Mutations::CreateComment < Mutations::BaseMutation
argument :body, String, required: true
argument :post_id, ID, required: true
def resolve(body:, post_id:)
...
end
end
Both are very Ruby-like, simple, and easy to understand. I deeply respect these ideas. In mcp-rb
, we provide a DSL inspired by these two to define MCP's Tools and Resources.
require "mcp"
name "demo"
tool "greet" do
description "Greet someone by name"
argument :name, String, required: true, description: "Name to greet"
call { |args| "Hello, #{args[:name]}!" }
end
resource "hello://world" do
name "Hello World"
description "A simple hello world message"
mime_type "text/plain"
call { "Hello, World!" }
end
What do you think?
You can start using it immediately with:
bundle add mcp-rb
The implementation is publicly available at:
https://github.com/funwarioisii/mcp-rb
Which do you like?
Let's compare it with the provided TypeScript implementation.
You can see that the Ruby DSL allows for more concise writing.
TypeScript
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
// Create an MCP server
const server = new McpServer({
name: "Demo",
});
// Add an addition tool
server.tool("add",
{ a: z.number(), b: z.number() },
async ({ a, b }) => ({
content: [{ type: "text", text: String(a + b) }]
})
);
// Add a dynamic greeting resource
server.resource(
"greeting",
new ResourceTemplate("greeting://{name}", { list: undefined }),
async (uri, { name }) => ({
contents: [{
uri: uri.href,
text: `Hello, ${name}!`
}]
})
);
// Start receiving messages on stdin and sending messages on stdout
const transport = new StdioServerTransport();
await server.connect(transport);
Ruby (I propose this)
require "mcp"
name "demo"
tool "add" do
description "Add two numbers"
argument :a, Integer, required: true
argument :b, Integer, required: true
call { |args| args[:a] + args[:b] }
end
# Dynamic resource definition is not yet implemented
resource "greeting://hello" do
description "A greeting resource"
call { |args| "Hello, #{args[:name]}!" }
end
What's Missing
Of course, we haven't achieved a type system as powerful as TypeScript's. Also, several features provided in the official SDK are not yet implemented.
However, the sample code targeting Cosense, a Wiki service made in Japan, is already working with Claude. I'm already using it at work and finding it very comfortable.
https://github.com/funwarioisii/mcp-rb/blob/a5b84026bd7228d6b9f425b52ea0bc49781eff5f/examples/cosense_example.rb
It's published on GitHub under the MIT license. If you're interested in improving the user experience, please send a Pull Request.
Summary
mcp-rb
provides a DSL for defining MCP Server Tools and Resources in Ruby. Ruby has various technical assets. Even in new fields like AI Agents, Ruby can leverage these technical assets. Please give it a try.