model-context-protocol-rb 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5f97580e7f9c5723d25472b545c037bad650d82434865324c6d1dd450ac4031e
4
- data.tar.gz: 1b73ad6036c7ded852210dc338190675e419c6f6354e027d2b7073a5e655c665
3
+ metadata.gz: 8fd0681c65b47196375ec7f4934cadf226ed01b1b289caf296348698808ef5cb
4
+ data.tar.gz: 4ce234855d56b724b6f69b97851ff1ee4db65370b7361ea0a65c43a929c448b7
5
5
  SHA512:
6
- metadata.gz: 3075cfc900a60fd1cb83b973c23f6f517373f6132ab043ea64079653bbc0ecc5c5aeb8a077e2c685396f9921d80ad341f9fa271fd343fb9b9f29ce93b6abda4b
7
- data.tar.gz: c72619fea381f8968d7dd33e60c306449973bbeda9f5a8ffd6b8d5baf95d26df8278a2106b82daeef61982a950b74b5f168a8afb680baa6e44f10d26626cac69
6
+ metadata.gz: b3bafa3fe92aa05ff380ad5fc311c0143d5e1bb6c3a91e50893115eb01ad2ea8b2d93dde89240815b50629fcb3b3b3467585766ac42d2c7087cd0be55b431455
7
+ data.tar.gz: 9d1c4f1c5f93352bf9392f9aeaf63253534348787aecb0866abe160dbf7cebc302bfec751955b19d0a06d9d60675c450960d401af2538aa9b100fe076bc7fd94
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.5.1] - 2025-09-23
4
+
5
+ - (Fix) Ensure streams are properly closed when clients disconnect.
6
+
3
7
  ## [0.5.0] - 2025-09-22
4
8
 
5
9
  - Make streamable HTTP transport thread-safe by using Redis to manage state.
@@ -75,6 +79,7 @@
75
79
  - Initial release
76
80
 
77
81
  [Unreleased]: https://github.com/dickdavis/model-context-protocol-rb/compare/v0.5.0...HEAD
82
+ [0.5.1]: https://github.com/dickdavis/model-context-protocol-rb/compare/v0.5.0...v0.5.1
78
83
  [0.5.0]: https://github.com/dickdavis/model-context-protocol-rb/compare/v0.4.0...v0.5.0
79
84
  [0.4.0]: https://github.com/dickdavis/model-context-protocol-rb/compare/v0.3.4...v0.4.0
80
85
  [0.3.4]: https://github.com/dickdavis/model-context-protocol-rb/compare/v0.3.3...v0.3.4
data/README.md CHANGED
@@ -7,24 +7,20 @@ Provides simple abstractions that allow you to serve prompts, resources, resourc
7
7
  ## Table of Contents
8
8
 
