model-context-protocol-rb 0.3.1 → 0.3.3
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 +19 -1
- data/README.md +254 -67
- data/lib/model_context_protocol/server/completion.rb +51 -0
- data/lib/model_context_protocol/server/configuration.rb +94 -2
- data/lib/model_context_protocol/server/mcp_logger.rb +109 -0
- data/lib/model_context_protocol/server/prompt.rb +72 -15
- data/lib/model_context_protocol/server/registry.rb +22 -0
- data/lib/model_context_protocol/server/resource.rb +35 -10
- data/lib/model_context_protocol/server/resource_template.rb +93 -0
- data/lib/model_context_protocol/server/session_store.rb +108 -0
- data/lib/model_context_protocol/server/stdio_transport.rb +26 -11
- data/lib/model_context_protocol/server/streamable_http_transport.rb +291 -0
- data/lib/model_context_protocol/server/tool.rb +28 -8
- data/lib/model_context_protocol/server.rb +80 -7
- data/lib/model_context_protocol/version.rb +1 -1
- data/lib/model_context_protocol.rb +1 -1
- data/tasks/templates/dev.erb +14 -1
- metadata +21 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5cce144594a63393d124f7edc41428730824f2e5df282b21458b506d1ac59376
|
4
|
+
data.tar.gz: f7a1de949d083fbcf9df57f500cad32869aa2c42b7dda17726509bab58ffc0b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f374a5e4cf00d1f905f86c51be35c812b6074c188dca28e2724a9e478afdba641337b4f17404ed44cdb22a86baf88dbcaf03df4896e5b039f1717eb3c8afbb71
|
7
|
+
data.tar.gz: 8bb5dd4e584f9df32265d1a88d9469e73b2c70225a88da510240bb5b7f80ef4f94b13738ed66a1f1bcec39012832efc0032d72d7ff93ede737ec31d737589243
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.3.3] - 2025-09-02
|
4
|
+
|
5
|
+
- (Breaking) Added logging support.
|
6
|
+
- Requires updating the `enable_log` configuration option to `logging_enabled`.
|
7
|
+
- Added experimental Streamable HTTP transport.
|
8
|
+
- (Breaking) Renamed params to arguments in prompts, resources, and tools.
|
9
|
+
- Requires updating all references to `params` in prompts, resources, and tools to `arguments` with symbolized keys.
|
10
|
+
- Improved ergonomics of completions and resource templates.
|
11
|
+
- Added support for providing context to prompts, resources, and tools.
|
12
|
+
|
13
|
+
## [0.3.2] - 2025-05-10
|
14
|
+
|
15
|
+
- Added resource template support.
|
16
|
+
- Added completion support for prompts and resources.
|
17
|
+
- Improved metadata definition for prompts, resources, and tools using simple DSL.
|
18
|
+
|
3
19
|
## [0.3.1] - 2025-04-04
|
4
20
|
|
5
21
|
- Added support for environment variables to MCP servers (thanks @hmk):
|
@@ -31,7 +47,9 @@
|
|
31
47
|
|
32
48
|
- Initial release
|
33
49
|
|
34
|
-
[Unreleased]: https://github.com/dickdavis/model-context-protocol-rb/compare/v0.3.
|
50
|
+
[Unreleased]: https://github.com/dickdavis/model-context-protocol-rb/compare/v0.3.3...HEAD
|
51
|
+
[0.3.3]: https://github.com/dickdavis/model-context-protocol-rb/compare/v0.3.2...v0.3.3
|
52
|
+
[0.3.2]: https://github.com/dickdavis/model-context-protocol-rb/compare/v0.3.1...v0.3.2
|
35
53
|
[0.3.1]: https://github.com/dickdavis/model-context-protocol-rb/compare/v0.3.0...v0.3.1
|
36
54
|
[0.3.0]: https://github.com/dickdavis/model-context-protocol-rb/compare/v0.2.0...v0.3.0
|
37
55
|
[0.2.0]: https://github.com/dickdavis/model-context-protocol-rb/compare/v0.1.0...v0.2.0
|
data/README.md
CHANGED
@@ -8,13 +8,10 @@ You are welcome to contribute.
|
|
8
8
|
|
9
9
|
TODO's:
|
10
10
|
|
11
|
-
* [Completion](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/utilities/completion/)
|
12
|
-
* [Logging](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/utilities/logging/)
|
13
11
|
* [Pagination](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/utilities/pagination/)
|
14
12
|
* [Prompt list changed notifications](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/prompts/#list-changed-notification)
|
15
13
|
* [Resource list changed notifications](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/resources/#list-changed-notification)
|
16
14
|
* [Resource subscriptions](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/resources/#subscriptions)
|
17
|
-
* [Resource templates](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/resources/#resource-templates)
|
18
15
|
* [Tool list changed notifications](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/tools/#list-changed-notification)
|
19
16
|
|
20
17
|
## Usage
|
@@ -27,13 +24,13 @@ require 'model_context_protocol'
|
|
27
24
|
|
28
25
|
### Building an MCP Server
|
29
26
|
|
30
|
-
Build a simple MCP server by registering your prompts, resources, and tools. Then, configure and run the server.
|
27
|
+
Build a simple MCP server by registering your prompts, resources, resource templates, and tools. Then, configure and run the server.
|
31
28
|
|
32
29
|
```ruby
|
33
30
|
server = ModelContextProtocol::Server.new do |config|
|
34
31
|
config.name = "MCP Development Server"
|
35
32
|
config.version = "1.0.0"
|
36
|
-
config.
|
33
|
+
config.logging_enabled = true
|
37
34
|
|
38
35
|
# Environment Variables - https://modelcontextprotocol.io/docs/tools/debugging#environment-variables
|
39
36
|
# Require specific environment variables to be set
|
@@ -42,6 +39,12 @@ server = ModelContextProtocol::Server.new do |config|
|
|
42
39
|
# Set environment variables programmatically
|
43
40
|
config.set_environment_variable("DEBUG_MODE", "true")
|
44
41
|
|
42
|
+
# Provide prompts, resources, and tools with contextual variables
|
43
|
+
config.context = {
|
44
|
+
user_id: "123456",
|
45
|
+
request_id: SecureRandom.uuid
|
46
|
+
}
|
47
|
+
|
45
48
|
config.registry = ModelContextProtocol::Server::Registry.new do
|
46
49
|
prompts list_changed: true do
|
47
50
|
register TestPrompt
|
@@ -51,6 +54,10 @@ server = ModelContextProtocol::Server.new do |config|
|
|
51
54
|
register TestResource
|
52
55
|
end
|
53
56
|
|
57
|
+
resource_templates do
|
58
|
+
register TestResourceTemplate
|
59
|
+
end
|
60
|
+
|
54
61
|
tools list_changed: true do
|
55
62
|
register TestTool
|
56
63
|
end
|
@@ -60,44 +67,159 @@ end
|
|
60
67
|
server.start
|
61
68
|
```
|
62
69
|
|
70
|
+
### Transport Configuration
|
71
|
+
|
72
|
+
The MCP server supports different transport mechanisms for communication with clients. By default, it uses stdio (standard input/output), but you can also configure it to use streamable HTTP transport for distributed deployments.
|
73
|
+
|
74
|
+
#### Stdio Transport (Default)
|
75
|
+
|
76
|
+
When no transport is specified, the server uses stdio transport, which is suitable for single-process communication:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
server = ModelContextProtocol::Server.new do |config|
|
80
|
+
config.name = "MCP Development Server"
|
81
|
+
config.version = "1.0.0"
|
82
|
+
# No transport specified - uses stdio by default
|
83
|
+
config.registry = ModelContextProtocol::Server::Registry.new
|
84
|
+
end
|
85
|
+
|
86
|
+
server.start
|
87
|
+
```
|
88
|
+
|
89
|
+
#### Streamable HTTP Transport
|
90
|
+
|
91
|
+
For distributed deployments with load balancers and multiple server instances, use the streamable HTTP transport with Redis-backed session management:
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
require 'redis'
|
95
|
+
|
96
|
+
server = ModelContextProtocol::Server.new do |config|
|
97
|
+
config.name = "MCP Development Server"
|
98
|
+
config.version = "1.0.0"
|
99
|
+
|
100
|
+
# Configure streamable HTTP transport
|
101
|
+
config.transport = {
|
102
|
+
type: :streamable_http,
|
103
|
+
redis_client: Redis.new(url: ENV['REDIS_URL']),
|
104
|
+
session_ttl: 3600 # Optional: session timeout in seconds (default: 3600)
|
105
|
+
}
|
106
|
+
|
107
|
+
config.registry = ModelContextProtocol::Server::Registry.new
|
108
|
+
end
|
109
|
+
|
110
|
+
# For HTTP frameworks, handle the request and return the response
|
111
|
+
result = server.start
|
112
|
+
# result will be a hash like: {json: {...}, status: 200, headers: {...}}
|
113
|
+
```
|
114
|
+
|
115
|
+
**Key Features:**
|
116
|
+
- **Distributed Sessions**: Redis-backed session storage enables multiple server instances
|
117
|
+
- **Load Balancer Support**: Sessions persist across different server instances
|
118
|
+
- **HTTP Methods**: Supports POST (requests), GET (Server-Sent Events), DELETE (cleanup)
|
119
|
+
- **Cross-Server Routing**: Messages are routed between servers via Redis pub/sub
|
120
|
+
|
121
|
+
**Integration Example (Rails):**
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
class McpController < ApplicationController
|
125
|
+
def handle
|
126
|
+
server = ModelContextProtocol::Server.new do |config|
|
127
|
+
config.name = "Rails MCP Server"
|
128
|
+
config.version = "1.0.0"
|
129
|
+
config.transport = {
|
130
|
+
type: :streamable_http,
|
131
|
+
redis_client: Redis.new(url: ENV['REDIS_URL']),
|
132
|
+
request: request,
|
133
|
+
response: response
|
134
|
+
}
|
135
|
+
config.registry = build_registry
|
136
|
+
end
|
137
|
+
|
138
|
+
result = server.start
|
139
|
+
render json: result[:json], status: result[:status], headers: result[:headers]
|
140
|
+
end
|
141
|
+
end
|
142
|
+
```
|
143
|
+
|
63
144
|
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
145
|
|
65
|
-
|
146
|
+
### Server features
|
147
|
+
|
148
|
+
#### Prompts
|
66
149
|
|
67
150
|
The `ModelContextProtocol::Server::Prompt` base class allows subclasses to define a prompt that the MCP client can use. Define the [appropriate metadata](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/prompts/) in the `with_metadata` block.
|
68
151
|
|
69
|
-
|
152
|
+
Define any arguments using the `with_argument` block. You can mark an argument as required, and you can optionally provide a completion class. See [Completions](#completions) for more information.
|
153
|
+
|
154
|
+
Then implement the `call` method to build your prompt. Any arguments passed to the tool from the MCP client will be available in the `arguments` hash with symbol keys (e.g., `arguments[:argument_name]`), and any context values provided in the server configuration will be available in the `context` hash. Use the `respond_with` instance method to ensure your prompt responds with appropriately formatted response data.
|
155
|
+
|
156
|
+
You can also log from within your prompt by calling a valid logger level method on the `logger` and passing a string message.
|
70
157
|
|
71
158
|
This is an example prompt that returns a properly formatted response:
|
72
159
|
|
73
160
|
```ruby
|
74
161
|
class TestPrompt < ModelContextProtocol::Server::Prompt
|
162
|
+
ToneCompletion = ModelContextProtocol::Server::Completion.define do
|
163
|
+
hints = ["whiny", "angry", "callous", "desperate", "nervous", "sneaky"]
|
164
|
+
values = hints.grep(/#{argument_value}/)
|
165
|
+
|
166
|
+
respond_with values:
|
167
|
+
end
|
168
|
+
|
75
169
|
with_metadata do
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
}
|
170
|
+
name "brainstorm_excuses"
|
171
|
+
description "A prompt for brainstorming excuses to get out of something"
|
172
|
+
end
|
173
|
+
|
174
|
+
with_argument do
|
175
|
+
name "undesirable_activity"
|
176
|
+
description "The thing to get out of"
|
177
|
+
required true
|
178
|
+
end
|
179
|
+
|
180
|
+
with_argument do
|
181
|
+
name "tone"
|
182
|
+
description "The general tone to be used in the generated excuses"
|
183
|
+
required false
|
184
|
+
completion ToneCompletion
|
92
185
|
end
|
93
186
|
|
94
187
|
def call
|
188
|
+
logger.info("Brainstorming excuses...")
|
95
189
|
messages = [
|
96
190
|
{
|
97
191
|
role: "user",
|
98
192
|
content: {
|
99
193
|
type: "text",
|
100
|
-
text: "
|
194
|
+
text: "My wife wants me to: #{arguments[:undesirable_activity]}... Can you believe it?"
|
195
|
+
}
|
196
|
+
},
|
197
|
+
{
|
198
|
+
role: "assistant",
|
199
|
+
content: {
|
200
|
+
type: "text",
|
201
|
+
text: "Oh, that's just downright awful. What are you going to do?"
|
202
|
+
}
|
203
|
+
},
|
204
|
+
{
|
205
|
+
role: "user",
|
206
|
+
content: {
|
207
|
+
type: "text",
|
208
|
+
text: "Well, I'd like to get out of it, but I'm going to need your help."
|
209
|
+
}
|
210
|
+
},
|
211
|
+
{
|
212
|
+
role: "assistant",
|
213
|
+
content: {
|
214
|
+
type: "text",
|
215
|
+
text: "Anything for you."
|
216
|
+
}
|
217
|
+
},
|
218
|
+
{
|
219
|
+
role: "user",
|
220
|
+
content: {
|
221
|
+
type: "text",
|
222
|
+
text: "Can you generate some excuses for me?" + (arguments[:tone] ? "Make them as #{arguments[:tone]} as possible." : "")
|
101
223
|
}
|
102
224
|
}
|
103
225
|
]
|
@@ -107,27 +229,39 @@ class TestPrompt < ModelContextProtocol::Server::Prompt
|
|
107
229
|
end
|
108
230
|
```
|
109
231
|
|
110
|
-
####
|
232
|
+
#### Resources
|
111
233
|
|
112
234
|
The `ModelContextProtocol::Server::Resource` base class allows subclasses to define a resource that the MCP client can use. Define the [appropriate metadata](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/resources/) in the `with_metadata` block.
|
113
235
|
|
114
|
-
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.
|
236
|
+
Then, implement the `call` method to build your resource. Any context values provided in the server configuration will be available in the `context` hash. Use the `respond_with` instance method to ensure your resource responds with appropriately formatted response data.
|
237
|
+
|
238
|
+
You can also log from within your resource by calling a valid logger level method on the `logger` and passing a string message.
|
115
239
|
|
116
240
|
This is an example resource that returns a text response:
|
117
241
|
|
118
242
|
```ruby
|
119
243
|
class TestResource < ModelContextProtocol::Server::Resource
|
120
244
|
with_metadata do
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
uri: "resource://test-resource"
|
126
|
-
}
|
245
|
+
name "top-secret-plans.txt"
|
246
|
+
description "Top secret plans to do top secret things"
|
247
|
+
mime_type "text/plain"
|
248
|
+
uri "file:///top-secret-plans.txt"
|
127
249
|
end
|
128
250
|
|
129
251
|
def call
|
130
|
-
|
252
|
+
unless authorized?(context[:user_id])
|
253
|
+
logger.info("This fool thinks he can get my top secret plans...")
|
254
|
+
return respond_with :text, text: "Nothing to see here, move along."
|
255
|
+
end
|
256
|
+
|
257
|
+
respond_with :text, text: "I'm finna eat all my wife's leftovers."
|
258
|
+
end
|
259
|
+
|
260
|
+
private
|
261
|
+
|
262
|
+
def authorized?(user_id)
|
263
|
+
authorized_users = ["42", "123456"]
|
264
|
+
authorized_users.any?(user_id)
|
131
265
|
end
|
132
266
|
end
|
133
267
|
```
|
@@ -137,52 +271,84 @@ This is an example resource that returns binary data:
|
|
137
271
|
```ruby
|
138
272
|
class TestBinaryResource < ModelContextProtocol::Server::Resource
|
139
273
|
with_metadata do
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
uri: "resource://project-logo"
|
145
|
-
}
|
274
|
+
name "project-logo.png"
|
275
|
+
description "The logo for the project"
|
276
|
+
mime_type "image/png"
|
277
|
+
uri "file:///project-logo.png"
|
146
278
|
end
|
147
279
|
|
148
280
|
def call
|
149
281
|
# In a real implementation, we would retrieve the binary resource
|
282
|
+
# This is a small valid base64 encoded string (represents "test")
|
150
283
|
data = "dGVzdA=="
|
151
284
|
respond_with :binary, blob: data
|
152
285
|
end
|
153
286
|
end
|
154
287
|
```
|
155
288
|
|
156
|
-
####
|
289
|
+
#### Resource Templates
|
290
|
+
|
291
|
+
The `ModelContextProtocol::Server::ResourceTemplate` base class allows subclasses to define a resource template that the MCP client can use. Define the [appropriate metadata](https://modelcontextprotocol.io/specification/2024-11-05/server/resources#resource-templates) in the `with_metadata` block.
|
292
|
+
|
293
|
+
This is an example resource template that provides a completion for a parameter of the URI template:
|
294
|
+
|
295
|
+
```ruby
|
296
|
+
class TestResourceTemplate < ModelContextProtocol::Server::ResourceTemplate
|
297
|
+
Completion = ModelContextProtocol::Server::Completion.define do
|
298
|
+
hints = {
|
299
|
+
"name" => ["top-secret-plans.txt"]
|
300
|
+
}
|
301
|
+
values = hints[argument_name].grep(/#{argument_value}/)
|
302
|
+
|
303
|
+
respond_with values:
|
304
|
+
end
|
305
|
+
|
306
|
+
with_metadata do
|
307
|
+
name "project-document-resource-template"
|
308
|
+
description "A resource template for retrieving project documents"
|
309
|
+
mime_type "text/plain"
|
310
|
+
uri_template "file:///{name}" do
|
311
|
+
completion :name, Completion
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
```
|
316
|
+
|
317
|
+
#### Tools
|
157
318
|
|
158
319
|
The `ModelContextProtocol::Server::Tool` base class allows subclasses to define a tool that the MCP client can use. Define the [appropriate metadata](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/tools/) in the `with_metadata` block.
|
159
320
|
|
160
|
-
Then implement the `call` method to build your tool. Use the `respond_with` instance method to ensure your tool responds with appropriately formatted response data.
|
321
|
+
Then, implement the `call` method to build your tool. Any arguments passed to the tool from the MCP client will be available in the `arguments` hash with symbol keys (e.g., `arguments[:argument_name]`), and any context values provided in the server configuration will be available in the `context` hash. Use the `respond_with` instance method to ensure your tool responds with appropriately formatted response data.
|
322
|
+
|
323
|
+
You can also log from within your tool by calling a valid logger level method on the `logger` and passing a string message.
|
161
324
|
|
162
325
|
This is an example tool that returns a text response:
|
163
326
|
|
164
327
|
```ruby
|
165
328
|
class TestToolWithTextResponse < ModelContextProtocol::Server::Tool
|
166
329
|
with_metadata do
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
330
|
+
name "double"
|
331
|
+
description "Doubles the provided number"
|
332
|
+
input_schema do
|
333
|
+
{
|
171
334
|
type: "object",
|
172
335
|
properties: {
|
173
336
|
number: {
|
174
|
-
type: "string"
|
337
|
+
type: "string"
|
175
338
|
}
|
176
339
|
},
|
177
340
|
required: ["number"]
|
178
341
|
}
|
179
|
-
|
342
|
+
end
|
180
343
|
end
|
181
344
|
|
182
345
|
def call
|
183
|
-
|
184
|
-
|
185
|
-
|
346
|
+
user_id = context[:user_id]
|
347
|
+
number = arguments[:number].to_i
|
348
|
+
logger.info("Silly user doesn't know how to double a number")
|
349
|
+
calculation = number * 2
|
350
|
+
salutation = user_id ? "User #{user_id}, " : ""
|
351
|
+
respond_with :text, text: salutation << "#{number} doubled is #{calculation}"
|
186
352
|
end
|
187
353
|
end
|
188
354
|
```
|
@@ -192,10 +358,10 @@ This is an example of a tool that returns an image:
|
|
192
358
|
```ruby
|
193
359
|
class TestToolWithImageResponse < ModelContextProtocol::Server::Tool
|
194
360
|
with_metadata do
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
361
|
+
name "custom-chart-generator"
|
362
|
+
description "Generates a chart in various formats"
|
363
|
+
input_schema do
|
364
|
+
{
|
199
365
|
type: "object",
|
200
366
|
properties: {
|
201
367
|
chart_type: {
|
@@ -209,12 +375,12 @@ class TestToolWithImageResponse < ModelContextProtocol::Server::Tool
|
|
209
375
|
},
|
210
376
|
required: ["chart_type", "format"]
|
211
377
|
}
|
212
|
-
|
378
|
+
end
|
213
379
|
end
|
214
380
|
|
215
381
|
def call
|
216
382
|
# Map format to mime type
|
217
|
-
mime_type = case
|
383
|
+
mime_type = case arguments[:format].downcase
|
218
384
|
when "svg"
|
219
385
|
"image/svg+xml"
|
220
386
|
when "jpg", "jpeg"
|
@@ -236,10 +402,10 @@ If you don't provide a mime type, it will default to `image/png`.
|
|
236
402
|
```ruby
|
237
403
|
class TestToolWithImageResponseDefaultMimeType < ModelContextProtocol::Server::Tool
|
238
404
|
with_metadata do
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
405
|
+
name "other-custom-chart-generator"
|
406
|
+
description "Generates a chart"
|
407
|
+
input_schema do
|
408
|
+
{
|
243
409
|
type: "object",
|
244
410
|
properties: {
|
245
411
|
chart_type: {
|
@@ -249,7 +415,7 @@ class TestToolWithImageResponseDefaultMimeType < ModelContextProtocol::Server::T
|
|
249
415
|
},
|
250
416
|
required: ["chart_type"]
|
251
417
|
}
|
252
|
-
|
418
|
+
end
|
253
419
|
end
|
254
420
|
|
255
421
|
def call
|
@@ -266,10 +432,10 @@ This is an example of a tool that returns a resource response:
|
|
266
432
|
```ruby
|
267
433
|
class TestToolWithResourceResponse < ModelContextProtocol::Server::Tool
|
268
434
|
with_metadata do
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
435
|
+
name "document-finder"
|
436
|
+
description "Finds a the document with the given title"
|
437
|
+
input_schema do
|
438
|
+
{
|
273
439
|
type: "object",
|
274
440
|
properties: {
|
275
441
|
title: {
|
@@ -279,11 +445,11 @@ class TestToolWithResourceResponse < ModelContextProtocol::Server::Tool
|
|
279
445
|
},
|
280
446
|
required: ["title"]
|
281
447
|
}
|
282
|
-
|
448
|
+
end
|
283
449
|
end
|
284
450
|
|
285
451
|
def call
|
286
|
-
title =
|
452
|
+
title = arguments[:title].downcase
|
287
453
|
# In a real implementation, we would do a lookup to get the document data
|
288
454
|
document = "richtextdata"
|
289
455
|
respond_with :resource, uri: "resource://document/#{title}", text: document, mime_type: "application/rtf"
|
@@ -291,6 +457,27 @@ class TestToolWithResourceResponse < ModelContextProtocol::Server::Tool
|
|
291
457
|
end
|
292
458
|
```
|
293
459
|
|
460
|
+
### Completions
|
461
|
+
|
462
|
+
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.
|
463
|
+
|
464
|
+
implement the `call` method to build your completion. Use the `respond_with` instance method to ensure your completion responds with appropriately formatted response data.
|
465
|
+
|
466
|
+
This is an example completion that returns an array of values in the response:
|
467
|
+
|
468
|
+
```ruby
|
469
|
+
class TestCompletion < ModelContextProtocol::Server::Completion
|
470
|
+
def call
|
471
|
+
hints = {
|
472
|
+
"message" => ["hello", "world", "foo", "bar"]
|
473
|
+
}
|
474
|
+
values = hints[argument_name].grep(/#{argument_value}/)
|
475
|
+
|
476
|
+
respond_with values:
|
477
|
+
end
|
478
|
+
end
|
479
|
+
```
|
480
|
+
|
294
481
|
## Installation
|
295
482
|
|
296
483
|
Add this line to your application's Gemfile:
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module ModelContextProtocol
|
2
|
+
class Server::Completion
|
3
|
+
attr_reader :argument_name, :argument_value
|
4
|
+
|
5
|
+
def initialize(argument_name, argument_value)
|
6
|
+
@argument_name = argument_name
|
7
|
+
@argument_value = argument_value
|
8
|
+
end
|
9
|
+
|
10
|
+
def call
|
11
|
+
raise NotImplementedError, "Subclasses must implement the call method"
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.call(...)
|
15
|
+
new(...).call
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.define(&block)
|
19
|
+
Class.new(self) do
|
20
|
+
define_method(:call, &block)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
Response = Data.define(:values, :total, :hasMore) do
|
27
|
+
def serialized
|
28
|
+
{completion: {values:, total:, hasMore:}}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def respond_with(values:)
|
33
|
+
values_to_return = values.take(100)
|
34
|
+
total = values.size
|
35
|
+
has_more = values_to_return.size != total
|
36
|
+
Response[values:, total:, hasMore: has_more]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class Server::NullCompletion
|
41
|
+
Response = Data.define(:values, :total, :hasMore) do
|
42
|
+
def serialized
|
43
|
+
{completion: {values:, total:, hasMore:}}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.call(_argument_name, _argument_value)
|
48
|
+
Response[values: [], total: 0, hasMore: false]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|