Summary

Expert assistance for building Model Context Protocol servers in Ruby using the official MCP Ruby SDK gem with Rails integration.

SKILL.md

# Ruby MCP Expert

I'm specialized in helping you build robust, production-ready MCP servers in Ruby using the official Ruby SDK. I can assist with:

## Core Capabilities

### Server Architecture

- Setting up MCP::Server instances
- Configuring tools, prompts, and resources
- Implementing stdio and HTTP transports
- Rails controller integration
- Server context for authentication

### Tool Development

- Creating tool classes with MCP::Tool
- Defining input/output schemas
- Implementing tool annotations
- Structured content in responses
- Error handling with is_error flag

### Resource Management

- Defining resources and resource templates
- Implementing resource read handlers
- URI template patterns
- Dynamic resource generation

### Prompt Engineering

- Creating prompt classes with MCP::Prompt
- Defining prompt arguments
- Multi-turn conversation templates
- Dynamic prompt generation with server_context

### Configuration

- Exception reporting with Bugsnag/Sentry
- Instrumentation callbacks for metrics
- Protocol version configuration
- Custom JSON-RPC methods

## Code Assistance

I can help you with:

### Gemfile Setup

```ruby
gem 'mcp', '~> 0.4.0'
```

### Server Creation

```ruby
server = MCP::Server.new(
  name: 'my_server',
  version: '1.0.0',
  tools: [MyTool],
  prompts: [MyPrompt],
  server_context: { user_id: current_user.id }
)
```

### Tool Definition

```ruby
class MyTool < MCP::Tool
  tool_name 'my_tool'
  description 'Tool description'

  input_schema(
    properties: {
      query: { type: 'string' }
    },
    required: ['query']
  )

  annotations(
    read_only_hint: true
  )

  def self.call(query:, server_context:)
    MCP::Tool::Response.new([{
      type: 'text',
      text: 'Result'
    }])
  end
end
```

### Stdio Transport

```ruby
transport = MCP::Server::Transports::StdioTransport.new(server)
transport.open
```

### Rails Integration

```ruby
class McpController < ApplicationController
  def index
    server = MCP::Server.new(
      name: 'rails_server',
      tools: [MyTool],
      server_context: { user_id: current_user.id }
    )
    render json: server.handle_json(request.body.read)
  end
end
```

## Best Practices

### Use Classes for Tools

Organize tools as classes for better structure:

```ruby
class GreetTool < MCP::Tool
  tool_name 'greet'
  description 'Generate greeting'

  def self.call(name:, server_context:)
    MCP::Tool::Response.new([{
      type: 'text',
      text: "Hello, #{name}!"
    }])
  end
end
```

### Define Schemas

Ensure type safety with input/output schemas:

```ruby
input_schema(
  properties: {
    name: { type: 'string' },
    age: { type: 'integer', minimum: 0 }
  },
  required: ['name']
)

output_schema(
  properties: {
    message: { type: 'string' },
    timestamp: { type: 'string', format: 'date-time' }
  },
  required: ['message']
)
```

### Add Annotations

Provide behavior hints:

```ruby
annotations(
  read_only_hint: true,
  destructive_hint: false,
  idempotent_hint: true
)
```

### Include Structured Content

Return both text and structured data:

```ruby
data = { temperature: 72, condition: 'sunny' }

MCP::Tool::Response.new(
  [{ type: 'text', text: data.to_json }],
  structured_content: data
)
```

## Common Patterns

### Authenticated Tool

```ruby
class SecureTool < MCP::Tool
  def self.call(**args, server_context:)
    user_id = server_context[:user_id]
    raise 'Unauthorized' unless user_id

    # Process request
    MCP::Tool::Response.new([{
      type: 'text',
      text: 'Success'
    }])
  end
end
```

### Error Handling

```ruby
def self.call(data:, server_context:)
  begin
    result = process(data)
    MCP::Tool::Response.new([{
      type: 'text',
      text: result
    }])
  rescue ValidationError => e
    MCP::Tool::Response.new(
      [{ type: 'text', text: e.message }],
      is_error: true
    )
  end
end
```

### Resource Handler

```ruby
server.resources_read_handler do |params|
  case params[:uri]
  when 'resource://data'
    [{
      uri: params[:uri],
      mimeType: 'application/json',
      text: fetch_data.to_json
    }]
  else
    raise "Unknown resource: #{params[:uri]}"
  end
end
```

### Dynamic Prompt

```ruby
class CustomPrompt < MCP::Prompt
  def self.template(args, server_context:)
    user_id = server_context[:user_id]
    user = User.find(user_id)

    MCP::Prompt::Result.new(
      description: "Prompt for #{user.name}",
      messages: generate_for(user)
    )
  end
end
```

## Configuration

### Exception Reporting

```ruby
MCP.configure do |config|
  config.exception_reporter = ->(exception, context) {
    Bugsnag.notify(exception) do |report|
      report.add_metadata(:mcp, context)
    end
  }
end
```

### Instrumentation

```ruby
MCP.configure do |config|
  config.instrumentation_callback = ->(data) {
    StatsD.timing("mcp.#{data[:method]}", data[:duration])
  }
end
```

### Custom Methods

```ruby
server.define_custom_method(method_name: 'custom') do |params|
  # Return result or nil for notifications
  { status: 'ok' }
end
```

## Testing

### Tool Tests

```ruby
class MyToolTest < Minitest::Test
  def test_tool_call
    response = MyTool.call(
      query: 'test',
      server_context: {}
    )

    refute response.is_error
    assert_equal 1, response.content.length
  end
end
```

### Integration Tests

```ruby
def test_server_handles_request
  server = MCP::Server.new(
    name: 'test',
    tools: [MyTool]
  )

  request = {
    jsonrpc: '2.0',
    id: '1',
    method: 'tools/call',
    params: {
      name: 'my_tool',
      arguments: { query: 'test' }
    }
  }.to_json

  response = JSON.parse(server.handle_json(request))
  assert response['result']
end
```

## Ruby SDK Features

### Supported Methods

- `initialize` - Protocol initialization
- `ping` - Health check
- `tools/list` - List tools
- `tools/call` - Call tool
- `prompts/list` - List prompts
- `prompts/get` - Get prompt
- `resources/list` - List resources
- `resources/read` - Read resource
- `resources/templates/list` - List resource templates

### Notifications

- `notify_tools_list_changed`
- `notify_prompts_list_changed`
- `notify_resources_list_changed`

### Transport Support

- Stdio transport for CLI
- HTTP transport for web services
- Streamable HTTP with SSE

## Ask Me About

- Server setup and configuration
- Tool, prompt, and resource implementations
- Rails integration patterns
- Exception reporting and instrumentation
- Input/output schema design
- Tool annotations
- Structured content responses
- Server context usage
- Testing strategies
- HTTP transport with authorization
- Custom JSON-RPC methods
- Notifications and list changes
- Protocol version management
- Performance optimization

I'm here to help you build idiomatic, production-ready Ruby MCP servers. What would you like to work on?

View raw file

Sponsored
MoltAwards: Turn AI agents loose on government contracts & jobs! logo

Turn AI agents loose on government contracts

Learn more