9
9
  - [Feature Support (Server)](#feature-support-server)
10
- - [Usage](#usage)
11
- - [Building an MCP Server](#building-an-mcp-server)
12
- - [Server Configuration Options](#server-configuration-options)
13
- - [Pagination Configuration Options](#pagination-configuration-options)
14
- - [Transport Configuration Options](#transport-configuration-options)
15
- - [STDIO Transport](#stdio-transport)
16
- - [Streamable HTTP Transport](#streamable-http-transport)
17
- - [Registry Configuration Options](#registry-configuration-options)
18
- - [Integration with Rails](#integration-with-rails)
19
- - [Server features](#server-features)
20
- - [Prompts](#prompts)
21
- - [Resources](#resources)
22
- - [Resource Templates](#resource-templates)
23
- - [Tools](#tools)
24
- - [Completions](#completions)
10
+ - [Quick Start with Rails](#quick-start-with-rails)
25
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)
26
23
  - [Development](#development)
27
- - [Releases](#releases)
28
24
  - [Contributing](#contributing)
29
25
  - [License](#license)
30
26
 
@@ -50,15 +46,144 @@ Provides simple abstractions that allow you to serve prompts, resources, resourc
50
46
  | ✅ | [Ping](https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/ping) |
51
47
  | ✅ | [Progress](https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/progress) |
52
48
 
53
- ## Usage
49
+ ## Quick Start with Rails
54
50
 
55
- Include `model_context_protocol` in your project.
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
56
 
57
57
  ```ruby
58
- require 'model_context_protocol'
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
59
69
  ```
60
70
 
61
- ### Building an MCP Server
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
+ ```
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
+ ## Installation
167
+
168
+ Add this line to your application's Gemfile:
169
+
170
+ ```ruby
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
184
+ ```
185
+
186
+ ## Building an MCP Server
62
187
 
63
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.
64
189
 
@@ -146,7 +271,7 @@ end
146
271
  server.start
147
272
  ```
148
273
 
149
- #### Server Configuration Options
274
+ ### Server Configuration Options
150
275
 
151
276
  The following table details all available configuration options for the MCP server:
152
277
 
@@ -162,7 +287,7 @@ The following table details all available configuration options for the MCP serv
162
287
  | `transport` | Hash | No | `{ type: :stdio }` | Transport configuration |
163
288
  | `registry` | Registry | Yes | - | Registry containing prompts, resources, and tools |
164
289
 
165
- #### Pagination Configuration Options
290
+ ### Pagination Configuration Options
166
291
 
167
292
  When `pagination` is set to a Hash, the following options are available:
168
293
 
@@ -174,16 +299,32 @@ When `pagination` is set to a Hash, the following options are available:
174
299
 
175
300
  **Note:** Set `config.pagination = false` to completely disable pagination support.
176
301
 
177
- #### Transport Configuration Options
302
+ ### Transport Configuration Options
178
303
 
179
304
  The transport configuration supports two types: `:stdio` (default) and `:streamable_http`.
180
305
 
181
- ##### STDIO Transport
306
+ #### STDIO Transport
307
+
182
308
  ```ruby
183
309
  config.transport = { type: :stdio } # This is the default, can be omitted
184
310
  ```
185
311
 
186
- ##### Streamable HTTP Transport
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:
319
+
320
+ | Option | Type | Required | Default | Description |
321
+ |--------|------|----------|---------|-------------|
322
+ | `type` | Symbol | Yes | `:stdio` | Must be `:streamable_http` for HTTP transport |
323
+ | `session_ttl` | Integer | No | `3600` | Session timeout in seconds (1 hour) |
324
+ | `env` | Hash | No | - | Rack environment hash (for Rails integration) |
325
+
326
+ ### Redis Configuration
327
+
187
328
  The `:streamable_http` transport requires Redis to be configured globally before use:
188
329
 
189
330
  ```ruby
@@ -206,15 +347,7 @@ end
206
347
  | `reaper_interval` | Integer | No | `60` | Reaper check interval in seconds |
207
348
  | `idle_timeout` | Integer | No | `300` | Idle connection timeout in seconds |
208
349
 
209
- When using `:streamable_http` transport, the following options are available:
210
-
211
- | Option | Type | Required | Default | Description |
212
- |--------|------|----------|---------|-------------|
213
- | `type` | Symbol | Yes | `:stdio` | Must be `:streamable_http` for HTTP transport |
214
- | `session_ttl` | Integer | No | `3600` | Session timeout in seconds (1 hour) |
215
- | `env` | Hash | No | - | Rack environment hash (for Rails integration) |
216
-
217
- #### Registry Configuration Options
350
+ ### Registry Configuration Options
218
351
 
219
352
  The registry is configured using `ModelContextProtocol::Server::Registry.new` and supports the following block types:
220
353
 
@@ -245,96 +378,9 @@ config.registry = ModelContextProtocol::Server::Registry.new do
245
378
  end
246
379
  ```
247
380
 
248
- #### Integration with Rails
249
-
250
- The streamable HTTP transport works with any valid Rack request. Here's an example of how you can integrate with Rails.
381
+ ---
251
382
 
252
- First, configure Redis in an initializer:
253
-
254
- ```ruby
255
- # config/initializers/model_context_protocol.rb
256
- ModelContextProtocol::Server.configure_redis do |config|
257
- config.redis_url = ENV.fetch('REDIS_URL')
258
- config.pool_size = 20
259
- config.pool_timeout = 5
260
- config.enable_reaper = true
261
- config.reaper_interval = 60
262
- config.idle_timeout = 300
263
- end
264
- ```
265
-
266
- Then, set the routes:
267
-
268
- ```ruby
269
- constraints format: :json do
270
- get "/mcp", to: "model_context_protocol#handle", as: :mcp_get
271
- post "/mcp", to: "model_context_protocol#handle", as: :mcp_post
272
- delete "/mcp", to: "model_context_protocol#handle", as: :mcp_delete
273
- end
274
- ```
275
-
276
- Then, implement a controller endpoint to handle the requests.
277
-
278
- ```ruby
279
- require 'model_context_protocol'
280
-
281
- class ModelContextProtocolController < ApplicationController
282
- before_action :authenticate_user
283
-
284
- def handle
285
- server = ModelContextProtocol::Server.new do |config|
286
- config.name = "MyMCPServer"
287
- config.title = "My MCP Server"
288
- config.version = "1.0.0"
289
- config.logging_enabled = true
290
- config.context = {
291
- user_id: current_user.id,
292
- request_id: request.id
293
- }
294
- config.registry = build_registry
295
- config.transport = {
296
- type: :streamable_http,
297
- env: request.env
298
- }
299
- config.instructions = <<~INSTRUCTIONS
300
- This server provides prompts, tools, and resources for interacting with my app.
301
-
302
- Key capabilities:
303
- - Does this one thing
304
- - Does this other thing
305
- - Oh, yeah, and it does that one thing, too
306
-
307
- Use this server when you need to do stuff.
308
- INSTRUCTIONS
309
- end
310
-
311
- result = server.start
312
-
313
- # For SSE responses
314
- if result[:stream]
315
- response.headers.merge!(result[:headers] || {})
316
- response.content_type = result[:headers]["Content-Type"] || "text/event-stream"
317
- # Handle streaming with result[:stream_proc]
318
- else
319
- # For regular JSON responses
320
- render json: result[:json], status: result[:status], headers: result[:headers]
321
- end
322
- end
323
-
324
- private
325
-
326
- def build_registry
327
- ModelContextProtocol::Server::Registry.new do
328
- tools do
329
- # Implement user authorization logic to dynamically build registry
330
- register TestTool if current_user.authorized_for?(TestTool)
331
- end
332
- end
333
- end
334
- end
335
- ```
336
-
337
- ### Prompts
383
+ ## Prompts
338
384
 
339
385
  The `ModelContextProtocol::Server::Prompt` base class allows subclasses to define a prompt that the MCP client can use.
340
386
 
@@ -342,7 +388,7 @@ Define the prompt properties and then implement the `call` method to build your
342
388
 
343
389
  You can also log from within your prompt by calling a valid logger level method on the `logger` and passing a string message.
344
390
 
345
- #### Prompt Definition
391
+ ### Prompt Definition
346
392
 
347
393
  Use the `define` block to set [prompt properties](https://spec.modelcontextprotocol.io/specification/2025-06-18/server/prompts/) and configure arguments.
348
394
 
@@ -353,7 +399,7 @@ Use the `define` block to set [prompt properties](https://spec.modelcontextproto
353
399
  | `description` | Short description of what the prompt does |
354
400
  | `argument` | Define an argument block with name, description, required flag, and completion |
355
401
 
356
- #### Argument Definition
402
+ ### Argument Definition
357
403
 
358
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.
359
405
 
@@ -364,7 +410,7 @@ Define any arguments using `argument` blocks nested within the `define` block. Y
364
410
  | `required` | Whether the argument is required (boolean) |
365
411
  | `completion` | Available hints for completions (array or completion class) |
366
412
 
367
- #### Prompt Methods
413
+ ### Prompt Methods
368
414
 
369
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.
370
416
 
@@ -377,7 +423,7 @@ Define your prompt properties and arguments, implement the `call` method using t
377
423
  | `message_history` | Within `call` | DSL method to build an array of user and assistant messages |
378
424
  | `respond_with` | Within `call` | Return properly formatted response data (e.g., `respond_with messages:`) |
379
425
 
380
- #### Message History DSL
426
+ ### Message History DSL
381
427
 
382
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.
383
429
 
@@ -386,7 +432,7 @@ Build a message history using the an intuitive DSL, creating an ordered history
386
432
  | `user_message` | Within `message_history` | Create a message with user role |
387
433
  | `assistant_message` | Within `message_history` | Create a message with assistant role |
388
434
 
389
- #### Content Blocks
435
+ ### Content Blocks
390
436
 
391
437
  Use content blocks to properly format the content included in messages.
392
438
 
@@ -398,7 +444,7 @@ Use content blocks to properly format the content included in messages.
398
444
  | `embedded_resource_content` | Within message blocks | Create embedded resource content block (requires `resource:`) |
399
445
  | `resource_link` | Within message blocks | Create resource link content block (requires `name:` and `uri:`) |
400
446
 
401
- #### Available Instance Variables
447
+ ### Available Instance Variables
402
448
 
403
449
  The `arguments` passed from an MCP client are available, as well as the `context` values passed in at server initialization.
404
450
 
@@ -408,7 +454,7 @@ The `arguments` passed from an MCP client are available, as well as the `context
408
454
  | `context` | Within `call` | Hash containing server configuration context values |
409
455
  | `logger` | Within `call` | Logger instance for logging (e.g., `logger.info("message")`) |
410
456
 
411
- #### Examples
457
+ ### Examples
412
458
 
413
459
  This is an example prompt that returns a properly formatted response:
414
460
 
@@ -487,13 +533,15 @@ class TestPrompt < ModelContextProtocol::Server::Prompt
487
533
  end
488
534
  ```
489
535
 
490
- ### Resources
536
+ ---
537
+
538
+ ## Resources
491
539
 
492
540
  The `ModelContextProtocol::Server::Resource` base class allows subclasses to define a resource that the MCP client can use.
493
541
 
494
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.
495
543
 
496
- #### Resource Definition
544
+ ### Resource Definition
497
545
 
498
546
  Use the `define` block to set [resource properties](https://spec.modelcontextprotocol.io/specification/2025-06-18/server/resources/) and configure annotations.
499
547
 
@@ -506,7 +554,7 @@ Use the `define` block to set [resource properties](https://spec.modelcontextpro
506
554
  | `uri` | URI identifier for the resource |
507
555
  | `annotations` | Block for defining resource annotations |
508
556
 
509
- #### Annotation Definition
557
+ ### Annotation Definition
510
558
 
511
559
  Define any [resource annotations](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#annotations) using an `annotations` block nested within the `define` block.
512
560
 
@@ -516,7 +564,7 @@ Define any [resource annotations](https://modelcontextprotocol.io/specification/
516
564
  | `priority` | Priority level (numeric value, e.g., `0.9`) |
517
565
  | `last_modified` | Last modified timestamp (ISO 8601 string) |
518
566
 
519
- #### Resource Methods
567
+ ### Resource Methods
520
568
 
521
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.
522
570
 
@@ -528,7 +576,7 @@ Define your resource properties and annotations, implement the `call` method to
528
576
  | `progressable` | Within `call` | Wrap long-running operations to send clients progress notifications (e.g., `progressable { slow_operation }`) |
529
577
  | `respond_with` | Within `call` | Return properly formatted response data (e.g., `respond_with text:` or `respond_with binary:`) |
530
578
 
531
- #### Available Instance Variables
579
+ ### Available Instance Variables
532
580
 
533
581
  Resources are stateless and only have access to their configured properties.
534
582
 
@@ -537,7 +585,7 @@ Resources are stateless and only have access to their configured properties.
537
585
  | `mime_type` | Within `call` | The configured MIME type for this resource |
538
586
  | `uri` | Within `call` | The configured URI identifier for this resource |
539
587
 
540
- #### Examples
588
+ ### Examples
541
589
 
542
590
  This is an example resource that returns a text response:
543
591
 
@@ -599,13 +647,15 @@ class TestBinaryResource < ModelContextProtocol::Server::Resource
599
647
  end
600
648
  ```
601
649
 
602
- ### Resource Templates
650
+ ---
651
+
652
+ ## Resource Templates
603
653
 
604
654
  The `ModelContextProtocol::Server::ResourceTemplate` base class allows subclasses to define a resource template that the MCP client can use.
605
655
 
606
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.
607
657
 
608
- #### Resource Template Definition
658
+ ### Resource Template Definition
609
659
 
610
660
  Use the `define` block to set [resource template properties](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#resource-templates).
611
661
 
@@ -616,7 +666,7 @@ Use the `define` block to set [resource template properties](https://modelcontex
616
666
  | `mime_type` | MIME type of resources created from this template |
617
667
  | `uri_template` | URI template with parameters (e.g., `"file:///{name}"`) |
618
668
 
619
- #### URI Template Configuration
669
+ ### URI Template Configuration
620
670
 
621
671
  Define the URI template and configure parameter completions within the `uri_template` block.
622
672
 
@@ -624,7 +674,7 @@ Define the URI template and configure parameter completions within the `uri_temp
624
674
  |--------|---------|-------------|
625
675
  | `completion` | Within `uri_template` block | Define completion for a URI parameter (e.g., `completion :name, ["value1", "value2"]`) |
626
676
 
627
- #### Resource Template Methods
677
+ ### Resource Template Methods
628
678
 
629
679
  Resource templates only use the `define` method to configure their properties - they don't have a `call` method.
630
680
 
@@ -632,7 +682,7 @@ Resource templates only use the `define` method to configure their properties -
632
682
  |--------|---------|-------------|
633
683
  | `define` | Class definition | Block for defining resource template metadata and URI template |
634
684
 
635
- #### Examples
685
+ ### Examples
636
686
 
637
687
  This is an example resource template that provides a completion for a parameter of the URI template:
638
688
 
@@ -668,13 +718,15 @@ class TestResourceTemplate < ModelContextProtocol::Server::ResourceTemplate
668
718
  end
669
719
  ```
670
720
 
671
- ### Tools
721
+ ---
722
+
723
+ ## Tools
672
724
 
673
725
  The `ModelContextProtocol::Server::Tool` base class allows subclasses to define a tool that the MCP client can use.
674
726
 
675
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.
676
728
 
677
- #### Tool Definition
729
+ ### Tool Definition
678
730
 
679
731
  Use the `define` block to set [tool properties](https://spec.modelcontextprotocol.io/specification/2025-06-18/server/tools/) and configure schemas.
680
732
 
@@ -686,7 +738,7 @@ Use the `define` block to set [tool properties](https://spec.modelcontextprotoco
686
738
  | `input_schema` | JSON schema block for validating tool inputs |
687
739
  | `output_schema` | JSON schema block for validating structured content outputs |
688
740
 
689
- #### Tool Methods
741
+ ### Tool Methods
690
742
 
691
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.
692
744
 
@@ -698,7 +750,7 @@ Define your tool properties and schemas, implement the `call` method using conte
698
750
  | `progressable` | Within `call` | Wrap long-running operations to send clients progress notifications (e.g., `progressable { slow_operation }`) |
699
751
  | `respond_with` | Within `call` | Return properly formatted response data with various content types |
700
752
 
701
- #### Content Blocks
753
+ ### Content Blocks
702
754
 
703
755
  Use content blocks to properly format the content included in tool responses.
704
756
 
@@ -710,7 +762,7 @@ Use content blocks to properly format the content included in tool responses.
710
762
  | `embedded_resource_content` | Within `call` | Create embedded resource content block (requires `resource:`) |
711
763
  | `resource_link` | Within `call` | Create resource link content block (requires `name:` and `uri:`) |
712
764
 
713
- #### Response Types
765
+ ### Response Types
714
766
 
715
767
  Tools can return different types of responses using `respond_with`.
716
768
 
@@ -721,7 +773,7 @@ Tools can return different types of responses using `respond_with`.
721
773
  | `content:` | `respond_with content: [content_blocks]` | Return array of mixed content blocks |
722
774
  | `error:` | `respond_with error: "message"` | Return tool error response |
723
775
 
724
- #### Available Instance Variables
776
+ ### Available Instance Variables
725
777
 
726
778
  Arguments from MCP clients and server context are available, along with logging capabilities.
727
779
 
@@ -731,7 +783,7 @@ Arguments from MCP clients and server context are available, along with logging
731
783
  | `context` | Within `call` | Hash containing server configuration context values |
732
784
  | `logger` | Within `call` | Logger instance for logging (e.g., `logger.info("message")`) |
733
785
 
734
- #### Examples
786
+ ### Examples
735
787
 
736
788
  This is an example of a tool that returns structured content validated by an output schema:
737
789
 
@@ -1096,13 +1148,15 @@ class TestToolWithProgressableAndCancellable < ModelContextProtocol::Server::Too
1096
1148
  end
1097
1149
  ```
1098
1150
 
1099
- ### Completions
1151
+ ---
1152
+
1153
+ ## Completions
1100
1154
 
1101
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.
1102
1156
 
1103
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.
1104
1158
 
1105
- #### Completion Methods
1159
+ ### Completion Methods
1106
1160
 
1107
1161
  Completions only implement the `call` method to provide completion logic.
1108
1162
 
@@ -1111,7 +1165,7 @@ Completions only implement the `call` method to provide completion logic.
1111
1165
  | `call` | Instance method | Main method to implement completion logic and build response |
1112
1166
  | `respond_with` | Within `call` | Return properly formatted completion response (e.g., `respond_with values:`) |
1113
1167
 
1114
- #### Available Instance Variables
1168
+ ### Available Instance Variables
1115
1169
 
1116
1170
  Completions receive the argument name and current value being completed.
1117
1171
 
@@ -1120,7 +1174,7 @@ Completions receive the argument name and current value being completed.
1120
1174
  | `argument_name` | Within `call` | String name of the argument being completed |
1121
1175
  | `argument_value` | Within `call` | Current partial value being typed by the user |
1122
1176
 
1123
- #### Examples
1177
+ ### Examples
1124
1178
 
1125
1179
  This is an example completion that returns an array of values in the response:
1126
1180
 
@@ -1137,25 +1191,7 @@ class TestCompletion < ModelContextProtocol::Server::Completion
1137
1191
  end
1138
1192
  ```
1139
1193
 
1140
- ## Installation
1141
-
1142
- Add this line to your application's Gemfile:
1143
-
1144
- ```ruby
1145
- gem 'model-context-protocol-rb'
1146
- ```
1147
-
1148
- And then execute:
1149
-
1150
- ```bash
1151
- bundle
1152
- ```
1153
-
1154
- Or install it yourself as:
1155
-
1156
- ```bash
1157
- gem install model-context-protocol-rb
1158
- ```
1194
+ ---
1159
1195
 
1160
1196
  ## Development
1161
1197
 
@@ -182,7 +182,13 @@ module ModelContextProtocol
182
182
  event_id = next_event_id
183
183
  send_sse_event(stream, {}, event_id)
184
184
  end
185
+
186
+ # Close stream immediately when work is complete
187
+ close_stream(temp_stream_id, reason: "request_completed")
188
+ rescue IOError, Errno::EPIPE, Errno::ECONNRESET
189
+ # Client disconnected during processing
185
190
  ensure
191
+ # Fallback cleanup
186
192
  @stream_registry.unregister_stream(temp_stream_id)
187
193
  end
188
194
  end
@@ -201,6 +207,20 @@ module ModelContextProtocol
201
207
  stream.flush if stream.respond_to?(:flush)
202
208
  end
203
209
 
210
+ def close_stream(session_id, reason: "completed")
211
+ if (stream = @stream_registry.get_local_stream(session_id))
212
+ begin
213
+ send_sse_event(stream, {type: "stream_complete", reason: reason})
214
+ stream.close
215
+ rescue IOError, Errno::EPIPE, Errno::ECONNRESET, Errno::ENOTCONN, Errno::EBADF
216
+ nil
217
+ end
218
+
219
+ @stream_registry.unregister_stream(session_id)
220
+ @session_store.mark_stream_inactive(session_id) if @require_sessions
221
+ end
222
+ end
223
+
204
224
  def handle_post_request(env)
205
225
  validation_error = validate_headers(env)
206
226
  return validation_error if validation_error
@@ -404,7 +424,7 @@ module ModelContextProtocol
404
424
  stream.write(": ping\n\n")
405
425
  stream.flush if stream.respond_to?(:flush)
406
426
  true
407
- rescue IOError, Errno::EPIPE, Errno::ECONNRESET
427
+ rescue IOError, Errno::EPIPE, Errno::ECONNRESET, Errno::ENOTCONN, Errno::EBADF
408
428
  false
409
429
  end
410
430
  end
@@ -438,12 +458,10 @@ module ModelContextProtocol
438
458
  send_ping_to_stream(stream)
439
459
  @stream_registry.refresh_heartbeat(session_id)
440
460
  else
441
- @stream_registry.unregister_stream(session_id)
442
- @session_store.mark_stream_inactive(session_id)
461
+ close_stream(session_id, reason: "client_disconnected")
443
462
  end
444
- rescue IOError, Errno::EPIPE, Errno::ECONNRESET
445
- @stream_registry.unregister_stream(session_id)
446
- @session_store.mark_stream_inactive(session_id)
463
+ rescue IOError, Errno::EPIPE, Errno::ECONNRESET, Errno::ENOTCONN, Errno::EBADF
464
+ close_stream(session_id, reason: "network_error")
447
465
  end
448
466
  end
449
467
 
@@ -468,7 +486,7 @@ module ModelContextProtocol
468
486
  send_to_stream(stream, data)
469
487
  return true
470
488
  rescue IOError, Errno::EPIPE, Errno::ECONNRESET
471
- @stream_registry.unregister_stream(session_id)
489
+ close_stream(session_id, reason: "client_disconnected")
472
490
  end
473
491
  end
474
492
 
@@ -493,7 +511,7 @@ module ModelContextProtocol
493
511
  @stream_registry.get_all_local_streams.each do |session_id, stream|
494
512
  send_to_stream(stream, notification)
495
513
  rescue IOError, Errno::EPIPE, Errno::ECONNRESET
496
- @stream_registry.unregister_stream(session_id)
514
+ close_stream(session_id, reason: "client_disconnected")
497
515
  end
498
516
  end
499
517
 
@@ -1,3 +1,3 @@
1
1
  module ModelContextProtocol
2
- VERSION = "0.5.0"
2
+ VERSION = "0.5.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: model-context-protocol-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dick Davis