model-context-protocol-rb 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -2
- data/README.md +174 -978
- data/lib/model_context_protocol/rspec/helpers.rb +54 -0
- data/lib/model_context_protocol/rspec/matchers/be_mcp_error_response.rb +123 -0
- data/lib/model_context_protocol/rspec/matchers/be_valid_mcp_class.rb +103 -0
- data/lib/model_context_protocol/rspec/matchers/be_valid_mcp_prompt_response.rb +126 -0
- data/lib/model_context_protocol/rspec/matchers/be_valid_mcp_resource_response.rb +121 -0
- data/lib/model_context_protocol/rspec/matchers/be_valid_mcp_tool_response.rb +135 -0
- data/lib/model_context_protocol/rspec/matchers/have_audio_content.rb +109 -0
- data/lib/model_context_protocol/rspec/matchers/have_embedded_resource_content.rb +150 -0
- data/lib/model_context_protocol/rspec/matchers/have_image_content.rb +109 -0
- data/lib/model_context_protocol/rspec/matchers/have_message_count.rb +87 -0
- data/lib/model_context_protocol/rspec/matchers/have_message_with_role.rb +152 -0
- data/lib/model_context_protocol/rspec/matchers/have_resource_annotations.rb +135 -0
- data/lib/model_context_protocol/rspec/matchers/have_resource_blob.rb +108 -0
- data/lib/model_context_protocol/rspec/matchers/have_resource_link_content.rb +138 -0
- data/lib/model_context_protocol/rspec/matchers/have_resource_mime_type.rb +103 -0
- data/lib/model_context_protocol/rspec/matchers/have_resource_text.rb +112 -0
- data/lib/model_context_protocol/rspec/matchers/have_structured_content.rb +88 -0
- data/lib/model_context_protocol/rspec/matchers/have_text_content.rb +113 -0
- data/lib/model_context_protocol/rspec/matchers.rb +31 -0
- data/lib/model_context_protocol/rspec.rb +23 -0
- data/lib/model_context_protocol/server/client_logger.rb +1 -1
- data/lib/model_context_protocol/server/configuration.rb +195 -91
- data/lib/model_context_protocol/server/content_helpers.rb +1 -1
- data/lib/model_context_protocol/server/prompt.rb +0 -14
- data/lib/model_context_protocol/server/redis_client_proxy.rb +2 -14
- data/lib/model_context_protocol/server/redis_config.rb +5 -7
- data/lib/model_context_protocol/server/redis_pool_manager.rb +10 -13
- data/lib/model_context_protocol/server/registry.rb +8 -0
- data/lib/model_context_protocol/server/router.rb +279 -4
- data/lib/model_context_protocol/server/server_logger.rb +5 -2
- data/lib/model_context_protocol/server/stdio_configuration.rb +114 -0
- data/lib/model_context_protocol/server/stdio_transport/request_store.rb +0 -41
- data/lib/model_context_protocol/server/streamable_http_configuration.rb +218 -0
- data/lib/model_context_protocol/server/streamable_http_transport/event_counter.rb +0 -13
- data/lib/model_context_protocol/server/streamable_http_transport/notification_queue.rb +0 -41
- data/lib/model_context_protocol/server/streamable_http_transport/request_store.rb +0 -103
- data/lib/model_context_protocol/server/streamable_http_transport/server_request_store.rb +0 -64
- data/lib/model_context_protocol/server/streamable_http_transport/session_message_queue.rb +0 -58
- data/lib/model_context_protocol/server/streamable_http_transport/session_store.rb +17 -31
- data/lib/model_context_protocol/server/streamable_http_transport/stream_registry.rb +0 -34
- data/lib/model_context_protocol/server/streamable_http_transport.rb +192 -56
- data/lib/model_context_protocol/server/tool.rb +67 -1
- data/lib/model_context_protocol/server.rb +203 -262
- data/lib/model_context_protocol/version.rb +1 -1
- data/lib/model_context_protocol.rb +4 -1
- data/lib/puma/plugin/mcp.rb +39 -0
- data/tasks/mcp.rake +26 -0
- data/tasks/templates/dev-http-puma.erb +251 -0
- data/tasks/templates/dev-http.erb +166 -184
- data/tasks/templates/dev.erb +29 -7
- metadata +26 -2
data/README.md
CHANGED
|
@@ -4,27 +4,6 @@ An implementation of the [Model Context Protocol (MCP)](https://spec.modelcontex
|
|
|
4
4
|
|
|
5
5
|
Provides simple abstractions that allow you to serve prompts, resources, resource templates, and tools via MCP locally (stdio) or in production (streamable HTTP backed by Redis) with minimal effort.
|
|
6
6
|
|
|
7
|
-
## Table of Contents
|
|
8
|
-
|
|
9
|
-
- [Feature Support (Server)](#feature-support-server)
|
|
10
|
-
- [Quick Start with Rails](#quick-start-with-rails)
|
|
11
|
-
- [Installation](#installation)
|
|
12
|
-
- [Building an MCP Server](#building-an-mcp-server)
|
|
13
|
-
- [Server Configuration Options](#server-configuration-options)
|
|
14
|
-
- [Pagination Configuration Options](#pagination-configuration-options)
|
|
15
|
-
- [Transport Configuration Options](#transport-configuration-options)
|
|
16
|
-
- [Redis Configuration](#redis-configuration)
|
|
17
|
-
- [Server Logging Configuration](#server-logging-configuration)
|
|
18
|
-
- [Registry Configuration Options](#registry-configuration-options)
|
|
19
|
-
- [Prompts](#prompts)
|
|
20
|
-
- [Resources](#resources)
|
|
21
|
-
- [Resource Templates](#resource-templates)
|
|
22
|
-
- [Tools](#tools)
|
|
23
|
-
- [Completions](#completions)
|
|
24
|
-
- [Development](#development)
|
|
25
|
-
- [Contributing](#contributing)
|
|
26
|
-
- [License](#license)
|
|
27
|
-
|
|
28
7
|
## Feature Support (Server)
|
|
29
8
|
|
|
30
9
|
| Status | Feature |
|
|
@@ -39,130 +18,14 @@ Provides simple abstractions that allow you to serve prompts, resources, resourc
|
|
|
39
18
|
| ✅ | [Environment Variables](https://modelcontextprotocol.io/legacy/tools/debugging#environment-variables) |
|
|
40
19
|
| ✅ | [STDIO Transport](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#stdio) |
|
|
41
20
|
| ✅ | [Streamable HTTP Transport](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#streamable-http) |
|
|
42
|
-
|
|
|
43
|
-
|
|
|
21
|
+
| ✅ | [List Changed Notification (Prompts)](https://modelcontextprotocol.io/specification/2025-06-18/server/prompts#list-changed-notification) ¹ |
|
|
22
|
+
| ✅ | [List Changed Notification (Resources)](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#list-changed-notification) ¹ |
|
|
44
23
|
| ❌ | [Subscriptions (Resources)](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#subscriptions) |
|
|
45
|
-
|
|
|
24
|
+
| ✅ | [List Changed Notification (Tools)](https://modelcontextprotocol.io/specification/2025-06-18/server/tools#list-changed-notification) ¹ |
|
|
46
25
|
| ✅ | [Cancellation](https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/cancellation) |
|
|
47
26
|
| ✅ | [Ping](https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/ping) |
|
|
48
27
|
| ✅ | [Progress](https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/progress) |
|
|
49
28
|
|
|
50
|
-
## Quick Start with Rails
|
|
51
|
-
|
|
52
|
-
The `model-context-protocol-rb` works out of the box with any valid Rack request. Currently, this project has no plans for building a deeper Rails integration, but it is fairly simple to build it out yourself. To support modern application deployments across multiple servers, the streamable HTTP transport requires Redis as an external dependency.
|
|
53
|
-
|
|
54
|
-
Here's an example of how you can easily integrate with Rails.
|
|
55
|
-
|
|
56
|
-
First, configure Redis in an initializer:
|
|
57
|
-
|
|
58
|
-
```ruby
|
|
59
|
-
# config/initializers/model_context_protocol.rb
|
|
60
|
-
require "model_context_protocol"
|
|
61
|
-
|
|
62
|
-
ModelContextProtocol::Server.configure_redis do |config|
|
|
63
|
-
config.redis_url = ENV.fetch("REDIS_URL", "redis://localhost:6379/0")
|
|
64
|
-
config.pool_size = 20
|
|
65
|
-
config.pool_timeout = 5
|
|
66
|
-
config.enable_reaper = true
|
|
67
|
-
config.reaper_interval = 60
|
|
68
|
-
config.idle_timeout = 300
|
|
69
|
-
end
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
Then, set the routes:
|
|
73
|
-
|
|
74
|
-
```ruby
|
|
75
|
-
constraints format: :json do
|
|
76
|
-
get "/mcp", to: "model_context_protocol#handle", as: :mcp_get
|
|
77
|
-
post "/mcp", to: "model_context_protocol#handle", as: :mcp_post
|
|
78
|
-
delete "/mcp", to: "model_context_protocol#handle", as: :mcp_delete
|
|
79
|
-
end
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
Then, implement a controller endpoint to handle the requests.
|
|
83
|
-
|
|
84
|
-
```ruby
|
|
85
|
-
class ModelContextProtocolController < ActionController::API
|
|
86
|
-
include ActionController::Live
|
|
87
|
-
|
|
88
|
-
before_action :authenticate_user
|
|
89
|
-
|
|
90
|
-
def handle
|
|
91
|
-
server = ModelContextProtocol::Server.new do |config|
|
|
92
|
-
config.name = "MyMCPServer"
|
|
93
|
-
config.title = "My MCP Server"
|
|
94
|
-
config.version = "1.0.0"
|
|
95
|
-
config.registry = build_registry
|
|
96
|
-
config.context = {
|
|
97
|
-
user_id: current_user.id,
|
|
98
|
-
request_id: request.id
|
|
99
|
-
}
|
|
100
|
-
config.transport = {
|
|
101
|
-
type: :streamable_http,
|
|
102
|
-
env: request.env
|
|
103
|
-
}
|
|
104
|
-
config.instructions = <<~INSTRUCTIONS
|
|
105
|
-
This server provides prompts, tools, and resources for interacting with my app.
|
|
106
|
-
|
|
107
|
-
Key capabilities:
|
|
108
|
-
- Does this one thing
|
|
109
|
-
- Does this other thing
|
|
110
|
-
- Oh, yeah, and it does that one thing, too
|
|
111
|
-
|
|
112
|
-
Use this server when you need to do stuff.
|
|
113
|
-
INSTRUCTIONS
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
result = server.start
|
|
117
|
-
handle_mcp_response(result)
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
private
|
|
121
|
-
|
|
122
|
-
def build_registry
|
|
123
|
-
ModelContextProtocol::Server::Registry.new do
|
|
124
|
-
tools do
|
|
125
|
-
# Implement user authorization logic to dynamically build registry
|
|
126
|
-
register TestTool if current_user.authorized_for?(TestTool)
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
def handle_mcp_response(result)
|
|
132
|
-
if result[:headers]&.dig("Content-Type") == "text/event-stream"
|
|
133
|
-
setup_streaming_headers
|
|
134
|
-
stream_response(result[:stream_proc])
|
|
135
|
-
else
|
|
136
|
-
render_json_response(result)
|
|
137
|
-
end
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
def setup_streaming_headers
|
|
141
|
-
response.headers.merge!(
|
|
142
|
-
"Content-Type" => "text/event-stream",
|
|
143
|
-
"Cache-Control" => "no-cache",
|
|
144
|
-
"Connection" => "keep-alive"
|
|
145
|
-
)
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def stream_response(stream_proc)
|
|
149
|
-
stream_proc&.call(response.stream)
|
|
150
|
-
ensure
|
|
151
|
-
response.stream.close rescue nil
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
def render_json_response(result)
|
|
155
|
-
render json: result[:json],
|
|
156
|
-
status: result[:status] || 200,
|
|
157
|
-
headers: result[:headers] || {}
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
Read more about the [server configuration options](building-an-mcp-server) to better understand how you can customize your MCP server.
|
|
163
|
-
|
|
164
|
-
From here, you can get started building [prompts](#prompts), [resources](#resources), [resource templates](#resource-templates), and [tools](#tools).
|
|
165
|
-
|
|
166
29
|
## Installation
|
|
167
30
|
|
|
168
31
|
Add this line to your application's Gemfile:
|
|
@@ -183,644 +46,249 @@ Or install it yourself as:
|
|
|
183
46
|
gem install model-context-protocol-rb
|
|
184
47
|
```
|
|
185
48
|
|
|
186
|
-
|
|
49
|
+
For detailed installation instructions, see the [Installation wiki page](https://github.com/dickdavis/model-context-protocol-rb/wiki/Installation).
|
|
187
50
|
|
|
188
|
-
|
|
51
|
+
## Building an MCP Server
|
|
189
52
|
|
|
190
|
-
|
|
191
|
-
server = ModelContextProtocol::Server.new do |config|
|
|
192
|
-
# Name of the MCP server (intended for programmatic use)
|
|
193
|
-
config.name = "MCPDevelopmentServer"
|
|
53
|
+
Build a simple MCP server by registering your prompts, resources, resource templates, and tools. Messages from the MCP client will be routed to the appropriate custom handler.
|
|
194
54
|
|
|
195
|
-
|
|
196
|
-
config.version = "1.0.0"
|
|
55
|
+
### STDIO Transport (Default)
|
|
197
56
|
|
|
198
|
-
|
|
199
|
-
config.title = "My Awesome Server"
|
|
57
|
+
For command-line MCP servers that communicate via standard input/output:
|
|
200
58
|
|
|
201
|
-
|
|
59
|
+
```ruby
|
|
60
|
+
server = ModelContextProtocol::Server.with_stdio_transport do |config|
|
|
61
|
+
config.name = "MyMCPServer"
|
|
62
|
+
config.title = "My Server"
|
|
63
|
+
config.version = "1.0.0"
|
|
202
64
|
config.instructions = <<~INSTRUCTIONS
|
|
203
|
-
This server provides
|
|
65
|
+
This server provides prompts, tools, and resources for interacting with my app.
|
|
204
66
|
|
|
205
67
|
Key capabilities:
|
|
206
|
-
-
|
|
207
|
-
-
|
|
208
|
-
-
|
|
68
|
+
- Does something
|
|
69
|
+
- Does something else
|
|
70
|
+
- Oh, and it does this other thing, too
|
|
209
71
|
|
|
210
|
-
Use this server when you need to
|
|
72
|
+
Use this server when you need to do things.
|
|
211
73
|
INSTRUCTIONS
|
|
212
74
|
|
|
213
|
-
|
|
214
|
-
# prompts/list, resources/list, resource_template/list, tools/list
|
|
215
|
-
config.pagination = {
|
|
216
|
-
default_page_size: 50, # Default items per page
|
|
217
|
-
max_page_size: 500, # Maximum allowed page size
|
|
218
|
-
cursor_ttl: 1800 # Cursor expiry in seconds (30 minutes)
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
# Disable pagination support (enabled by default)
|
|
222
|
-
# config.pagination = false
|
|
223
|
-
|
|
224
|
-
# Optional: require specific environment variables to be set
|
|
225
|
-
config.require_environment_variable("API_KEY")
|
|
226
|
-
|
|
227
|
-
# Optional: set environment variables programmatically
|
|
228
|
-
config.set_environment_variable("DEBUG_MODE", "true")
|
|
229
|
-
|
|
230
|
-
# Optional: provide prompts, resources, and tools with contextual variables
|
|
231
|
-
config.context = {
|
|
232
|
-
user_id: "123456",
|
|
233
|
-
request_id: SecureRandom.uuid
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
# Optional: explicitly specify STDIO as the transport
|
|
237
|
-
# This is not necessary as STDIO is the default transport
|
|
238
|
-
# config.transport = { type: :stdio }
|
|
239
|
-
|
|
240
|
-
# Optional: configure streamable HTTP transport if required
|
|
241
|
-
# config.transport = {
|
|
242
|
-
# type: :streamable_http,
|
|
243
|
-
# env: request.env,
|
|
244
|
-
# session_ttl: 3600 # Optional: session timeout in seconds (default: 3600)
|
|
245
|
-
# }
|
|
246
|
-
|
|
247
|
-
# Register prompts, resources, resource templates, and tools
|
|
248
|
-
config.registry = ModelContextProtocol::Server::Registry.new do
|
|
75
|
+
config.registry do
|
|
249
76
|
prompts do
|
|
250
|
-
register
|
|
77
|
+
register MyPrompt
|
|
251
78
|
end
|
|
252
79
|
|
|
253
80
|
resources do
|
|
254
|
-
register
|
|
255
|
-
end
|
|
256
|
-
|
|
257
|
-
resource_templates do
|
|
258
|
-
register TestResourceTemplate
|
|
81
|
+
register MyResource
|
|
259
82
|
end
|
|
260
83
|
|
|
261
84
|
tools do
|
|
262
|
-
register
|
|
85
|
+
register MyTool
|
|
263
86
|
end
|
|
264
87
|
end
|
|
265
88
|
end
|
|
266
89
|
|
|
267
|
-
# Start the MCP server
|
|
268
90
|
server.start
|
|
269
91
|
```
|
|
270
92
|
|
|
271
|
-
###
|
|
93
|
+
### Streamable HTTP Transport
|
|
272
94
|
|
|
273
|
-
|
|
95
|
+
For HTTP-based MCP servers (e.g., Rails applications), you'll need to setup your MCP server in an initializer with Redis configuration. Redis enables coordination across multiple server processes in production deployments (e.g., Puma workers), where no single process can hold all state in memory.
|
|
274
96
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
| `version` | String | Yes | - | Version of the MCP server |
|
|
279
|
-
| `title` | String | No | - | Human-readable display name for the MCP server |
|
|
280
|
-
| `instructions` | String | No | - | Instructions for how the MCP server should be used by LLMs |
|
|
281
|
-
| `pagination` | Hash/Boolean | No | See pagination table | Pagination configuration (or `false` to disable) |
|
|
282
|
-
| `context` | Hash | No | `{}` | Contextual variables available to prompts, resources, and tools |
|
|
283
|
-
| `transport` | Hash | No | `{ type: :stdio }` | Transport configuration |
|
|
284
|
-
| `registry` | Registry | Yes | - | Registry containing prompts, resources, and tools |
|
|
285
|
-
|
|
286
|
-
### Pagination Configuration Options
|
|
97
|
+
```ruby
|
|
98
|
+
# config/initializers/model_context_protocol.rb
|
|
99
|
+
require "model_context_protocol"
|
|
287
100
|
|
|
288
|
-
|
|
101
|
+
# Assuming your handlers will be organized in the app/mcp folder.
|
|
102
|
+
Dir[Rails.root.join("app/mcp/**/*.rb")].sort.each { |f| require f }
|
|
289
103
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
104
|
+
ModelContextProtocol::Server.with_streamable_http_transport do |config|
|
|
105
|
+
config.name = "MyServer"
|
|
106
|
+
config.title = "My Server"
|
|
107
|
+
config.version = "1.0.0"
|
|
108
|
+
config.instructions = <<~INSTRUCTIONS
|
|
109
|
+
This server provides prompts, tools, and resources for interacting with my app.
|
|
295
110
|
|
|
296
|
-
|
|
111
|
+
Key capabilities:
|
|
112
|
+
- Does something
|
|
113
|
+
- Does something else
|
|
114
|
+
- Oh, and it does this other thing, too
|
|
297
115
|
|
|
298
|
-
|
|
116
|
+
Use this server when you need to do things.
|
|
117
|
+
INSTRUCTIONS
|
|
299
118
|
|
|
300
|
-
|
|
119
|
+
config.redis_url = ENV.fetch("REDIS_URL", "redis://localhost:6379/0")
|
|
120
|
+
config.redis_pool_size = 20
|
|
121
|
+
config.redis_pool_timeout = 5
|
|
122
|
+
config.redis_enable_reaper = true
|
|
123
|
+
config.redis_reaper_interval = 60
|
|
124
|
+
config.redis_idle_timeout = 300
|
|
125
|
+
config.redis_ssl_params = {verify_mode: OpenSSL::SSL::VERIFY_NONE}
|
|
126
|
+
|
|
127
|
+
config.registry do
|
|
128
|
+
prompts do
|
|
129
|
+
register MyPrompt
|
|
130
|
+
end
|
|
301
131
|
|
|
302
|
-
|
|
132
|
+
resources do
|
|
133
|
+
register MyResource
|
|
134
|
+
end
|
|
303
135
|
|
|
304
|
-
|
|
305
|
-
|
|
136
|
+
tools do
|
|
137
|
+
register MyTool
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
306
141
|
```
|
|
307
142
|
|
|
308
|
-
|
|
143
|
+
If your app uses Puma (>= 7.0) as the web server, use the provided plugin to start the MCP server.
|
|
309
144
|
|
|
310
145
|
```ruby
|
|
311
|
-
config.
|
|
146
|
+
# config/puma.rb
|
|
147
|
+
plugin :mcp
|
|
312
148
|
```
|
|
313
149
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
| Option | Type | Required | Default | Description |
|
|
317
|
-
|--------|------|----------|---------|-------------|
|
|
318
|
-
| `type` | Symbol | Yes | `:stdio` | Must be `:streamable_http` for HTTP transport |
|
|
319
|
-
| `session_ttl` | Integer | No | `3600` | Session timeout in seconds (1 hour) |
|
|
320
|
-
| `env` | Hash | No | - | Rack environment hash (for Rails integration) |
|
|
321
|
-
|
|
322
|
-
### Redis Configuration
|
|
323
|
-
|
|
324
|
-
The `:streamable_http` transport requires Redis to be configured globally before use:
|
|
150
|
+
For Puma 6.x or other web servers, you'll need to manually implement logic for starting and shutting the MCP server appropriately. This example shows how to do so for Puma 6.x; you can adapt it for your server of choice:
|
|
325
151
|
|
|
326
152
|
```ruby
|
|
327
|
-
|
|
328
|
-
config.redis_url = ENV.fetch('REDIS_URL')
|
|
329
|
-
config.pool_size = 20
|
|
330
|
-
config.pool_timeout = 5
|
|
331
|
-
config.enable_reaper = true
|
|
332
|
-
config.reaper_interval = 60
|
|
333
|
-
config.idle_timeout = 300
|
|
334
|
-
end
|
|
335
|
-
```
|
|
153
|
+
# config/puma.rb
|
|
336
154
|
|
|
337
|
-
|
|
338
|
-
|--------|------|----------|---------|-------------|
|
|
339
|
-
| `redis_url` | String | Yes | - | Redis connection URL |
|
|
340
|
-
| `pool_size` | Integer | No | `20` | Connection pool size |
|
|
341
|
-
| `pool_timeout` | Integer | No | `5` | Pool checkout timeout in seconds |
|
|
342
|
-
| `enable_reaper` | Boolean | No | `true` | Enable connection reaping |
|
|
343
|
-
| `reaper_interval` | Integer | No | `60` | Reaper check interval in seconds |
|
|
344
|
-
| `idle_timeout` | Integer | No | `300` | Idle connection timeout in seconds |
|
|
155
|
+
workers ENV.fetch("WEB_CONCURRENCY", 0).to_i
|
|
345
156
|
|
|
346
|
-
|
|
157
|
+
mcp_start = ->(*) { ModelContextProtocol::Server.start unless ModelContextProtocol::Server.running? }
|
|
158
|
+
mcp_shutdown = ->(*) { ModelContextProtocol::Server.shutdown }
|
|
347
159
|
|
|
348
|
-
|
|
160
|
+
# Clustered mode: workers fork, so start threads after fork
|
|
161
|
+
on_worker_boot(&mcp_start)
|
|
162
|
+
on_worker_shutdown(&mcp_shutdown)
|
|
349
163
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
config.progname = "MyMCPServer" # Program name for log entries
|
|
355
|
-
config.formatter = proc do |severity, datetime, progname, msg|
|
|
356
|
-
"#{datetime.strftime('%Y-%m-%d %H:%M:%S')} #{severity} [#{progname}] #{msg}\n"
|
|
357
|
-
end
|
|
164
|
+
# Single mode: start directly (no forking)
|
|
165
|
+
if ENV.fetch("WEB_CONCURRENCY", 0).to_i.zero?
|
|
166
|
+
mcp_start.call
|
|
167
|
+
at_exit(&mcp_shutdown)
|
|
358
168
|
end
|
|
359
169
|
```
|
|
360
170
|
|
|
361
|
-
|
|
362
|
-
|--------|------|----------|---------|-------------|
|
|
363
|
-
| `logdev` | IO/String | No | `$stderr` | Log destination (IO object or file path) |
|
|
364
|
-
| `level` | Integer | No | `Logger::INFO` | Minimum log level to output |
|
|
365
|
-
| `progname` | String | No | `"MCP-Server"` | Program name for log entries |
|
|
366
|
-
| `formatter` | Proc | No | Default timestamp format | Custom log formatter |
|
|
367
|
-
|
|
368
|
-
**Note:** When using `:stdio` transport, server logging must not use `$stdout` as it conflicts with the MCP protocol communication. Use `$stderr` or a file instead.
|
|
369
|
-
|
|
370
|
-
### Registry Configuration Options
|
|
171
|
+
Then, implement a controller action to handle the requests to the MCP server.
|
|
371
172
|
|
|
372
|
-
The registry is configured using `ModelContextProtocol::Server::Registry.new` and supports the following block types:
|
|
373
|
-
|
|
374
|
-
| Block Type | Options | Description |
|
|
375
|
-
|------------|---------|-------------|
|
|
376
|
-
| `prompts` | `list_changed: Boolean` | Register prompt handlers with optional list change notifications |
|
|
377
|
-
| `resources` | `list_changed: Boolean`, `subscribe: Boolean` | Register resource handlers with optional list change notifications and subscriptions |
|
|
378
|
-
| `resource_templates` | - | Register resource template handlers |
|
|
379
|
-
| `tools` | `list_changed: Boolean` | Register tool handlers with optional list change notifications |
|
|
380
|
-
|
|
381
|
-
Within each block, use `register ClassName` to register your handlers.
|
|
382
|
-
|
|
383
|
-
**Note:** The `list_changed` and `subscribe` options are accepted for capability advertisement but the list changed notification functionality is not yet implemented (see [Feature Support](#feature-support-server)).
|
|
384
|
-
|
|
385
|
-
**Example:**
|
|
386
173
|
```ruby
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
register MyPrompt
|
|
390
|
-
register AnotherPrompt
|
|
391
|
-
end
|
|
174
|
+
class ModelContextProtocolController < ActionController::API
|
|
175
|
+
include ActionController::Live
|
|
392
176
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
177
|
+
def handle
|
|
178
|
+
result = ModelContextProtocol::Server.serve(
|
|
179
|
+
env: request.env,
|
|
180
|
+
session_context: { user_id: current_user.id }
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
response.headers.merge!(result[:headers]) if result[:headers]
|
|
396
184
|
|
|
397
|
-
|
|
398
|
-
|
|
185
|
+
if result[:stream]
|
|
186
|
+
result[:stream_proc]&.call(response.stream)
|
|
187
|
+
else
|
|
188
|
+
render json: result[:json], status: result[:status] || 200
|
|
189
|
+
end
|
|
190
|
+
ensure
|
|
191
|
+
response.stream.close rescue nil
|
|
399
192
|
end
|
|
400
193
|
end
|
|
401
194
|
```
|
|
402
195
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
## Prompts
|
|
406
|
-
|
|
407
|
-
The `ModelContextProtocol::Server::Prompt` base class allows subclasses to define a prompt that the MCP client can use.
|
|
408
|
-
|
|
409
|
-
Define the prompt properties and then implement the `call` method to build your prompt. Any arguments passed to the prompt from the MCP client will be available in the `arguments` hash with symbol keys (e.g., `arguments[:argument_name]`), and any context values provided in the server configuration will be available in the `context` hash. Use the `respond_with` instance method to ensure your prompt responds with appropriately formatted response data.
|
|
410
|
-
|
|
411
|
-
You can also send MCP log messages to clients from within your prompt by calling a valid logger level method on the `client_logger` and passing a string message. For server-side debugging and monitoring, use the `server_logger` to write logs that are not sent to clients.
|
|
412
|
-
|
|
413
|
-
### Prompt Definition
|
|
414
|
-
|
|
415
|
-
Use the `define` block to set [prompt properties](https://spec.modelcontextprotocol.io/specification/2025-06-18/server/prompts/) and configure arguments.
|
|
416
|
-
|
|
417
|
-
| Property | Description |
|
|
418
|
-
|----------|-------------|
|
|
419
|
-
| `name` | The programmatic name of the prompt |
|
|
420
|
-
| `title` | Human-readable display name |
|
|
421
|
-
| `description` | Short description of what the prompt does |
|
|
422
|
-
| `argument` | Define an argument block with name, description, required flag, and completion |
|
|
423
|
-
|
|
424
|
-
### Argument Definition
|
|
425
|
-
|
|
426
|
-
Define any arguments using `argument` blocks nested within the `define` block. You can mark an argument as required, and you can optionally provide a completion class. See [Completions](#completions) for more information.
|
|
427
|
-
|
|
428
|
-
| Property | Description |
|
|
429
|
-
|----------|-------------|
|
|
430
|
-
| `name` | The name of the argument |
|
|
431
|
-
| `description` | A short description of the argument |
|
|
432
|
-
| `required` | Whether the argument is required (boolean) |
|
|
433
|
-
| `completion` | Available hints for completions (array or completion class) |
|
|
434
|
-
|
|
435
|
-
### Prompt Methods
|
|
436
|
-
|
|
437
|
-
Define your prompt properties and arguments, implement the `call` method using the `message_history` DSL to build prompt messages and `respond_with` to serialize them. You can wrap long running operations in a `cancellable` block to allow clients to cancel the request. Also, you can automatically send progress notifications to clients by wrapping long-running operations in a `progressable` block.
|
|
438
|
-
|
|
439
|
-
| Method | Context | Description |
|
|
440
|
-
|--------|---------|-------------|
|
|
441
|
-
| `define` | Class definition | Block for defining prompt metadata and arguments |
|
|
442
|
-
| `call` | Instance method | Main method to implement prompt logic and build response |
|
|
443
|
-
| `cancellable` | Within `call` | Wrap long-running operations to allow client cancellation (e.g., `cancellable { slow_operation }`) |
|
|
444
|
-
| `progressable` | Within `call` | Wrap long-running operations to send clients progress notifications (e.g., `progressable { slow_operation }`) |
|
|
445
|
-
| `message_history` | Within `call` | DSL method to build an array of user and assistant messages |
|
|
446
|
-
| `respond_with` | Within `call` | Return properly formatted response data (e.g., `respond_with messages:`) |
|
|
196
|
+
Lastly, add the necessary routes:
|
|
447
197
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|--------|---------|-------------|
|
|
454
|
-
| `user_message` | Within `message_history` | Create a message with user role |
|
|
455
|
-
| `assistant_message` | Within `message_history` | Create a message with assistant role |
|
|
456
|
-
|
|
457
|
-
### Content Blocks
|
|
458
|
-
|
|
459
|
-
Use content blocks to properly format the content included in messages.
|
|
198
|
+
```ruby
|
|
199
|
+
get "/", to: "model_context_protocol#handle", as: :mcp_get
|
|
200
|
+
post "/", to: "model_context_protocol#handle", as: :mcp_post
|
|
201
|
+
delete "/", to: "model_context_protocol#handle", as: :mcp_delete
|
|
202
|
+
```
|
|
460
203
|
|
|
461
|
-
|
|
462
|
-
|--------|---------|-------------|
|
|
463
|
-
| `text_content` | Within message blocks | Create text content block |
|
|
464
|
-
| `image_content` | Within message blocks | Create image content block (requires `data:` and `mime_type:`) |
|
|
465
|
-
| `audio_content` | Within message blocks | Create audio content block (requires `data:` and `mime_type:`) |
|
|
466
|
-
| `embedded_resource_content` | Within message blocks | Create embedded resource content block (requires `resource:`) |
|
|
467
|
-
| `resource_link` | Within message blocks | Create resource link content block (requires `name:` and `uri:`) |
|
|
204
|
+
For a complete Rails integration example, see the [Quick Start with Rails](https://github.com/dickdavis/model-context-protocol-rb/wiki/Quick-Start-with-Rails) guide.
|
|
468
205
|
|
|
469
|
-
|
|
206
|
+
For complete configuration details including all server options, Redis configuration, and logging options, see the [Building an MCP Server](https://github.com/dickdavis/model-context-protocol-rb/wiki/Building-an-MCP-Server) wiki page.
|
|
470
207
|
|
|
471
|
-
|
|
208
|
+
## Claude Code Plugin
|
|
472
209
|
|
|
473
|
-
|
|
474
|
-
|----------|---------|-------------|
|
|
475
|
-
| `arguments` | Within `call` | Hash containing client-provided arguments (symbol keys) |
|
|
476
|
-
| `context` | Within `call` | Hash containing server configuration context values |
|
|
477
|
-
| `client_logger` | Within `call` | Client logger instance for sending MCP log messages (e.g., `client_logger.info("message")`) |
|
|
478
|
-
| `server_logger` | Within `call` | Server logger instance for debugging and monitoring (e.g., `server_logger.debug("message")`) |
|
|
210
|
+
The [mcp-rb](https://github.com/dickdavis/model-context-protocol-rb-plugin) Claude Code plugin teaches Claude how to build MCP handlers and configure servers using this gem's DSL. It provides skills for creating tools, prompts, resources, and server configurations.
|
|
479
211
|
|
|
480
|
-
|
|
212
|
+
## Prompts
|
|
481
213
|
|
|
482
|
-
|
|
214
|
+
Define prompts that MCP clients can use to generate contextual message sequences.
|
|
483
215
|
|
|
484
216
|
```ruby
|
|
485
217
|
class TestPrompt < ModelContextProtocol::Server::Prompt
|
|
486
218
|
define do
|
|
487
|
-
# The name of the prompt for programmatic use
|
|
488
219
|
name "brainstorm_excuses"
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
# A short description of what the tool does
|
|
492
|
-
description "A prompt for brainstorming excuses to get out of something"
|
|
493
|
-
|
|
494
|
-
# Define arguments to be used with your prompt
|
|
495
|
-
argument do
|
|
496
|
-
# The name of the argument
|
|
497
|
-
name "tone"
|
|
498
|
-
# A short description of the argument
|
|
499
|
-
description "The general tone to be used in the generated excuses"
|
|
500
|
-
# If the argument is required
|
|
501
|
-
required false
|
|
502
|
-
# Available hints for completions
|
|
503
|
-
completion ["whiny", "angry", "callous", "desperate", "nervous", "sneaky"]
|
|
504
|
-
end
|
|
505
|
-
|
|
506
|
-
argument do
|
|
507
|
-
name "undesirable_activity"
|
|
508
|
-
description "The thing to get out of"
|
|
509
|
-
required true
|
|
510
|
-
end
|
|
220
|
+
description "A prompt for brainstorming excuses"
|
|
221
|
+
argument { name "tone"; required false }
|
|
511
222
|
end
|
|
512
223
|
|
|
513
|
-
# You can optionally define a custom completion for an argument and pass it to completions.
|
|
514
|
-
# ToneCompletion = ModelContextProtocol::Server::Completion.define do
|
|
515
|
-
# hints = ["whiny", "angry", "callous", "desperate", "nervous", "sneaky"]
|
|
516
|
-
# values = hints.grep(/#{argument_value}/)
|
|
517
|
-
# respond_with values:
|
|
518
|
-
# end
|
|
519
|
-
# ...
|
|
520
|
-
# define do
|
|
521
|
-
# argument do
|
|
522
|
-
# name "tone"
|
|
523
|
-
# description "The general tone to be used in the generated excuses"
|
|
524
|
-
# required false
|
|
525
|
-
# completion ToneCompletion
|
|
526
|
-
# end
|
|
527
|
-
# end
|
|
528
|
-
|
|
529
|
-
# The call method is invoked by the MCP Server to generate a response to resource/read requests
|
|
530
224
|
def call
|
|
531
|
-
# You can use the client_logger
|
|
532
|
-
client_logger.info("Brainstorming excuses...")
|
|
533
|
-
|
|
534
|
-
# Server logging for debugging and monitoring (not sent to client)
|
|
535
|
-
server_logger.debug("Prompt called with arguments: #{arguments}")
|
|
536
|
-
server_logger.info("Generating excuse brainstorming prompt")
|
|
537
|
-
|
|
538
|
-
# Build an array of user and assistant messages
|
|
539
225
|
messages = message_history do
|
|
540
|
-
|
|
541
|
-
user_message do
|
|
542
|
-
# Use any type of content block in a message (text, image, audio, embedded_resource, or resource_link)
|
|
543
|
-
text_content(text: "My wife wants me to: #{arguments[:undesirable_activity]}... Can you believe it?")
|
|
544
|
-
end
|
|
545
|
-
|
|
546
|
-
# You can also create messages with the assistant role
|
|
547
|
-
assistant_message do
|
|
548
|
-
text_content(text: "Oh, that's just downright awful. How can I help?")
|
|
549
|
-
end
|
|
550
|
-
|
|
551
|
-
user_message do
|
|
552
|
-
# Reference any inputs from the client by accessing the appropriate key in the arguments hash
|
|
553
|
-
text_content(text: "Can you generate some excuses for me?" + (arguments[:tone] ? " Make them as #{arguments[:tone]} as possible." : ""))
|
|
554
|
-
end
|
|
226
|
+
user_message { text_content(text: "Generate excuses with #{arguments[:tone]} tone") }
|
|
555
227
|
end
|
|
556
|
-
|
|
557
|
-
# Respond with the messages
|
|
558
228
|
respond_with messages:
|
|
559
229
|
end
|
|
560
230
|
end
|
|
561
231
|
```
|
|
562
232
|
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
The `ModelContextProtocol::Server::Resource` base class allows subclasses to define a resource that the MCP client can use.
|
|
568
|
-
|
|
569
|
-
Define the resource properties and optionally annotations, then implement the `call` method to build your resource. Use the `respond_with` instance method to ensure your resource responds with appropriately formatted response data.
|
|
570
|
-
|
|
571
|
-
You can also send MCP log messages to clients from within your resource by calling a valid logger level method on the `client_logger` and passing a string message. For server-side debugging and monitoring, use the `server_logger` to write logs that are not sent to clients.
|
|
572
|
-
|
|
573
|
-
### Resource Definition
|
|
574
|
-
|
|
575
|
-
Use the `define` block to set [resource properties](https://spec.modelcontextprotocol.io/specification/2025-06-18/server/resources/) and configure annotations.
|
|
576
|
-
|
|
577
|
-
| Property | Description |
|
|
578
|
-
|----------|-------------|
|
|
579
|
-
| `name` | The name of the resource |
|
|
580
|
-
| `title` | Human-readable display name |
|
|
581
|
-
| `description` | Short description of what the resource contains |
|
|
582
|
-
| `mime_type` | MIME type of the resource content |
|
|
583
|
-
| `uri` | URI identifier for the resource |
|
|
584
|
-
| `annotations` | Block for defining resource annotations |
|
|
585
|
-
|
|
586
|
-
### Annotation Definition
|
|
587
|
-
|
|
588
|
-
Define any [resource annotations](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#annotations) using an `annotations` block nested within the `define` block.
|
|
233
|
+
Key features:
|
|
234
|
+
- Define arguments with validation and completion hints
|
|
235
|
+
- Build message histories with user and assistant messages
|
|
236
|
+
- Support for text, image, audio, and embedded resource content
|
|
589
237
|
|
|
590
|
-
|
|
591
|
-
|----------|-------------|
|
|
592
|
-
| `audience` | Target audience for the resource (array of symbols like `[:user, :assistant]`) |
|
|
593
|
-
| `priority` | Priority level (numeric value, e.g., `0.9`) |
|
|
594
|
-
| `last_modified` | Last modified timestamp (ISO 8601 string) |
|
|
238
|
+
For complete documentation and examples, see the [Prompts](https://github.com/dickdavis/model-context-protocol-rb/wiki/Prompts) wiki page.
|
|
595
239
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
Define your resource properties and annotations, implement the `call` method to build resource content and `respond_with` to serialize the response. You can wrap long running operations in a `cancellable` block to allow clients to cancel the request. Also, you can automatically send progress notifications to clients by wrapping long-running operations in a `progressable` block.
|
|
599
|
-
|
|
600
|
-
| Method | Context | Description |
|
|
601
|
-
|--------|---------|-------------|
|
|
602
|
-
| `define` | Class definition | Block for defining resource metadata and annotations |
|
|
603
|
-
| `call` | Instance method | Main method to implement resource logic and build response |
|
|
604
|
-
| `cancellable` | Within `call` | Wrap long-running operations to allow client cancellation (e.g., `cancellable { slow_operation }`) |
|
|
605
|
-
| `progressable` | Within `call` | Wrap long-running operations to send clients progress notifications (e.g., `progressable { slow_operation }`) |
|
|
606
|
-
| `respond_with` | Within `call` | Return properly formatted response data (e.g., `respond_with text:` or `respond_with binary:`) |
|
|
607
|
-
|
|
608
|
-
### Available Instance Variables
|
|
609
|
-
|
|
610
|
-
Resources have access to their configured properties and server context.
|
|
611
|
-
|
|
612
|
-
| Variable | Context | Description |
|
|
613
|
-
|----------|---------|-------------|
|
|
614
|
-
| `mime_type` | Within `call` | The configured MIME type for this resource |
|
|
615
|
-
| `uri` | Within `call` | The configured URI identifier for this resource |
|
|
616
|
-
| `client_logger` | Within `call` | Client logger instance for sending MCP log messages (e.g., `client_logger.info("message")`) |
|
|
617
|
-
| `server_logger` | Within `call` | Server logger instance for debugging and monitoring (e.g., `server_logger.debug("message")`) |
|
|
618
|
-
| `context` | Within `call` | Hash containing server configuration context values |
|
|
619
|
-
|
|
620
|
-
### Examples
|
|
240
|
+
## Resources
|
|
621
241
|
|
|
622
|
-
|
|
242
|
+
Expose data and content to MCP clients through defined resources.
|
|
623
243
|
|
|
624
244
|
```ruby
|
|
625
245
|
class TestResource < ModelContextProtocol::Server::Resource
|
|
626
246
|
define do
|
|
627
|
-
name "
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
uri "file:///top-secret-plans.txt"
|
|
632
|
-
end
|
|
633
|
-
|
|
634
|
-
def call
|
|
635
|
-
respond_with text: "I'm finna eat all my wife's leftovers."
|
|
636
|
-
end
|
|
637
|
-
end
|
|
638
|
-
```
|
|
639
|
-
|
|
640
|
-
This is an example resource with annotations:
|
|
641
|
-
|
|
642
|
-
```ruby
|
|
643
|
-
class TestAnnotatedResource < ModelContextProtocol::Server::Resource
|
|
644
|
-
define do
|
|
645
|
-
name "annotated-document.md"
|
|
646
|
-
description "A document with annotations showing priority and audience"
|
|
647
|
-
mime_type "text/markdown"
|
|
648
|
-
uri "file:///docs/annotated-document.md"
|
|
649
|
-
annotations do
|
|
650
|
-
audience [:user, :assistant]
|
|
651
|
-
priority 0.9
|
|
652
|
-
last_modified "2025-01-12T15:00:58Z"
|
|
653
|
-
end
|
|
247
|
+
name "config.json"
|
|
248
|
+
description "Application configuration"
|
|
249
|
+
mime_type "application/json"
|
|
250
|
+
uri "file:///config.json"
|
|
654
251
|
end
|
|
655
252
|
|
|
656
253
|
def call
|
|
657
|
-
respond_with text:
|
|
254
|
+
respond_with text: { setting: "value" }.to_json
|
|
658
255
|
end
|
|
659
256
|
end
|
|
660
257
|
```
|
|
661
258
|
|
|
662
|
-
|
|
259
|
+
Key features:
|
|
260
|
+
- Define metadata including MIME type and URI
|
|
261
|
+
- Return text or binary content
|
|
262
|
+
- Add annotations for audience and priority
|
|
663
263
|
|
|
664
|
-
|
|
665
|
-
class TestBinaryResource < ModelContextProtocol::Server::Resource
|
|
666
|
-
define do
|
|
667
|
-
name "project-logo.png"
|
|
668
|
-
description "The logo for the project"
|
|
669
|
-
mime_type "image/png"
|
|
670
|
-
uri "file:///project-logo.png"
|
|
671
|
-
end
|
|
672
|
-
|
|
673
|
-
def call
|
|
674
|
-
# In a real implementation, we would retrieve the binary resource
|
|
675
|
-
# This is a small valid base64 encoded string (represents "test")
|
|
676
|
-
data = "dGVzdA=="
|
|
677
|
-
respond_with binary: data
|
|
678
|
-
end
|
|
679
|
-
end
|
|
680
|
-
```
|
|
681
|
-
|
|
682
|
-
---
|
|
264
|
+
For complete documentation and examples, see the [Resources](https://github.com/dickdavis/model-context-protocol-rb/wiki/Resources) wiki page.
|
|
683
265
|
|
|
684
266
|
## Resource Templates
|
|
685
267
|
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
Define the resource template properties and URI template with optional parameter completions. Resource templates are used to define parameterized resources that clients can instantiate.
|
|
689
|
-
|
|
690
|
-
### Resource Template Definition
|
|
691
|
-
|
|
692
|
-
Use the `define` block to set [resource template properties](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#resource-templates).
|
|
693
|
-
|
|
694
|
-
| Property | Description |
|
|
695
|
-
|----------|-------------|
|
|
696
|
-
| `name` | The name of the resource template |
|
|
697
|
-
| `description` | Short description of what the template provides |
|
|
698
|
-
| `mime_type` | MIME type of resources created from this template |
|
|
699
|
-
| `uri_template` | URI template with parameters (e.g., `"file:///{name}"`) |
|
|
700
|
-
|
|
701
|
-
### URI Template Configuration
|
|
702
|
-
|
|
703
|
-
Define the URI template and configure parameter completions within the `uri_template` block.
|
|
704
|
-
|
|
705
|
-
| Method | Context | Description |
|
|
706
|
-
|--------|---------|-------------|
|
|
707
|
-
| `completion` | Within `uri_template` block | Define completion for a URI parameter (e.g., `completion :name, ["value1", "value2"]`) |
|
|
708
|
-
|
|
709
|
-
### Resource Template Methods
|
|
710
|
-
|
|
711
|
-
Resource templates only use the `define` method to configure their properties - they don't have a `call` method.
|
|
712
|
-
|
|
713
|
-
| Method | Context | Description |
|
|
714
|
-
|--------|---------|-------------|
|
|
715
|
-
| `define` | Class definition | Block for defining resource template metadata and URI template |
|
|
716
|
-
|
|
717
|
-
### Examples
|
|
718
|
-
|
|
719
|
-
This is an example resource template that provides a completion for a parameter of the URI template:
|
|
268
|
+
Define parameterized resources with URI templates that clients can instantiate.
|
|
720
269
|
|
|
721
270
|
```ruby
|
|
722
271
|
class TestResourceTemplate < ModelContextProtocol::Server::ResourceTemplate
|
|
723
272
|
define do
|
|
724
|
-
name "
|
|
725
|
-
description "
|
|
273
|
+
name "document-template"
|
|
274
|
+
description "Template for retrieving documents"
|
|
726
275
|
mime_type "text/plain"
|
|
727
276
|
uri_template "file:///{name}" do
|
|
728
|
-
completion :name, ["
|
|
277
|
+
completion :name, ["readme.txt", "config.json"]
|
|
729
278
|
end
|
|
730
279
|
end
|
|
731
|
-
|
|
732
|
-
# You can optionally define a custom completion for an argument and pass it to completions.
|
|
733
|
-
# Completion = ModelContextProtocol::Server::Completion.define do
|
|
734
|
-
# hints = {
|
|
735
|
-
# "name" => ["top-secret-plans.txt"]
|
|
736
|
-
# }
|
|
737
|
-
# values = hints[argument_name].grep(/#{argument_value}/)
|
|
738
|
-
|
|
739
|
-
# respond_with values:
|
|
740
|
-
# end
|
|
741
|
-
|
|
742
|
-
# define do
|
|
743
|
-
# name "project-document-resource-template"
|
|
744
|
-
# description "A resource template for retrieving project documents"
|
|
745
|
-
# mime_type "text/plain"
|
|
746
|
-
# uri_template "file:///{name}" do
|
|
747
|
-
# completion :name, Completion
|
|
748
|
-
# end
|
|
749
|
-
# end
|
|
750
280
|
end
|
|
751
281
|
```
|
|
752
282
|
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
The `ModelContextProtocol::Server::Tool` base class allows subclasses to define a tool that the MCP client can use.
|
|
758
|
-
|
|
759
|
-
Define the tool properties and schemas, then implement the `call` method to build your tool. Any arguments passed to the tool from the MCP client will be available in the `arguments` hash with symbol keys (e.g., `arguments[:argument_name]`), and any context values provided in the server configuration will be available in the `context` hash. Use the `respond_with` instance method to ensure your prompt responds with appropriately formatted response data.
|
|
760
|
-
|
|
761
|
-
You can also send MCP log messages to clients from within your tool by calling a valid logger level method on the `client_logger` and passing a string message. For server-side debugging and monitoring, use the `server_logger` to write logs that are not sent to clients.
|
|
762
|
-
|
|
763
|
-
### Tool Definition
|
|
283
|
+
Key features:
|
|
284
|
+
- Define URI templates with parameters
|
|
285
|
+
- Provide completion hints for template parameters
|
|
764
286
|
|
|
765
|
-
|
|
287
|
+
For complete documentation and examples, see the [Resource Templates](https://github.com/dickdavis/model-context-protocol-rb/wiki/Resource-Templates) wiki page.
|
|
766
288
|
|
|
767
|
-
|
|
768
|
-
|----------|-------------|
|
|
769
|
-
| `name` | The programmatic name of the tool |
|
|
770
|
-
| `title` | Human-readable display name |
|
|
771
|
-
| `description` | Short description of what the tool does |
|
|
772
|
-
| `input_schema` | JSON schema block for validating tool inputs |
|
|
773
|
-
| `output_schema` | JSON schema block for validating structured content outputs |
|
|
774
|
-
|
|
775
|
-
### Tool Methods
|
|
776
|
-
|
|
777
|
-
Define your tool properties and schemas, implement the `call` method using content helpers and `respond_with` to serialize responses. You can wrap long running operations in a `cancellable` block to allow clients to cancel the request. Also, you can automatically send progress notifications to clients by wrapping long-running operations in a `progressable` block.
|
|
778
|
-
|
|
779
|
-
| Method | Context | Description |
|
|
780
|
-
|--------|---------|-------------|
|
|
781
|
-
| `define` | Class definition | Block for defining tool metadata and schemas |
|
|
782
|
-
| `call` | Instance method | Main method to implement tool logic and build response |
|
|
783
|
-
| `cancellable` | Within `call` | Wrap long-running operations to allow client cancellation (e.g., `cancellable { slow_operation }`) |
|
|
784
|
-
| `progressable` | Within `call` | Wrap long-running operations to send clients progress notifications (e.g., `progressable { slow_operation }`) |
|
|
785
|
-
| `respond_with` | Within `call` | Return properly formatted response data with various content types |
|
|
786
|
-
|
|
787
|
-
### Content Blocks
|
|
788
|
-
|
|
789
|
-
Use content blocks to properly format the content included in tool responses.
|
|
790
|
-
|
|
791
|
-
| Method | Context | Description |
|
|
792
|
-
|--------|---------|-------------|
|
|
793
|
-
| `text_content` | Within `call` | Create text content block |
|
|
794
|
-
| `image_content` | Within `call` | Create image content block (requires `data:` and `mime_type:`) |
|
|
795
|
-
| `audio_content` | Within `call` | Create audio content block (requires `data:` and `mime_type:`) |
|
|
796
|
-
| `embedded_resource_content` | Within `call` | Create embedded resource content block (requires `resource:`) |
|
|
797
|
-
| `resource_link` | Within `call` | Create resource link content block (requires `name:` and `uri:`) |
|
|
798
|
-
|
|
799
|
-
### Response Types
|
|
800
|
-
|
|
801
|
-
Tools can return different types of responses using `respond_with`.
|
|
802
|
-
|
|
803
|
-
| Response Type | Usage | Description |
|
|
804
|
-
|---------------|-------|-------------|
|
|
805
|
-
| `structured_content:` | `respond_with structured_content: data` | Return structured data validated against output schema |
|
|
806
|
-
| `content:` | `respond_with content: content_block` | Return single content block |
|
|
807
|
-
| `content:` | `respond_with content: [content_blocks]` | Return array of mixed content blocks |
|
|
808
|
-
| `error:` | `respond_with error: "message"` | Return tool error response |
|
|
809
|
-
|
|
810
|
-
### Available Instance Variables
|
|
811
|
-
|
|
812
|
-
Arguments from MCP clients and server context are available, along with logging capabilities.
|
|
813
|
-
|
|
814
|
-
| Variable | Context | Description |
|
|
815
|
-
|----------|---------|-------------|
|
|
816
|
-
| `arguments` | Within `call` | Hash containing client-provided arguments (symbol keys) |
|
|
817
|
-
| `context` | Within `call` | Hash containing server configuration context values |
|
|
818
|
-
| `client_logger` | Within `call` | Client logger instance for sending MCP log messages (e.g., `client_logger.info("message")`) |
|
|
819
|
-
| `server_logger` | Within `call` | Server logger instance for debugging and monitoring (e.g., `server_logger.debug("message")`) |
|
|
820
|
-
|
|
821
|
-
### Examples
|
|
289
|
+
## Tools
|
|
822
290
|
|
|
823
|
-
|
|
291
|
+
Create callable functions that MCP clients can invoke with validated inputs.
|
|
824
292
|
|
|
825
293
|
```ruby
|
|
826
294
|
class TestToolWithStructuredContentResponse < ModelContextProtocol::Server::Tool
|
|
@@ -865,6 +333,13 @@ class TestToolWithStructuredContentResponse < ModelContextProtocol::Server::Tool
|
|
|
865
333
|
required: ["temperature", "conditions", "humidity"]
|
|
866
334
|
}
|
|
867
335
|
end
|
|
336
|
+
# Optional security requirements for the tool
|
|
337
|
+
security_schemes do
|
|
338
|
+
[
|
|
339
|
+
{type: "noauth"},
|
|
340
|
+
{type: "oauth2", scopes: ["search.read"]}
|
|
341
|
+
]
|
|
342
|
+
end
|
|
868
343
|
end
|
|
869
344
|
|
|
870
345
|
def call
|
|
@@ -896,337 +371,55 @@ class TestToolWithStructuredContentResponse < ModelContextProtocol::Server::Tool
|
|
|
896
371
|
end
|
|
897
372
|
```
|
|
898
373
|
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
title "Number Doubler"
|
|
906
|
-
description "Doubles the provided number"
|
|
907
|
-
input_schema do
|
|
908
|
-
{
|
|
909
|
-
type: "object",
|
|
910
|
-
properties: {
|
|
911
|
-
number: {
|
|
912
|
-
type: "string"
|
|
913
|
-
}
|
|
914
|
-
},
|
|
915
|
-
required: ["number"]
|
|
916
|
-
}
|
|
917
|
-
end
|
|
918
|
-
end
|
|
919
|
-
|
|
920
|
-
def call
|
|
921
|
-
client_logger.info("Silly user doesn't know how to double a number")
|
|
922
|
-
number = arguments[:number].to_i
|
|
923
|
-
calculation = number * 2
|
|
924
|
-
|
|
925
|
-
user_id = context[:user_id]
|
|
926
|
-
salutation = user_id ? "User #{user_id}, " : ""
|
|
927
|
-
text_content = text_content(text: salutation << "#{number} doubled is #{calculation}")
|
|
928
|
-
|
|
929
|
-
respond_with content: text_content
|
|
930
|
-
end
|
|
931
|
-
end
|
|
932
|
-
```
|
|
374
|
+
Key features:
|
|
375
|
+
- Define input and output JSON schemas
|
|
376
|
+
- Declare tool security schemes (e.g., noauth, oauth2 scopes)
|
|
377
|
+
- Return text, image, audio, or embedded resource content
|
|
378
|
+
- Support for structured content responses
|
|
379
|
+
- Cancellable and progressable operations
|
|
933
380
|
|
|
934
|
-
|
|
381
|
+
For complete documentation and 7 detailed examples, see the [Tools](https://github.com/dickdavis/model-context-protocol-rb/wiki/Tools) wiki page.
|
|
935
382
|
|
|
936
|
-
|
|
937
|
-
class TestToolWithImageResponse < ModelContextProtocol::Server::Tool
|
|
938
|
-
define do
|
|
939
|
-
name "custom-chart-generator"
|
|
940
|
-
description "Generates a chart in various formats"
|
|
941
|
-
input_schema do
|
|
942
|
-
{
|
|
943
|
-
type: "object",
|
|
944
|
-
properties: {
|
|
945
|
-
chart_type: {
|
|
946
|
-
type: "string",
|
|
947
|
-
description: "Type of chart (pie, bar, line)"
|
|
948
|
-
},
|
|
949
|
-
format: {
|
|
950
|
-
type: "string",
|
|
951
|
-
description: "Image format (jpg, svg, etc)"
|
|
952
|
-
}
|
|
953
|
-
},
|
|
954
|
-
required: ["chart_type", "format"]
|
|
955
|
-
}
|
|
956
|
-
end
|
|
957
|
-
end
|
|
958
|
-
|
|
959
|
-
def call
|
|
960
|
-
# Map format to mime type
|
|
961
|
-
mime_type = case arguments[:format].downcase
|
|
962
|
-
when "svg"
|
|
963
|
-
"image/svg+xml"
|
|
964
|
-
when "jpg", "jpeg"
|
|
965
|
-
"image/jpeg"
|
|
966
|
-
else
|
|
967
|
-
"image/png"
|
|
968
|
-
end
|
|
969
|
-
|
|
970
|
-
# In a real implementation, we would generate an actual chart
|
|
971
|
-
# This is a small valid base64 encoded string (represents "test")
|
|
972
|
-
data = "dGVzdA=="
|
|
973
|
-
image_content = image_content(data:, mime_type:)
|
|
974
|
-
respond_with content: image_content
|
|
975
|
-
end
|
|
976
|
-
end
|
|
977
|
-
```
|
|
978
|
-
|
|
979
|
-
This is an example of a tool that returns an embedded resource response:
|
|
980
|
-
|
|
981
|
-
```ruby
|
|
982
|
-
class TestToolWithResourceResponse < ModelContextProtocol::Server::Tool
|
|
983
|
-
define do
|
|
984
|
-
name "resource-finder"
|
|
985
|
-
description "Finds a resource given a name"
|
|
986
|
-
input_schema do
|
|
987
|
-
{
|
|
988
|
-
type: "object",
|
|
989
|
-
properties: {
|
|
990
|
-
name: {
|
|
991
|
-
type: "string",
|
|
992
|
-
description: "The name of the resource"
|
|
993
|
-
}
|
|
994
|
-
},
|
|
995
|
-
required: ["name"]
|
|
996
|
-
}
|
|
997
|
-
end
|
|
998
|
-
end
|
|
999
|
-
|
|
1000
|
-
RESOURCE_MAPPINGS = {
|
|
1001
|
-
test_annotated_resource: TestAnnotatedResource,
|
|
1002
|
-
test_binary_resource: TestBinaryResource,
|
|
1003
|
-
test_resource: TestResource
|
|
1004
|
-
}.freeze
|
|
1005
|
-
|
|
1006
|
-
def call
|
|
1007
|
-
name = arguments[:name]
|
|
1008
|
-
resource_klass = RESOURCE_MAPPINGS[name.downcase.to_sym]
|
|
1009
|
-
unless resource_klass
|
|
1010
|
-
return respond_with :error, text: "Resource `#{name}` not found"
|
|
1011
|
-
end
|
|
1012
|
-
|
|
1013
|
-
resource_data = resource_klass.call(client_logger, context)
|
|
1014
|
-
|
|
1015
|
-
respond_with content: embedded_resource_content(resource: resource_data)
|
|
1016
|
-
end
|
|
1017
|
-
end
|
|
1018
|
-
```
|
|
1019
|
-
|
|
1020
|
-
This is an example of a tool that returns mixed content:
|
|
1021
|
-
|
|
1022
|
-
```ruby
|
|
1023
|
-
class TestToolWithMixedContentResponse < ModelContextProtocol::Server::Tool
|
|
1024
|
-
define do
|
|
1025
|
-
name "get_temperature_history"
|
|
1026
|
-
description "Gets comprehensive temperature history for a zip code"
|
|
1027
|
-
input_schema do
|
|
1028
|
-
{
|
|
1029
|
-
type: "object",
|
|
1030
|
-
properties: {
|
|
1031
|
-
zip: {
|
|
1032
|
-
type: "string"
|
|
1033
|
-
}
|
|
1034
|
-
},
|
|
1035
|
-
required: ["zip"]
|
|
1036
|
-
}
|
|
1037
|
-
end
|
|
1038
|
-
end
|
|
1039
|
-
|
|
1040
|
-
def call
|
|
1041
|
-
client_logger.info("Getting comprehensive temperature history data")
|
|
1042
|
-
|
|
1043
|
-
zip = arguments[:zip]
|
|
1044
|
-
temperature_history = retrieve_temperature_history(zip:)
|
|
1045
|
-
temperature_history_block = text_content(text: temperature_history.join(", "))
|
|
1046
|
-
|
|
1047
|
-
temperature_chart = generate_weather_history_chart(temperature_history)
|
|
1048
|
-
temperature_chart_block = image_content(
|
|
1049
|
-
data: temperature_chart[:base64_chart_data],
|
|
1050
|
-
mime_type: temperature_chart[:mime_type]
|
|
1051
|
-
)
|
|
1052
|
-
|
|
1053
|
-
respond_with content: [temperature_history_block, temperature_chart_block]
|
|
1054
|
-
end
|
|
1055
|
-
|
|
1056
|
-
private
|
|
1057
|
-
|
|
1058
|
-
def retrieve_temperature_history(zip:)
|
|
1059
|
-
# Simulates a call to an API or DB to retrieve weather history
|
|
1060
|
-
[85.2, 87.4, 89.0, 95.3, 96.0]
|
|
1061
|
-
end
|
|
1062
|
-
|
|
1063
|
-
def generate_weather_history_chart(history)
|
|
1064
|
-
# SImulate a call to generate a chart given the weather history
|
|
1065
|
-
{
|
|
1066
|
-
base64_chart_data: "dGVzdA==",
|
|
1067
|
-
mime_type: "image/png"
|
|
1068
|
-
}
|
|
1069
|
-
end
|
|
1070
|
-
end
|
|
1071
|
-
```
|
|
383
|
+
## Completions
|
|
1072
384
|
|
|
1073
|
-
|
|
385
|
+
Provide argument completion hints for prompts and resource templates.
|
|
1074
386
|
|
|
1075
387
|
```ruby
|
|
1076
|
-
class
|
|
1077
|
-
define do
|
|
1078
|
-
name "api-caller"
|
|
1079
|
-
description "Makes calls to external APIs"
|
|
1080
|
-
input_schema do
|
|
1081
|
-
{
|
|
1082
|
-
type: "object",
|
|
1083
|
-
properties: {
|
|
1084
|
-
api_endpoint: {
|
|
1085
|
-
type: "string",
|
|
1086
|
-
description: "API endpoint URL"
|
|
1087
|
-
},
|
|
1088
|
-
method: {
|
|
1089
|
-
type: "string",
|
|
1090
|
-
description: "HTTP method (GET, POST, etc)"
|
|
1091
|
-
}
|
|
1092
|
-
},
|
|
1093
|
-
required: ["api_endpoint", "method"]
|
|
1094
|
-
}
|
|
1095
|
-
end
|
|
1096
|
-
end
|
|
1097
|
-
|
|
388
|
+
class TestCompletion < ModelContextProtocol::Server::Completion
|
|
1098
389
|
def call
|
|
1099
|
-
|
|
1100
|
-
|
|
390
|
+
hints = { "tone" => ["whiny", "angry", "nervous"] }
|
|
391
|
+
values = hints[argument_name].grep(/#{argument_value}/)
|
|
392
|
+
respond_with values:
|
|
1101
393
|
end
|
|
1102
394
|
end
|
|
1103
395
|
```
|
|
1104
396
|
|
|
1105
|
-
|
|
397
|
+
For complete documentation, see the [Completions](https://github.com/dickdavis/model-context-protocol-rb/wiki/Completions) wiki page.
|
|
1106
398
|
|
|
1107
|
-
|
|
1108
|
-
class TestToolWithCancellableSleep < ModelContextProtocol::Server::Tool
|
|
1109
|
-
define do
|
|
1110
|
-
name "cancellable_sleep"
|
|
1111
|
-
title "Cancellable Sleep Tool"
|
|
1112
|
-
description "Sleep for 3 seconds with cancellation support"
|
|
1113
|
-
input_schema do
|
|
1114
|
-
{
|
|
1115
|
-
type: "object",
|
|
1116
|
-
properties: {},
|
|
1117
|
-
additionalProperties: false
|
|
1118
|
-
}
|
|
1119
|
-
end
|
|
1120
|
-
end
|
|
1121
|
-
|
|
1122
|
-
def call
|
|
1123
|
-
client_logger.info("Starting 3 second sleep operation")
|
|
1124
|
-
|
|
1125
|
-
result = cancellable do
|
|
1126
|
-
sleep 3
|
|
1127
|
-
"Sleep completed successfully"
|
|
1128
|
-
end
|
|
1129
|
-
|
|
1130
|
-
respond_with content: text_content(text: result)
|
|
1131
|
-
end
|
|
1132
|
-
end
|
|
1133
|
-
```
|
|
399
|
+
## Testing with RSpec
|
|
1134
400
|
|
|
1135
|
-
This
|
|
401
|
+
This gem provides custom RSpec matchers and helpers for testing your MCP handlers.
|
|
1136
402
|
|
|
1137
403
|
```ruby
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
name "test_tool_with_progressable_and_cancellable"
|
|
1141
|
-
description "A test tool that demonstrates combined progressable and cancellable functionality"
|
|
1142
|
-
|
|
1143
|
-
input_schema do
|
|
1144
|
-
{
|
|
1145
|
-
type: "object",
|
|
1146
|
-
properties: {
|
|
1147
|
-
max_duration: {
|
|
1148
|
-
type: "number",
|
|
1149
|
-
description: "Expected maximum duration in seconds"
|
|
1150
|
-
},
|
|
1151
|
-
work_steps: {
|
|
1152
|
-
type: "number",
|
|
1153
|
-
description: "Number of work steps to perform"
|
|
1154
|
-
}
|
|
1155
|
-
},
|
|
1156
|
-
required: ["max_duration"]
|
|
1157
|
-
}
|
|
1158
|
-
end
|
|
1159
|
-
end
|
|
1160
|
-
|
|
1161
|
-
def call
|
|
1162
|
-
max_duration = arguments[:max_duration] || 10
|
|
1163
|
-
work_steps = arguments[:work_steps] || 10
|
|
1164
|
-
client_logger.info("Starting progressable call with max_duration=#{max_duration}, work_steps=#{work_steps}")
|
|
404
|
+
require "model_context_protocol/rspec"
|
|
405
|
+
ModelContextProtocol::RSpec.configure!
|
|
1165
406
|
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
sleep(max_duration / work_steps.to_f)
|
|
1172
|
-
processed_items << "item_#{i + 1}"
|
|
1173
|
-
end
|
|
1174
|
-
|
|
1175
|
-
processed_items
|
|
1176
|
-
end
|
|
1177
|
-
end
|
|
1178
|
-
|
|
1179
|
-
response = text_content(text: "Successfully processed #{result.length} items: #{result.join(", ")}")
|
|
1180
|
-
|
|
1181
|
-
respond_with content: response
|
|
407
|
+
RSpec.describe WeatherTool, type: :mcp do
|
|
408
|
+
it "returns weather data" do
|
|
409
|
+
response = call_mcp_tool(WeatherTool, { location: "New York" })
|
|
410
|
+
expect(response).to be_valid_mcp_tool_response
|
|
411
|
+
expect(response).to have_text_content(/temperature/)
|
|
1182
412
|
end
|
|
1183
413
|
end
|
|
1184
414
|
```
|
|
1185
415
|
|
|
1186
|
-
|
|
416
|
+
Key features:
|
|
417
|
+
- Helper methods: `call_mcp_tool`, `call_mcp_prompt`, `call_mcp_resource`
|
|
418
|
+
- Class definition matchers: `be_valid_mcp_class(:tool)`
|
|
419
|
+
- Response matchers for text, image, audio, and structured content
|
|
420
|
+
- Prompt and resource-specific matchers
|
|
1187
421
|
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
The `ModelContextProtocol::Server::Completion` base class allows subclasses to define a completion that the MCP client can use to obtain hints or suggestions for arguments to prompts and resources.
|
|
1191
|
-
|
|
1192
|
-
Implement the `call` method to build your completion logic using the provided argument name and value. Completions are simpler than other server features - they don't use a `define` block and only provide filtered suggestion lists.
|
|
1193
|
-
|
|
1194
|
-
### Completion Methods
|
|
1195
|
-
|
|
1196
|
-
Completions only implement the `call` method to provide completion logic.
|
|
1197
|
-
|
|
1198
|
-
| Method | Context | Description |
|
|
1199
|
-
|--------|---------|-------------|
|
|
1200
|
-
| `call` | Instance method | Main method to implement completion logic and build response |
|
|
1201
|
-
| `respond_with` | Within `call` | Return properly formatted completion response (e.g., `respond_with values:`) |
|
|
1202
|
-
|
|
1203
|
-
### Available Instance Variables
|
|
1204
|
-
|
|
1205
|
-
Completions receive the argument name and current value being completed.
|
|
1206
|
-
|
|
1207
|
-
| Variable | Context | Description |
|
|
1208
|
-
|----------|---------|-------------|
|
|
1209
|
-
| `argument_name` | Within `call` | String name of the argument being completed |
|
|
1210
|
-
| `argument_value` | Within `call` | Current partial value being typed by the user |
|
|
1211
|
-
|
|
1212
|
-
### Examples
|
|
1213
|
-
|
|
1214
|
-
This is an example completion that returns an array of values in the response:
|
|
1215
|
-
|
|
1216
|
-
```ruby
|
|
1217
|
-
class TestCompletion < ModelContextProtocol::Server::Completion
|
|
1218
|
-
def call
|
|
1219
|
-
hints = {
|
|
1220
|
-
"message" => ["hello", "world", "foo", "bar"]
|
|
1221
|
-
}
|
|
1222
|
-
values = hints[argument_name].grep(/#{argument_value}/)
|
|
1223
|
-
|
|
1224
|
-
respond_with values:
|
|
1225
|
-
end
|
|
1226
|
-
end
|
|
1227
|
-
```
|
|
1228
|
-
|
|
1229
|
-
---
|
|
422
|
+
For complete matcher documentation and examples, see the [Testing with RSpec](https://github.com/dickdavis/model-context-protocol-rb/wiki/Testing-with-RSpec) wiki page.
|
|
1230
423
|
|
|
1231
424
|
## Development
|
|
1232
425
|
|
|
@@ -1242,6 +435,9 @@ bundle exec rake mcp:generate_stdio_server
|
|
|
1242
435
|
|
|
1243
436
|
# generates bin/dev-http for streamable HTTP transport
|
|
1244
437
|
bundle exec rake mcp:generate_streamable_http_server
|
|
438
|
+
|
|
439
|
+
# generates bin/dev-http-puma for streamable HTTP transport with Puma web server
|
|
440
|
+
bundle exec rake mcp:generate_puma_server
|
|
1245
441
|
```
|
|
1246
442
|
|
|
1247
443
|
If you need to test with HTTPS (e.g., for clients that require SSL), generate self-signed certificates:
|