model-context-protocol-rb 0.4.0 → 0.5.1
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 +14 -1
- data/README.md +337 -158
- data/lib/model_context_protocol/server/cancellable.rb +54 -0
- data/lib/model_context_protocol/server/configuration.rb +4 -9
- data/lib/model_context_protocol/server/progressable.rb +72 -0
- data/lib/model_context_protocol/server/prompt.rb +3 -1
- data/lib/model_context_protocol/server/redis_client_proxy.rb +134 -0
- data/lib/model_context_protocol/server/redis_config.rb +108 -0
- data/lib/model_context_protocol/server/redis_pool_manager.rb +110 -0
- data/lib/model_context_protocol/server/resource.rb +3 -0
- data/lib/model_context_protocol/server/router.rb +36 -3
- data/lib/model_context_protocol/server/stdio_transport/request_store.rb +102 -0
- data/lib/model_context_protocol/server/stdio_transport.rb +31 -6
- data/lib/model_context_protocol/server/streamable_http_transport/event_counter.rb +35 -0
- data/lib/model_context_protocol/server/streamable_http_transport/message_poller.rb +101 -0
- data/lib/model_context_protocol/server/streamable_http_transport/notification_queue.rb +80 -0
- data/lib/model_context_protocol/server/streamable_http_transport/request_store.rb +224 -0
- data/lib/model_context_protocol/server/streamable_http_transport/session_message_queue.rb +120 -0
- data/lib/model_context_protocol/server/{session_store.rb → streamable_http_transport/session_store.rb} +30 -16
- data/lib/model_context_protocol/server/streamable_http_transport/stream_registry.rb +119 -0
- data/lib/model_context_protocol/server/streamable_http_transport.rb +181 -80
- data/lib/model_context_protocol/server/tool.rb +4 -0
- data/lib/model_context_protocol/server.rb +9 -3
- data/lib/model_context_protocol/version.rb +1 -1
- data/tasks/templates/dev-http.erb +58 -14
- metadata +57 -3
data/README.md
CHANGED
@@ -1,28 +1,26 @@
|
|
1
1
|
# model-context-protocol-rb
|
2
2
|
|
3
|
-
An implementation of the [Model Context Protocol (MCP)](https://spec.modelcontextprotocol.io/specification/2025-06-18/) in Ruby.
|
3
|
+
An implementation of the [Model Context Protocol (MCP)](https://spec.modelcontextprotocol.io/specification/2025-06-18/) in Ruby.
|
4
|
+
|
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.
|
4
6
|
|
5
7
|
## Table of Contents
|
6
8
|
|
7
9
|
- [Feature Support (Server)](#feature-support-server)
|
8
|
-
- [
|
9
|
-
- [Building an MCP Server](#building-an-mcp-server)
|
10
|
-
- [Server Configuration Options](#server-configuration-options)
|
11
|
-
- [Pagination Configuration Options](#pagination-configuration-options)
|
12
|
-
- [Transport Configuration Options](#transport-configuration-options)
|
13
|
-
- [STDIO Transport](#stdio-transport)
|
14
|
-
- [Streamable HTTP Transport](#streamable-http-transport)
|
15
|
-
- [Registry Configuration Options](#registry-configuration-options)
|
16
|
-
- [Integration with Rails](#integration-with-rails)
|
17
|
-
- [Server features](#server-features)
|
18
|
-
- [Prompts](#prompts)
|
19
|
-
- [Resources](#resources)
|
20
|
-
- [Resource Templates](#resource-templates)
|
21
|
-
- [Tools](#tools)
|
22
|
-
- [Completions](#completions)
|
10
|
+
- [Quick Start with Rails](#quick-start-with-rails)
|
23
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
|
+
- [Registry Configuration Options](#registry-configuration-options)
|
18
|
+
- [Prompts](#prompts)
|
19
|
+
- [Resources](#resources)
|
20
|
+
- [Resource Templates](#resource-templates)
|
21
|
+
- [Tools](#tools)
|
22
|
+
- [Completions](#completions)
|
24
23
|
- [Development](#development)
|
25
|
-
- [Releases](#releases)
|
26
24
|
- [Contributing](#contributing)
|
27
25
|
- [License](#license)
|
28
26
|
|
@@ -44,19 +42,148 @@ An implementation of the [Model Context Protocol (MCP)](https://spec.modelcontex
|
|
44
42
|
| ❌ | [List Changed Notification (Resources)](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#list-changed-notification) |
|
45
43
|
| ❌ | [Subscriptions (Resources)](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#subscriptions) |
|
46
44
|
| ❌ | [List Changed Notification (Tools)](https://modelcontextprotocol.io/specification/2025-06-18/server/tools#list-changed-notification) |
|
47
|
-
|
|
45
|
+
| ✅ | [Cancellation](https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/cancellation) |
|
48
46
|
| ✅ | [Ping](https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/ping) |
|
49
|
-
|
|
47
|
+
| ✅ | [Progress](https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/progress) |
|
48
|
+
|
49
|
+
## Quick Start with Rails
|
50
|
+
|
51
|
+
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.
|
52
|
+
|
53
|
+
Here's an example of how you can easily integrate with Rails.
|
54
|
+
|
55
|
+
First, configure Redis in an initializer:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
# config/initializers/model_context_protocol.rb
|
59
|
+
require "model_context_protocol"
|
60
|
+
|
61
|
+
ModelContextProtocol::Server.configure_redis do |config|
|
62
|
+
config.redis_url = ENV.fetch("REDIS_URL", "redis://localhost:6379/0")
|
63
|
+
config.pool_size = 20
|
64
|
+
config.pool_timeout = 5
|
65
|
+
config.enable_reaper = true
|
66
|
+
config.reaper_interval = 60
|
67
|
+
config.idle_timeout = 300
|
68
|
+
end
|
69
|
+
```
|
70
|
+
|
71
|
+
Then, set the routes:
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
constraints format: :json do
|
75
|
+
get "/mcp", to: "model_context_protocol#handle", as: :mcp_get
|
76
|
+
post "/mcp", to: "model_context_protocol#handle", as: :mcp_post
|
77
|
+
delete "/mcp", to: "model_context_protocol#handle", as: :mcp_delete
|
78
|
+
end
|
79
|
+
```
|
80
|
+
|
81
|
+
Then, implement a controller endpoint to handle the requests.
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
class ModelContextProtocolController < ActionController::API
|
85
|
+
include ActionController::Live
|
86
|
+
|
87
|
+
before_action :authenticate_user
|
88
|
+
|
89
|
+
def handle
|
90
|
+
server = ModelContextProtocol::Server.new do |config|
|
91
|
+
config.name = "MyMCPServer"
|
92
|
+
config.title = "My MCP Server"
|
93
|
+
config.version = "1.0.0"
|
94
|
+
config.logging_enabled = true
|
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
|
+
```
|
50
161
|
|
51
|
-
|
162
|
+
Read more about the [server configuration options](building-an-mcp-server) to better understand how you can customize your MCP server.
|
52
163
|
|
53
|
-
|
164
|
+
From here, you can get started building [prompts](#prompts), [resources](#resources), [resource templates](#resource-templates), and [tools](#tools).
|
165
|
+
|
166
|
+
## Installation
|
167
|
+
|
168
|
+
Add this line to your application's Gemfile:
|
54
169
|
|
55
170
|
```ruby
|
56
|
-
|
171
|
+
gem 'model-context-protocol-rb'
|
172
|
+
```
|
173
|
+
|
174
|
+
And then execute:
|
175
|
+
|
176
|
+
```bash
|
177
|
+
bundle
|
178
|
+
```
|
179
|
+
|
180
|
+
Or install it yourself as:
|
181
|
+
|
182
|
+
```bash
|
183
|
+
gem install model-context-protocol-rb
|
57
184
|
```
|
58
185
|
|
59
|
-
|
186
|
+
## Building an MCP Server
|
60
187
|
|
61
188
|
Build a simple MCP server by registering your prompts, resources, resource templates, and tools. Then, configure and run the server. Messages from the MCP client will be routed to the appropriate custom handler. This SDK provides several classes that should be used to build your handlers.
|
62
189
|
|
@@ -116,7 +243,7 @@ server = ModelContextProtocol::Server.new do |config|
|
|
116
243
|
# Optional: configure streamable HTTP transport if required
|
117
244
|
# config.transport = {
|
118
245
|
# type: :streamable_http,
|
119
|
-
#
|
246
|
+
# env: request.env,
|
120
247
|
# session_ttl: 3600 # Optional: session timeout in seconds (default: 3600)
|
121
248
|
# }
|
122
249
|
|
@@ -144,7 +271,7 @@ end
|
|
144
271
|
server.start
|
145
272
|
```
|
146
273
|
|
147
|
-
|
274
|
+
### Server Configuration Options
|
148
275
|
|
149
276
|
The following table details all available configuration options for the MCP server:
|
150
277
|
|
@@ -160,7 +287,7 @@ The following table details all available configuration options for the MCP serv
|
|
160
287
|
| `transport` | Hash | No | `{ type: :stdio }` | Transport configuration |
|
161
288
|
| `registry` | Registry | Yes | - | Registry containing prompts, resources, and tools |
|
162
289
|
|
163
|
-
|
290
|
+
### Pagination Configuration Options
|
164
291
|
|
165
292
|
When `pagination` is set to a Hash, the following options are available:
|
166
293
|
|
@@ -172,26 +299,55 @@ When `pagination` is set to a Hash, the following options are available:
|
|
172
299
|
|
173
300
|
**Note:** Set `config.pagination = false` to completely disable pagination support.
|
174
301
|
|
175
|
-
|
302
|
+
### Transport Configuration Options
|
176
303
|
|
177
304
|
The transport configuration supports two types: `:stdio` (default) and `:streamable_http`.
|
178
305
|
|
179
|
-
|
306
|
+
#### STDIO Transport
|
307
|
+
|
180
308
|
```ruby
|
181
309
|
config.transport = { type: :stdio } # This is the default, can be omitted
|
182
310
|
```
|
183
311
|
|
184
|
-
|
185
|
-
|
312
|
+
#### Streamable HTTP Transport
|
313
|
+
|
314
|
+
```ruby
|
315
|
+
config.transport = { type: :streamable_http, env: request.env }
|
316
|
+
```
|
317
|
+
|
318
|
+
When using `:streamable_http` transport, the following options are available:
|
186
319
|
|
187
320
|
| Option | Type | Required | Default | Description |
|
188
321
|
|--------|------|----------|---------|-------------|
|
189
322
|
| `type` | Symbol | Yes | `:stdio` | Must be `:streamable_http` for HTTP transport |
|
190
|
-
| `redis_client` | Redis | Yes | - | Redis client instance for session management |
|
191
323
|
| `session_ttl` | Integer | No | `3600` | Session timeout in seconds (1 hour) |
|
192
324
|
| `env` | Hash | No | - | Rack environment hash (for Rails integration) |
|
193
325
|
|
194
|
-
|
326
|
+
### Redis Configuration
|
327
|
+
|
328
|
+
The `:streamable_http` transport requires Redis to be configured globally before use:
|
329
|
+
|
330
|
+
```ruby
|
331
|
+
ModelContextProtocol::Server.configure_redis do |config|
|
332
|
+
config.redis_url = ENV.fetch('REDIS_URL')
|
333
|
+
config.pool_size = 20
|
334
|
+
config.pool_timeout = 5
|
335
|
+
config.enable_reaper = true
|
336
|
+
config.reaper_interval = 60
|
337
|
+
config.idle_timeout = 300
|
338
|
+
end
|
339
|
+
```
|
340
|
+
|
341
|
+
| Option | Type | Required | Default | Description |
|
342
|
+
|--------|------|----------|---------|-------------|
|
343
|
+
| `redis_url` | String | Yes | - | Redis connection URL |
|
344
|
+
| `pool_size` | Integer | No | `20` | Connection pool size |
|
345
|
+
| `pool_timeout` | Integer | No | `5` | Pool checkout timeout in seconds |
|
346
|
+
| `enable_reaper` | Boolean | No | `true` | Enable connection reaping |
|
347
|
+
| `reaper_interval` | Integer | No | `60` | Reaper check interval in seconds |
|
348
|
+
| `idle_timeout` | Integer | No | `300` | Idle connection timeout in seconds |
|
349
|
+
|
350
|
+
### Registry Configuration Options
|
195
351
|
|
196
352
|
The registry is configured using `ModelContextProtocol::Server::Registry.new` and supports the following block types:
|
197
353
|
|
@@ -222,83 +378,9 @@ config.registry = ModelContextProtocol::Server::Registry.new do
|
|
222
378
|
end
|
223
379
|
```
|
224
380
|
|
225
|
-
|
226
|
-
|
227
|
-
The streamable HTTP transport works with any valid Rack request. Here's an example of how you can integrate with Rails.
|
381
|
+
---
|
228
382
|
|
229
|
-
|
230
|
-
|
231
|
-
```ruby
|
232
|
-
constraints format: :json do
|
233
|
-
get "/mcp", to: "model_context_protocol#handle", as: :mcp_get
|
234
|
-
post "/mcp", to: "model_context_protocol#handle", as: :mcp_post
|
235
|
-
delete "/mcp", to: "model_context_protocol#handle", as: :mcp_delete
|
236
|
-
end
|
237
|
-
```
|
238
|
-
|
239
|
-
Then, implement a controller endpoint to handle the requests.
|
240
|
-
|
241
|
-
```ruby
|
242
|
-
require 'model_context_protocol'
|
243
|
-
|
244
|
-
class ModelContextProtocolController < ApplicationController
|
245
|
-
before_action :authenticate_user
|
246
|
-
|
247
|
-
def handle
|
248
|
-
server = ModelContextProtocol::Server.new do |config|
|
249
|
-
config.name = "MyMCPServer"
|
250
|
-
config.title = "My MCP Server"
|
251
|
-
config.version = "1.0.0"
|
252
|
-
config.logging_enabled = true
|
253
|
-
config.context = {
|
254
|
-
user_id: current_user.id,
|
255
|
-
request_id: request.id
|
256
|
-
}
|
257
|
-
config.registry = build_registry
|
258
|
-
config.transport = {
|
259
|
-
type: :streamable_http,
|
260
|
-
redis_client: Redis.new(url: ENV['REDIS_URL']), # Prefer initializing a client from a connection pool
|
261
|
-
env: request.env # Rack environment hash
|
262
|
-
}
|
263
|
-
config.instructions = <<~INSTRUCTIONS
|
264
|
-
This server provides prompts, tools, and resources for interacting with my app.
|
265
|
-
|
266
|
-
Key capabilities:
|
267
|
-
- Does this one thing
|
268
|
-
- Does this other thing
|
269
|
-
- Oh, yeah, and it does that one thing, too
|
270
|
-
|
271
|
-
Use this server when you need to do stuff.
|
272
|
-
INSTRUCTIONS
|
273
|
-
end
|
274
|
-
|
275
|
-
result = server.start
|
276
|
-
|
277
|
-
# For SSE responses
|
278
|
-
if result[:stream]
|
279
|
-
response.headers.merge!(result[:headers] || {})
|
280
|
-
response.content_type = result[:headers]["Content-Type"] || "text/event-stream"
|
281
|
-
# Handle streaming with result[:stream_proc]
|
282
|
-
else
|
283
|
-
# For regular JSON responses
|
284
|
-
render json: result[:json], status: result[:status], headers: result[:headers]
|
285
|
-
end
|
286
|
-
end
|
287
|
-
|
288
|
-
private
|
289
|
-
|
290
|
-
def build_registry
|
291
|
-
ModelContextProtocol::Server::Registry.new do
|
292
|
-
tools do
|
293
|
-
# Implement user authorization logic to dynamically build registry
|
294
|
-
register TestTool if current_user.authorized_for?(TestTool)
|
295
|
-
end
|
296
|
-
end
|
297
|
-
end
|
298
|
-
end
|
299
|
-
```
|
300
|
-
|
301
|
-
### Prompts
|
383
|
+
## Prompts
|
302
384
|
|
303
385
|
The `ModelContextProtocol::Server::Prompt` base class allows subclasses to define a prompt that the MCP client can use.
|
304
386
|
|
@@ -306,7 +388,7 @@ Define the prompt properties and then implement the `call` method to build your
|
|
306
388
|
|
307
389
|
You can also log from within your prompt by calling a valid logger level method on the `logger` and passing a string message.
|
308
390
|
|
309
|
-
|
391
|
+
### Prompt Definition
|
310
392
|
|
311
393
|
Use the `define` block to set [prompt properties](https://spec.modelcontextprotocol.io/specification/2025-06-18/server/prompts/) and configure arguments.
|
312
394
|
|
@@ -317,7 +399,7 @@ Use the `define` block to set [prompt properties](https://spec.modelcontextproto
|
|
317
399
|
| `description` | Short description of what the prompt does |
|
318
400
|
| `argument` | Define an argument block with name, description, required flag, and completion |
|
319
401
|
|
320
|
-
|
402
|
+
### Argument Definition
|
321
403
|
|
322
404
|
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.
|
323
405
|
|
@@ -328,18 +410,20 @@ Define any arguments using `argument` blocks nested within the `define` block. Y
|
|
328
410
|
| `required` | Whether the argument is required (boolean) |
|
329
411
|
| `completion` | Available hints for completions (array or completion class) |
|
330
412
|
|
331
|
-
|
413
|
+
### Prompt Methods
|
332
414
|
|
333
|
-
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.
|
415
|
+
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.
|
334
416
|
|
335
417
|
| Method | Context | Description |
|
336
418
|
|--------|---------|-------------|
|
337
419
|
| `define` | Class definition | Block for defining prompt metadata and arguments |
|
338
420
|
| `call` | Instance method | Main method to implement prompt logic and build response |
|
421
|
+
| `cancellable` | Within `call` | Wrap long-running operations to allow client cancellation (e.g., `cancellable { slow_operation }`) |
|
422
|
+
| `progressable` | Within `call` | Wrap long-running operations to send clients progress notifications (e.g., `progressable { slow_operation }`) |
|
339
423
|
| `message_history` | Within `call` | DSL method to build an array of user and assistant messages |
|
340
424
|
| `respond_with` | Within `call` | Return properly formatted response data (e.g., `respond_with messages:`) |
|
341
425
|
|
342
|
-
|
426
|
+
### Message History DSL
|
343
427
|
|
344
428
|
Build a message history using the an intuitive DSL, creating an ordered history of user and assistant messages with flexible content blocks that can include text, image, audio, embedded resources, and resource links.
|
345
429
|
|
@@ -348,7 +432,7 @@ Build a message history using the an intuitive DSL, creating an ordered history
|
|
348
432
|
| `user_message` | Within `message_history` | Create a message with user role |
|
349
433
|
| `assistant_message` | Within `message_history` | Create a message with assistant role |
|
350
434
|
|
351
|
-
|
435
|
+
### Content Blocks
|
352
436
|
|
353
437
|
Use content blocks to properly format the content included in messages.
|
354
438
|
|
@@ -360,7 +444,7 @@ Use content blocks to properly format the content included in messages.
|
|
360
444
|
| `embedded_resource_content` | Within message blocks | Create embedded resource content block (requires `resource:`) |
|
361
445
|
| `resource_link` | Within message blocks | Create resource link content block (requires `name:` and `uri:`) |
|
362
446
|
|
363
|
-
|
447
|
+
### Available Instance Variables
|
364
448
|
|
365
449
|
The `arguments` passed from an MCP client are available, as well as the `context` values passed in at server initialization.
|
366
450
|
|
@@ -370,7 +454,7 @@ The `arguments` passed from an MCP client are available, as well as the `context
|
|
370
454
|
| `context` | Within `call` | Hash containing server configuration context values |
|
371
455
|
| `logger` | Within `call` | Logger instance for logging (e.g., `logger.info("message")`) |
|
372
456
|
|
373
|
-
|
457
|
+
### Examples
|
374
458
|
|
375
459
|
This is an example prompt that returns a properly formatted response:
|
376
460
|
|
@@ -449,13 +533,15 @@ class TestPrompt < ModelContextProtocol::Server::Prompt
|
|
449
533
|
end
|
450
534
|
```
|
451
535
|
|
452
|
-
|
536
|
+
---
|
537
|
+
|
538
|
+
## Resources
|
453
539
|
|
454
540
|
The `ModelContextProtocol::Server::Resource` base class allows subclasses to define a resource that the MCP client can use.
|
455
541
|
|
456
542
|
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.
|
457
543
|
|
458
|
-
|
544
|
+
### Resource Definition
|
459
545
|
|
460
546
|
Use the `define` block to set [resource properties](https://spec.modelcontextprotocol.io/specification/2025-06-18/server/resources/) and configure annotations.
|
461
547
|
|
@@ -468,7 +554,7 @@ Use the `define` block to set [resource properties](https://spec.modelcontextpro
|
|
468
554
|
| `uri` | URI identifier for the resource |
|
469
555
|
| `annotations` | Block for defining resource annotations |
|
470
556
|
|
471
|
-
|
557
|
+
### Annotation Definition
|
472
558
|
|
473
559
|
Define any [resource annotations](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#annotations) using an `annotations` block nested within the `define` block.
|
474
560
|
|
@@ -478,17 +564,19 @@ Define any [resource annotations](https://modelcontextprotocol.io/specification/
|
|
478
564
|
| `priority` | Priority level (numeric value, e.g., `0.9`) |
|
479
565
|
| `last_modified` | Last modified timestamp (ISO 8601 string) |
|
480
566
|
|
481
|
-
|
567
|
+
### Resource Methods
|
482
568
|
|
483
|
-
Define your resource properties and annotations, implement the `call` method to build resource content and `respond_with` to serialize the response.
|
569
|
+
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.
|
484
570
|
|
485
571
|
| Method | Context | Description |
|
486
572
|
|--------|---------|-------------|
|
487
573
|
| `define` | Class definition | Block for defining resource metadata and annotations |
|
488
574
|
| `call` | Instance method | Main method to implement resource logic and build response |
|
575
|
+
| `cancellable` | Within `call` | Wrap long-running operations to allow client cancellation (e.g., `cancellable { slow_operation }`) |
|
576
|
+
| `progressable` | Within `call` | Wrap long-running operations to send clients progress notifications (e.g., `progressable { slow_operation }`) |
|
489
577
|
| `respond_with` | Within `call` | Return properly formatted response data (e.g., `respond_with text:` or `respond_with binary:`) |
|
490
578
|
|
491
|
-
|
579
|
+
### Available Instance Variables
|
492
580
|
|
493
581
|
Resources are stateless and only have access to their configured properties.
|
494
582
|
|
@@ -497,7 +585,7 @@ Resources are stateless and only have access to their configured properties.
|
|
497
585
|
| `mime_type` | Within `call` | The configured MIME type for this resource |
|
498
586
|
| `uri` | Within `call` | The configured URI identifier for this resource |
|
499
587
|
|
500
|
-
|
588
|
+
### Examples
|
501
589
|
|
502
590
|
This is an example resource that returns a text response:
|
503
591
|
|
@@ -559,13 +647,15 @@ class TestBinaryResource < ModelContextProtocol::Server::Resource
|
|
559
647
|
end
|
560
648
|
```
|
561
649
|
|
562
|
-
|
650
|
+
---
|
651
|
+
|
652
|
+
## Resource Templates
|
563
653
|
|
564
654
|
The `ModelContextProtocol::Server::ResourceTemplate` base class allows subclasses to define a resource template that the MCP client can use.
|
565
655
|
|
566
656
|
Define the resource template properties and URI template with optional parameter completions. Resource templates are used to define parameterized resources that clients can instantiate.
|
567
657
|
|
568
|
-
|
658
|
+
### Resource Template Definition
|
569
659
|
|
570
660
|
Use the `define` block to set [resource template properties](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#resource-templates).
|
571
661
|
|
@@ -576,7 +666,7 @@ Use the `define` block to set [resource template properties](https://modelcontex
|
|
576
666
|
| `mime_type` | MIME type of resources created from this template |
|
577
667
|
| `uri_template` | URI template with parameters (e.g., `"file:///{name}"`) |
|
578
668
|
|
579
|
-
|
669
|
+
### URI Template Configuration
|
580
670
|
|
581
671
|
Define the URI template and configure parameter completions within the `uri_template` block.
|
582
672
|
|
@@ -584,7 +674,7 @@ Define the URI template and configure parameter completions within the `uri_temp
|
|
584
674
|
|--------|---------|-------------|
|
585
675
|
| `completion` | Within `uri_template` block | Define completion for a URI parameter (e.g., `completion :name, ["value1", "value2"]`) |
|
586
676
|
|
587
|
-
|
677
|
+
### Resource Template Methods
|
588
678
|
|
589
679
|
Resource templates only use the `define` method to configure their properties - they don't have a `call` method.
|
590
680
|
|
@@ -592,7 +682,7 @@ Resource templates only use the `define` method to configure their properties -
|
|
592
682
|
|--------|---------|-------------|
|
593
683
|
| `define` | Class definition | Block for defining resource template metadata and URI template |
|
594
684
|
|
595
|
-
|
685
|
+
### Examples
|
596
686
|
|
597
687
|
This is an example resource template that provides a completion for a parameter of the URI template:
|
598
688
|
|
@@ -628,13 +718,15 @@ class TestResourceTemplate < ModelContextProtocol::Server::ResourceTemplate
|
|
628
718
|
end
|
629
719
|
```
|
630
720
|
|
631
|
-
|
721
|
+
---
|
722
|
+
|
723
|
+
## Tools
|
632
724
|
|
633
725
|
The `ModelContextProtocol::Server::Tool` base class allows subclasses to define a tool that the MCP client can use.
|
634
726
|
|
635
727
|
Define the tool properties and schemas, then implement the `call` method to build your tool response. Arguments from the MCP client and server context are available, along with logging capabilities.
|
636
728
|
|
637
|
-
|
729
|
+
### Tool Definition
|
638
730
|
|
639
731
|
Use the `define` block to set [tool properties](https://spec.modelcontextprotocol.io/specification/2025-06-18/server/tools/) and configure schemas.
|
640
732
|
|
@@ -646,17 +738,19 @@ Use the `define` block to set [tool properties](https://spec.modelcontextprotoco
|
|
646
738
|
| `input_schema` | JSON schema block for validating tool inputs |
|
647
739
|
| `output_schema` | JSON schema block for validating structured content outputs |
|
648
740
|
|
649
|
-
|
741
|
+
### Tool Methods
|
650
742
|
|
651
|
-
Define your tool properties and schemas, implement the `call` method using content helpers and `respond_with` to serialize responses.
|
743
|
+
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.
|
652
744
|
|
653
745
|
| Method | Context | Description |
|
654
746
|
|--------|---------|-------------|
|
655
747
|
| `define` | Class definition | Block for defining tool metadata and schemas |
|
656
748
|
| `call` | Instance method | Main method to implement tool logic and build response |
|
749
|
+
| `cancellable` | Within `call` | Wrap long-running operations to allow client cancellation (e.g., `cancellable { slow_operation }`) |
|
750
|
+
| `progressable` | Within `call` | Wrap long-running operations to send clients progress notifications (e.g., `progressable { slow_operation }`) |
|
657
751
|
| `respond_with` | Within `call` | Return properly formatted response data with various content types |
|
658
752
|
|
659
|
-
|
753
|
+
### Content Blocks
|
660
754
|
|
661
755
|
Use content blocks to properly format the content included in tool responses.
|
662
756
|
|
@@ -668,7 +762,7 @@ Use content blocks to properly format the content included in tool responses.
|
|
668
762
|
| `embedded_resource_content` | Within `call` | Create embedded resource content block (requires `resource:`) |
|
669
763
|
| `resource_link` | Within `call` | Create resource link content block (requires `name:` and `uri:`) |
|
670
764
|
|
671
|
-
|
765
|
+
### Response Types
|
672
766
|
|
673
767
|
Tools can return different types of responses using `respond_with`.
|
674
768
|
|
@@ -679,7 +773,7 @@ Tools can return different types of responses using `respond_with`.
|
|
679
773
|
| `content:` | `respond_with content: [content_blocks]` | Return array of mixed content blocks |
|
680
774
|
| `error:` | `respond_with error: "message"` | Return tool error response |
|
681
775
|
|
682
|
-
|
776
|
+
### Available Instance Variables
|
683
777
|
|
684
778
|
Arguments from MCP clients and server context are available, along with logging capabilities.
|
685
779
|
|
@@ -689,7 +783,7 @@ Arguments from MCP clients and server context are available, along with logging
|
|
689
783
|
| `context` | Within `call` | Hash containing server configuration context values |
|
690
784
|
| `logger` | Within `call` | Logger instance for logging (e.g., `logger.info("message")`) |
|
691
785
|
|
692
|
-
|
786
|
+
### Examples
|
693
787
|
|
694
788
|
This is an example of a tool that returns structured content validated by an output schema:
|
695
789
|
|
@@ -973,13 +1067,96 @@ class TestToolWithToolErrorResponse < ModelContextProtocol::Server::Tool
|
|
973
1067
|
end
|
974
1068
|
```
|
975
1069
|
|
976
|
-
|
1070
|
+
This is an example of a tool that allows a client to cancel a long-running operation:
|
1071
|
+
|
1072
|
+
```ruby
|
1073
|
+
class TestToolWithCancellableSleep < ModelContextProtocol::Server::Tool
|
1074
|
+
define do
|
1075
|
+
name "cancellable_sleep"
|
1076
|
+
title "Cancellable Sleep Tool"
|
1077
|
+
description "Sleep for 3 seconds with cancellation support"
|
1078
|
+
input_schema do
|
1079
|
+
{
|
1080
|
+
type: "object",
|
1081
|
+
properties: {},
|
1082
|
+
additionalProperties: false
|
1083
|
+
}
|
1084
|
+
end
|
1085
|
+
end
|
1086
|
+
|
1087
|
+
def call
|
1088
|
+
logger.info("Starting 3 second sleep operation")
|
1089
|
+
|
1090
|
+
result = cancellable do
|
1091
|
+
sleep 3
|
1092
|
+
"Sleep completed successfully"
|
1093
|
+
end
|
1094
|
+
|
1095
|
+
respond_with content: text_content(text: result)
|
1096
|
+
end
|
1097
|
+
end
|
1098
|
+
```
|
1099
|
+
|
1100
|
+
This is an example of a tool that automatically sends progress notifications to the client and allows the client to cancel the operation:
|
1101
|
+
|
1102
|
+
```ruby
|
1103
|
+
class TestToolWithProgressableAndCancellable < ModelContextProtocol::Server::Tool
|
1104
|
+
define do
|
1105
|
+
name "test_tool_with_progressable_and_cancellable"
|
1106
|
+
description "A test tool that demonstrates combined progressable and cancellable functionality"
|
1107
|
+
|
1108
|
+
input_schema do
|
1109
|
+
{
|
1110
|
+
type: "object",
|
1111
|
+
properties: {
|
1112
|
+
max_duration: {
|
1113
|
+
type: "number",
|
1114
|
+
description: "Expected maximum duration in seconds"
|
1115
|
+
},
|
1116
|
+
work_steps: {
|
1117
|
+
type: "number",
|
1118
|
+
description: "Number of work steps to perform"
|
1119
|
+
}
|
1120
|
+
},
|
1121
|
+
required: ["max_duration"]
|
1122
|
+
}
|
1123
|
+
end
|
1124
|
+
end
|
1125
|
+
|
1126
|
+
def call
|
1127
|
+
max_duration = arguments[:max_duration] || 10
|
1128
|
+
work_steps = arguments[:work_steps] || 10
|
1129
|
+
logger.info("Starting progressable call with max_duration=#{max_duration}, work_steps=#{work_steps}")
|
1130
|
+
|
1131
|
+
result = progressable(max_duration:, message: "Processing #{work_steps} items") do
|
1132
|
+
cancellable do
|
1133
|
+
processed_items = []
|
1134
|
+
|
1135
|
+
work_steps.times do |i|
|
1136
|
+
sleep(max_duration / work_steps.to_f)
|
1137
|
+
processed_items << "item_#{i + 1}"
|
1138
|
+
end
|
1139
|
+
|
1140
|
+
processed_items
|
1141
|
+
end
|
1142
|
+
end
|
1143
|
+
|
1144
|
+
response = text_content(text: "Successfully processed #{result.length} items: #{result.join(", ")}")
|
1145
|
+
|
1146
|
+
respond_with content: response
|
1147
|
+
end
|
1148
|
+
end
|
1149
|
+
```
|
1150
|
+
|
1151
|
+
---
|
1152
|
+
|
1153
|
+
## Completions
|
977
1154
|
|
978
1155
|
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.
|
979
1156
|
|
980
1157
|
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.
|
981
1158
|
|
982
|
-
|
1159
|
+
### Completion Methods
|
983
1160
|
|
984
1161
|
Completions only implement the `call` method to provide completion logic.
|
985
1162
|
|
@@ -988,7 +1165,7 @@ Completions only implement the `call` method to provide completion logic.
|
|
988
1165
|
| `call` | Instance method | Main method to implement completion logic and build response |
|
989
1166
|
| `respond_with` | Within `call` | Return properly formatted completion response (e.g., `respond_with values:`) |
|
990
1167
|
|
991
|
-
|
1168
|
+
### Available Instance Variables
|
992
1169
|
|
993
1170
|
Completions receive the argument name and current value being completed.
|
994
1171
|
|
@@ -997,7 +1174,7 @@ Completions receive the argument name and current value being completed.
|
|
997
1174
|
| `argument_name` | Within `call` | String name of the argument being completed |
|
998
1175
|
| `argument_value` | Within `call` | Current partial value being typed by the user |
|
999
1176
|
|
1000
|
-
|
1177
|
+
### Examples
|
1001
1178
|
|
1002
1179
|
This is an example completion that returns an array of values in the response:
|
1003
1180
|
|
@@ -1014,38 +1191,40 @@ class TestCompletion < ModelContextProtocol::Server::Completion
|
|
1014
1191
|
end
|
1015
1192
|
```
|
1016
1193
|
|
1017
|
-
|
1194
|
+
---
|
1018
1195
|
|
1019
|
-
|
1196
|
+
## Development
|
1020
1197
|
|
1021
|
-
|
1022
|
-
gem 'model-context-protocol-rb'
|
1023
|
-
```
|
1198
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rspec` to run the tests.
|
1024
1199
|
|
1025
|
-
|
1200
|
+
### Generate Development Servers
|
1201
|
+
|
1202
|
+
Generate executables that you can use for testing:
|
1026
1203
|
|
1027
1204
|
```bash
|
1028
|
-
|
1205
|
+
# generates bin/dev for STDIO transport
|
1206
|
+
bundle exec rake mcp:generate_stdio_server
|
1207
|
+
|
1208
|
+
# generates bin/dev-http for streamable HTTP transport
|
1209
|
+
bundle exec rake mcp:generate_streamable_http_server
|
1029
1210
|
```
|
1030
1211
|
|
1031
|
-
|
1212
|
+
If you need to test with HTTPS (e.g., for clients that require SSL), generate self-signed certificates:
|
1032
1213
|
|
1033
1214
|
```bash
|
1034
|
-
|
1215
|
+
# Create SSL directory and generate certificates
|
1216
|
+
mkdir -p tmp/ssl
|
1217
|
+
openssl req -x509 -newkey rsa:4096 -keyout tmp/ssl/server.key -out tmp/ssl/server.crt -days 365 -nodes -subj "/C=US/ST=Dev/L=Dev/O=Dev/CN=localhost"
|
1035
1218
|
```
|
1036
1219
|
|
1037
|
-
|
1038
|
-
|
1039
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rspec` to run the tests.
|
1040
|
-
|
1041
|
-
Generate executables that you can use for testing:
|
1220
|
+
The HTTP server supports both HTTP and HTTPS:
|
1042
1221
|
|
1043
1222
|
```bash
|
1044
|
-
#
|
1045
|
-
|
1223
|
+
# Run HTTP server (default)
|
1224
|
+
bin/dev-http
|
1046
1225
|
|
1047
|
-
#
|
1048
|
-
|
1226
|
+
# Run HTTPS server (requires SSL certificates in tmp/ssl/)
|
1227
|
+
SSL=true bin/dev-http
|
1049
1228
|
```
|
1050
1229
|
|
1051
1230
|
You can also run `bin/console` for an interactive prompt that will allow you to experiment. Execute command `rp` to reload the project.
|