MCP Server¶
Creating and using Model Context Protocol servers.
Overview¶
This example demonstrates how to create MCP servers to expose tools and how to connect robots to external MCP servers.
Creating an MCP Server¶
#!/usr/bin/env ruby
# examples/mcp_server.rb
require "bundler/setup"
require "robot_lab"
require "json"
# Create an MCP server with database tools
server = RobotLab::MCP::Server.new(
name: "database_tools",
version: "1.0.0"
)
# Mock database
USERS = {
"1" => { id: "1", name: "Alice", email: "alice@example.com", plan: "pro" },
"2" => { id: "2", name: "Bob", email: "bob@example.com", plan: "free" }
}
ORDERS = {
"ORD001" => { id: "ORD001", user_id: "1", total: 99.99, status: "shipped" },
"ORD002" => { id: "ORD002", user_id: "1", total: 49.99, status: "pending" },
"ORD003" => { id: "ORD003", user_id: "2", total: 29.99, status: "delivered" }
}
# Add tools to the server
server.add_tool(
name: "get_user",
description: "Get user by ID",
parameters: {
user_id: { type: "string", required: true, description: "User ID" }
},
handler: ->(user_id:) {
user = USERS[user_id]
user || { error: "User not found" }
}
)
server.add_tool(
name: "list_users",
description: "List all users",
parameters: {
plan: { type: "string", enum: ["free", "pro"], description: "Filter by plan" }
},
handler: ->(plan: nil) {
users = USERS.values
users = users.select { |u| u[:plan] == plan } if plan
users
}
)
server.add_tool(
name: "get_orders",
description: "Get orders for a user",
parameters: {
user_id: { type: "string", required: true },
status: { type: "string", enum: ["pending", "shipped", "delivered"] }
},
handler: ->(user_id:, status: nil) {
orders = ORDERS.values.select { |o| o[:user_id] == user_id }
orders = orders.select { |o| o[:status] == status } if status
orders
}
)
server.add_tool(
name: "update_order_status",
description: "Update an order's status",
parameters: {
order_id: { type: "string", required: true },
status: { type: "string", required: true, enum: ["pending", "shipped", "delivered"] }
},
handler: ->(order_id:, status:) {
order = ORDERS[order_id]
return { error: "Order not found" } unless order
order[:status] = status
{ success: true, order: order }
}
)
# Start the server (stdio for local use)
puts "Starting MCP server..."
server.start(transport: :stdio)
Using MCP Server in Robot¶
#!/usr/bin/env ruby
# examples/mcp_client.rb
require "bundler/setup"
require "robot_lab"
RobotLab.configure do |config|
config.default_model = "claude-sonnet-4"
end
# Robot that uses the MCP server
admin_bot = RobotLab.build do
name "admin_assistant"
description "Helps with administrative tasks"
template <<~PROMPT
You are an administrative assistant with access to user and order data.
Help users look up information and manage orders.
PROMPT
mcp [
{
name: "database",
transport: {
type: "stdio",
command: "ruby",
args: ["examples/mcp_server.rb"]
}
}
]
end
# Interactive session
puts "Admin Assistant (uses MCP server)"
puts "-" * 50
state = RobotLab.create_state(message: "List all pro users and their orders")
admin_bot.run(state: state) do |event|
case event.type
when :text_delta
print event.text
when :tool_call
puts "\n[MCP: #{event.name}]"
end
end
puts
admin_bot.disconnect
Network with MCP¶
# examples/network_with_mcp.rb
network = RobotLab.create_network do
name "support_with_mcp"
# MCP servers available to all robots
mcp [
{
name: "database",
transport: { type: "stdio", command: "ruby examples/mcp_server.rb" }
},
{
name: "filesystem",
transport: {
type: "stdio",
command: "npx",
args: ["@modelcontextprotocol/server-filesystem", "/data"]
}
}
]
add_robot RobotLab.build {
name "data_analyst"
template "You analyze user data."
mcp :inherit # Uses network's MCP servers
}
add_robot RobotLab.build {
name "file_manager"
template "You manage files."
mcp :inherit
tools %w[read_file list_directory] # Only these MCP tools
}
end
HTTP MCP Server¶
#!/usr/bin/env ruby
# examples/http_mcp_server.rb
require "robot_lab"
require "sinatra"
server = RobotLab::MCP::Server.new(name: "api_tools")
server.add_tool(
name: "get_stats",
description: "Get system statistics",
parameters: {},
handler: -> {
{
uptime: `uptime`.strip,
memory: `free -m 2>/dev/null || vm_stat`.strip,
time: Time.now.iso8601
}
}
)
# Sinatra endpoint for MCP
post "/mcp" do
content_type :json
request_body = JSON.parse(request.body.read)
response = server.handle_request(request_body)
response.to_json
end
# Run: ruby examples/http_mcp_server.rb
# Connect with HTTP transport
Connecting to HTTP Server¶
robot = RobotLab.build do
name "remote_assistant"
template "You have access to remote tools."
mcp [
{
name: "remote",
transport: {
type: "http",
url: "https://mcp.example.com/mcp",
headers: { "Authorization" => "Bearer #{ENV['MCP_TOKEN']}" }
}
}
]
end
WebSocket Server¶
#!/usr/bin/env ruby
# examples/websocket_mcp_server.rb
require "robot_lab"
server = RobotLab::MCP::Server.new(name: "realtime_tools")
server.add_tool(
name: "subscribe_events",
description: "Subscribe to real-time events",
parameters: { channel: { type: "string", required: true } },
handler: ->(channel:) { { subscribed: channel } }
)
# Start WebSocket server
server.start(transport: :websocket, port: 8765)
Running¶
# Start MCP server in one terminal
ruby examples/mcp_server.rb
# Run client in another terminal
export ANTHROPIC_API_KEY="your-key"
ruby examples/mcp_client.rb
Key Concepts¶
- Server Creation: Use
RobotLab::MCP::Server.new - Tool Registration: Add tools with
server.add_tool - Transport: Choose stdio, http, websocket, or sse
- Client Connection: Configure in robot's
mcpblock - Tool Filtering: Use
toolswhitelist for security