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.
Files changed (27) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -1
  3. data/README.md +337 -158
  4. data/lib/model_context_protocol/server/cancellable.rb +54 -0
  5. data/lib/model_context_protocol/server/configuration.rb +4 -9
  6. data/lib/model_context_protocol/server/progressable.rb +72 -0
  7. data/lib/model_context_protocol/server/prompt.rb +3 -1
  8. data/lib/model_context_protocol/server/redis_client_proxy.rb +134 -0
  9. data/lib/model_context_protocol/server/redis_config.rb +108 -0
  10. data/lib/model_context_protocol/server/redis_pool_manager.rb +110 -0
  11. data/lib/model_context_protocol/server/resource.rb +3 -0
  12. data/lib/model_context_protocol/server/router.rb +36 -3
  13. data/lib/model_context_protocol/server/stdio_transport/request_store.rb +102 -0
  14. data/lib/model_context_protocol/server/stdio_transport.rb +31 -6
  15. data/lib/model_context_protocol/server/streamable_http_transport/event_counter.rb +35 -0
  16. data/lib/model_context_protocol/server/streamable_http_transport/message_poller.rb +101 -0
  17. data/lib/model_context_protocol/server/streamable_http_transport/notification_queue.rb +80 -0
  18. data/lib/model_context_protocol/server/streamable_http_transport/request_store.rb +224 -0
  19. data/lib/model_context_protocol/server/streamable_http_transport/session_message_queue.rb +120 -0
  20. data/lib/model_context_protocol/server/{session_store.rb → streamable_http_transport/session_store.rb} +30 -16
  21. data/lib/model_context_protocol/server/streamable_http_transport/stream_registry.rb +119 -0
  22. data/lib/model_context_protocol/server/streamable_http_transport.rb +181 -80
  23. data/lib/model_context_protocol/server/tool.rb +4 -0
  24. data/lib/model_context_protocol/server.rb +9 -3
  25. data/lib/model_context_protocol/version.rb +1 -1
  26. data/tasks/templates/dev-http.erb +58 -14
  27. 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. You are welcome to contribute.
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
- - [Usage](#usage)
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
- | | [Cancellation](https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/cancellation) |
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
- | | [Progress](https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/progress) |
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
- ## Usage
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
- Include `model_context_protocol` in your project.
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
- require 'model_context_protocol'
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
- ### Building an MCP Server
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
- # redis_client: Redis.new(url: ENV['REDIS_URL']),
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
- #### Server Configuration Options
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
- #### Pagination Configuration Options
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
- #### Transport Configuration Options
302
+ ### Transport Configuration Options
176
303
 
177
304
  The transport configuration supports two types: `:stdio` (default) and `:streamable_http`.
178
305
 
179
- ##### STDIO Transport
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
- ##### Streamable HTTP Transport
185
- When using `:streamable_http`, the following options are available:
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
- #### Registry Configuration Options
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
- #### Integration with Rails
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
- First, set the routes:
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
- #### Prompt Definition
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
- #### Argument Definition
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
- #### Prompt Methods
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
- #### Message History DSL
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
- #### Content Blocks
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
- #### Available Instance Variables
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
- #### Examples
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
- ### Resources
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
- #### Resource Definition
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
- #### Annotation Definition
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
- #### Resource Methods
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
- #### Available Instance Variables
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
- #### Examples
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
- ### Resource Templates
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
- #### Resource Template Definition
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
- #### URI Template Configuration
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
- #### Resource Template Methods
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
- #### Examples
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
- ### Tools
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
- #### Tool Definition
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
- #### Tool Methods
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
- #### Content Blocks
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
- #### Response Types
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
- #### Available Instance Variables
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
- #### Examples
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
- ### Completions
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
- #### Completion Methods
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
- #### Available Instance Variables
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
- #### Examples
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
- ## Installation
1194
+ ---
1018
1195
 
1019
- Add this line to your application's Gemfile:
1196
+ ## Development
1020
1197
 
1021
- ```ruby
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
- And then execute:
1200
+ ### Generate Development Servers
1201
+
1202
+ Generate executables that you can use for testing:
1026
1203
 
1027
1204
  ```bash
1028
- bundle
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
- Or install it yourself as:
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
- gem install model-context-protocol-rb
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
- ## Development
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
- # generates bin/dev for STDIO transport
1045
- bundle exec rake mcp:generate_stdio_server
1223
+ # Run HTTP server (default)
1224
+ bin/dev-http
1046
1225
 
1047
- # generates bin/dev-http for streamable HTTP transport
1048
- bundle exec rake mcp:generate_streamable_http_server
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.