model-context-protocol-rb 0.3.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +23 -1
- data/README.md +745 -198
- data/lib/model_context_protocol/server/configuration.rb +79 -2
- data/lib/model_context_protocol/server/content.rb +321 -0
- data/lib/model_context_protocol/server/content_helpers.rb +84 -0
- data/lib/model_context_protocol/server/pagination.rb +71 -0
- data/lib/model_context_protocol/server/prompt.rb +123 -31
- data/lib/model_context_protocol/server/registry.rb +94 -18
- data/lib/model_context_protocol/server/resource.rb +95 -25
- data/lib/model_context_protocol/server/resource_template.rb +26 -13
- data/lib/model_context_protocol/server/streamable_http_transport.rb +211 -54
- data/lib/model_context_protocol/server/tool.rb +83 -61
- data/lib/model_context_protocol/server.rb +115 -18
- data/lib/model_context_protocol/version.rb +1 -3
- data/tasks/mcp.rake +28 -2
- data/tasks/templates/dev-http.erb +244 -0
- data/tasks/templates/dev.erb +7 -1
- metadata +6 -2
data/README.md
CHANGED
@@ -1,18 +1,52 @@
|
|
1
1
|
# model-context-protocol-rb
|
2
2
|
|
3
|
-
An implementation of the [Model Context Protocol (MCP)](https://spec.modelcontextprotocol.io/specification/
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
3
|
+
An implementation of the [Model Context Protocol (MCP)](https://spec.modelcontextprotocol.io/specification/2025-06-18/) in Ruby. You are welcome to contribute.
|
4
|
+
|
5
|
+
## Table of Contents
|
6
|
+
|
7
|
+
- [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)
|
23
|
+
- [Installation](#installation)
|
24
|
+
- [Development](#development)
|
25
|
+
- [Releases](#releases)
|
26
|
+
- [Contributing](#contributing)
|
27
|
+
- [License](#license)
|
28
|
+
|
29
|
+
## Feature Support (Server)
|
30
|
+
|
31
|
+
| Status | Feature |
|
32
|
+
|--------|---------|
|
33
|
+
| ✅ | [Prompts](https://modelcontextprotocol.io/specification/2025-06-18/server/prompts) |
|
34
|
+
| ✅ | [Resources](https://modelcontextprotocol.io/specification/2025-06-18/server/resources) |
|
35
|
+
| ✅ | [Resource Templates](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#resource-templates) |
|
36
|
+
| ✅ | [Tools](https://modelcontextprotocol.io/specification/2025-06-18/server/tools) |
|
37
|
+
| ✅ | [Completion](https://modelcontextprotocol.io/specification/2025-06-18/server/utilities/completion) |
|
38
|
+
| ✅ | [Logging](https://modelcontextprotocol.io/specification/2025-06-18/server/utilities/logging) |
|
39
|
+
| ✅ | [Pagination](https://modelcontextprotocol.io/specification/2025-06-18/server/utilities/pagination) |
|
40
|
+
| ✅ | [Environment Variables](https://modelcontextprotocol.io/legacy/tools/debugging#environment-variables) |
|
41
|
+
| ✅ | [STDIO Transport](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#stdio) |
|
42
|
+
| ✅ | [Streamable HTTP Transport](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#streamable-http) |
|
43
|
+
| ❌ | [List Changed Notification (Prompts)](https://modelcontextprotocol.io/specification/2025-06-18/server/prompts#list-changed-notification) |
|
44
|
+
| ❌ | [List Changed Notification (Resources)](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#list-changed-notification) |
|
45
|
+
| ❌ | [Subscriptions (Resources)](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#subscriptions) |
|
46
|
+
| ❌ | [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) |
|
48
|
+
| ✅ | [Ping](https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/ping) |
|
49
|
+
| ❌ | [Progress](https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/progress) |
|
16
50
|
|
17
51
|
## Usage
|
18
52
|
|
@@ -24,27 +58,69 @@ require 'model_context_protocol'
|
|
24
58
|
|
25
59
|
### Building an MCP Server
|
26
60
|
|
27
|
-
Build a simple MCP server by registering your prompts, resources, resource templates, and tools. Then, configure and run the server.
|
61
|
+
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.
|
28
62
|
|
29
63
|
```ruby
|
30
64
|
server = ModelContextProtocol::Server.new do |config|
|
31
|
-
|
65
|
+
# Name of the MCP server (intended for programmatic use)
|
66
|
+
config.name = "MCPDevelopmentServer"
|
67
|
+
|
68
|
+
# Version of the MCP server
|
32
69
|
config.version = "1.0.0"
|
70
|
+
|
71
|
+
# Optional: human-readable display name for the MCP server
|
72
|
+
config.title = "My Awesome Server"
|
73
|
+
|
74
|
+
# Optional: instuctions for how the MCP server should be used by LLMs
|
75
|
+
config.instructions = <<~INSTRUCTIONS
|
76
|
+
This server provides file system access and development tools.
|
77
|
+
|
78
|
+
Key capabilities:
|
79
|
+
- Read and write files in the project directory
|
80
|
+
- Execute shell commands for development tasks
|
81
|
+
- Analyze code structure and dependencies
|
82
|
+
|
83
|
+
Use this server when you need to interact with the local development environment.
|
84
|
+
INSTRUCTIONS
|
85
|
+
|
86
|
+
# Enable or disable MCP server logging
|
33
87
|
config.logging_enabled = true
|
34
88
|
|
35
|
-
#
|
36
|
-
#
|
89
|
+
# Configure pagination options for the following methods:
|
90
|
+
# prompts/list, resources/list, resource_template/list, tools/list
|
91
|
+
config.pagination = {
|
92
|
+
default_page_size: 50, # Default items per page
|
93
|
+
max_page_size: 500, # Maximum allowed page size
|
94
|
+
cursor_ttl: 1800 # Cursor expiry in seconds (30 minutes)
|
95
|
+
}
|
96
|
+
|
97
|
+
# Disable pagination support (enabled by default)
|
98
|
+
# config.pagination = false
|
99
|
+
|
100
|
+
# Optional: require specific environment variables to be set
|
37
101
|
config.require_environment_variable("API_KEY")
|
38
102
|
|
39
|
-
#
|
103
|
+
# Optional: set environment variables programmatically
|
40
104
|
config.set_environment_variable("DEBUG_MODE", "true")
|
41
105
|
|
42
|
-
#
|
106
|
+
# Optional: provide prompts, resources, and tools with contextual variables
|
43
107
|
config.context = {
|
44
108
|
user_id: "123456",
|
45
109
|
request_id: SecureRandom.uuid
|
46
110
|
}
|
47
111
|
|
112
|
+
# Optional: explicitly specify STDIO as the transport
|
113
|
+
# This is not necessary as STDIO is the default transport
|
114
|
+
# config.transport = { type: :stdio }
|
115
|
+
|
116
|
+
# Optional: configure streamable HTTP transport if required
|
117
|
+
# config.transport = {
|
118
|
+
# type: :streamable_http,
|
119
|
+
# redis_client: Redis.new(url: ENV['REDIS_URL']),
|
120
|
+
# session_ttl: 3600 # Optional: session timeout in seconds (default: 3600)
|
121
|
+
# }
|
122
|
+
|
123
|
+
# Register prompts, resources, resource templates, and tools
|
48
124
|
config.registry = ModelContextProtocol::Server::Registry.new do
|
49
125
|
prompts list_changed: true do
|
50
126
|
register TestPrompt
|
@@ -64,204 +140,401 @@ server = ModelContextProtocol::Server.new do |config|
|
|
64
140
|
end
|
65
141
|
end
|
66
142
|
|
143
|
+
# Start the MCP server
|
67
144
|
server.start
|
68
145
|
```
|
69
146
|
|
70
|
-
|
147
|
+
#### Server Configuration Options
|
71
148
|
|
72
|
-
The
|
149
|
+
The following table details all available configuration options for the MCP server:
|
73
150
|
|
74
|
-
|
151
|
+
| Option | Type | Required | Default | Description |
|
152
|
+
|--------|------|----------|---------|-------------|
|
153
|
+
| `name` | String | Yes | - | Name of the MCP server for programmatic use |
|
154
|
+
| `version` | String | Yes | - | Version of the MCP server |
|
155
|
+
| `title` | String | No | - | Human-readable display name for the MCP server |
|
156
|
+
| `instructions` | String | No | - | Instructions for how the MCP server should be used by LLMs |
|
157
|
+
| `logging_enabled` | Boolean | No | `true` | Enable or disable MCP server logging |
|
158
|
+
| `pagination` | Hash/Boolean | No | See pagination table | Pagination configuration (or `false` to disable) |
|
159
|
+
| `context` | Hash | No | `{}` | Contextual variables available to prompts, resources, and tools |
|
160
|
+
| `transport` | Hash | No | `{ type: :stdio }` | Transport configuration |
|
161
|
+
| `registry` | Registry | Yes | - | Registry containing prompts, resources, and tools |
|
75
162
|
|
76
|
-
|
163
|
+
#### Pagination Configuration Options
|
77
164
|
|
78
|
-
|
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
|
165
|
+
When `pagination` is set to a Hash, the following options are available:
|
85
166
|
|
86
|
-
|
87
|
-
|
167
|
+
| Option | Type | Required | Default | Description |
|
168
|
+
|--------|------|----------|---------|-------------|
|
169
|
+
| `default_page_size` | Integer | No | `50` | Default number of items per page |
|
170
|
+
| `max_page_size` | Integer | No | `500` | Maximum allowed page size |
|
171
|
+
| `cursor_ttl` | Integer | No | `1800` | Cursor expiry time in seconds (30 minutes) |
|
172
|
+
|
173
|
+
**Note:** Set `config.pagination = false` to completely disable pagination support.
|
88
174
|
|
89
|
-
####
|
175
|
+
#### Transport Configuration Options
|
90
176
|
|
91
|
-
|
177
|
+
The transport configuration supports two types: `:stdio` (default) and `:streamable_http`.
|
92
178
|
|
179
|
+
##### STDIO Transport
|
93
180
|
```ruby
|
94
|
-
|
181
|
+
config.transport = { type: :stdio } # This is the default, can be omitted
|
182
|
+
```
|
95
183
|
|
96
|
-
|
97
|
-
|
98
|
-
config.version = "1.0.0"
|
184
|
+
##### Streamable HTTP Transport
|
185
|
+
When using `:streamable_http`, the following options are available:
|
99
186
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
187
|
+
| Option | Type | Required | Default | Description |
|
188
|
+
|--------|------|----------|---------|-------------|
|
189
|
+
| `type` | Symbol | Yes | `:stdio` | Must be `:streamable_http` for HTTP transport |
|
190
|
+
| `redis_client` | Redis | Yes | - | Redis client instance for session management |
|
191
|
+
| `session_ttl` | Integer | No | `3600` | Session timeout in seconds (1 hour) |
|
192
|
+
| `env` | Hash | No | - | Rack environment hash (for Rails integration) |
|
106
193
|
|
107
|
-
|
108
|
-
|
194
|
+
#### Registry Configuration Options
|
195
|
+
|
196
|
+
The registry is configured using `ModelContextProtocol::Server::Registry.new` and supports the following block types:
|
197
|
+
|
198
|
+
| Block Type | Options | Description |
|
199
|
+
|------------|---------|-------------|
|
200
|
+
| `prompts` | `list_changed: Boolean` | Register prompt handlers with optional list change notifications |
|
201
|
+
| `resources` | `list_changed: Boolean`, `subscribe: Boolean` | Register resource handlers with optional list change notifications and subscriptions |
|
202
|
+
| `resource_templates` | - | Register resource template handlers |
|
203
|
+
| `tools` | `list_changed: Boolean` | Register tool handlers with optional list change notifications |
|
204
|
+
|
205
|
+
Within each block, use `register ClassName` to register your handlers.
|
206
|
+
|
207
|
+
**Example:**
|
208
|
+
```ruby
|
209
|
+
config.registry = ModelContextProtocol::Server::Registry.new do
|
210
|
+
prompts list_changed: true do
|
211
|
+
register MyPrompt
|
212
|
+
register AnotherPrompt
|
213
|
+
end
|
109
214
|
|
110
|
-
|
111
|
-
|
112
|
-
|
215
|
+
resources list_changed: true, subscribe: true do
|
216
|
+
register MyResource
|
217
|
+
end
|
218
|
+
|
219
|
+
tools do
|
220
|
+
register MyTool
|
221
|
+
end
|
222
|
+
end
|
113
223
|
```
|
114
224
|
|
115
|
-
|
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
|
225
|
+
#### Integration with Rails
|
120
226
|
|
121
|
-
|
227
|
+
The streamable HTTP transport works with any valid Rack request. Here's an example of how you can integrate with Rails.
|
228
|
+
|
229
|
+
First, set the routes:
|
122
230
|
|
123
231
|
```ruby
|
124
|
-
|
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
|
+
|
125
247
|
def handle
|
126
248
|
server = ModelContextProtocol::Server.new do |config|
|
127
|
-
config.name = "
|
249
|
+
config.name = "MyMCPServer"
|
250
|
+
config.title = "My MCP Server"
|
128
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
|
129
258
|
config.transport = {
|
130
259
|
type: :streamable_http,
|
131
|
-
redis_client: Redis.new(url: ENV['REDIS_URL']),
|
132
|
-
|
133
|
-
response: response
|
260
|
+
redis_client: Redis.new(url: ENV['REDIS_URL']), # Prefer initializing a client from a connection pool
|
261
|
+
env: request.env # Rack environment hash
|
134
262
|
}
|
135
|
-
config.
|
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
|
136
273
|
end
|
137
274
|
|
138
275
|
result = server.start
|
139
|
-
|
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
|
140
297
|
end
|
141
298
|
end
|
142
299
|
```
|
143
300
|
|
144
|
-
|
301
|
+
### Prompts
|
145
302
|
|
146
|
-
|
303
|
+
The `ModelContextProtocol::Server::Prompt` base class allows subclasses to define a prompt that the MCP client can use.
|
147
304
|
|
148
|
-
|
305
|
+
Define the prompt properties and 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.
|
149
306
|
|
150
|
-
|
307
|
+
You can also log from within your prompt by calling a valid logger level method on the `logger` and passing a string message.
|
151
308
|
|
152
|
-
|
309
|
+
#### Prompt Definition
|
153
310
|
|
154
|
-
|
311
|
+
Use the `define` block to set [prompt properties](https://spec.modelcontextprotocol.io/specification/2025-06-18/server/prompts/) and configure arguments.
|
155
312
|
|
156
|
-
|
313
|
+
| Property | Description |
|
314
|
+
|----------|-------------|
|
315
|
+
| `name` | The programmatic name of the prompt |
|
316
|
+
| `title` | Human-readable display name |
|
317
|
+
| `description` | Short description of what the prompt does |
|
318
|
+
| `argument` | Define an argument block with name, description, required flag, and completion |
|
319
|
+
|
320
|
+
#### Argument Definition
|
321
|
+
|
322
|
+
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
|
+
|
324
|
+
| Property | Description |
|
325
|
+
|----------|-------------|
|
326
|
+
| `name` | The name of the argument |
|
327
|
+
| `description` | A short description of the argument |
|
328
|
+
| `required` | Whether the argument is required (boolean) |
|
329
|
+
| `completion` | Available hints for completions (array or completion class) |
|
330
|
+
|
331
|
+
#### Prompt Methods
|
332
|
+
|
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.
|
334
|
+
|
335
|
+
| Method | Context | Description |
|
336
|
+
|--------|---------|-------------|
|
337
|
+
| `define` | Class definition | Block for defining prompt metadata and arguments |
|
338
|
+
| `call` | Instance method | Main method to implement prompt logic and build response |
|
339
|
+
| `message_history` | Within `call` | DSL method to build an array of user and assistant messages |
|
340
|
+
| `respond_with` | Within `call` | Return properly formatted response data (e.g., `respond_with messages:`) |
|
341
|
+
|
342
|
+
#### Message History DSL
|
343
|
+
|
344
|
+
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
|
+
|
346
|
+
| Method | Context | Description |
|
347
|
+
|--------|---------|-------------|
|
348
|
+
| `user_message` | Within `message_history` | Create a message with user role |
|
349
|
+
| `assistant_message` | Within `message_history` | Create a message with assistant role |
|
350
|
+
|
351
|
+
#### Content Blocks
|
352
|
+
|
353
|
+
Use content blocks to properly format the content included in messages.
|
354
|
+
|
355
|
+
| Method | Context | Description |
|
356
|
+
|--------|---------|-------------|
|
357
|
+
| `text_content` | Within message blocks | Create text content block |
|
358
|
+
| `image_content` | Within message blocks | Create image content block (requires `data:` and `mime_type:`) |
|
359
|
+
| `audio_content` | Within message blocks | Create audio content block (requires `data:` and `mime_type:`) |
|
360
|
+
| `embedded_resource_content` | Within message blocks | Create embedded resource content block (requires `resource:`) |
|
361
|
+
| `resource_link` | Within message blocks | Create resource link content block (requires `name:` and `uri:`) |
|
362
|
+
|
363
|
+
#### Available Instance Variables
|
364
|
+
|
365
|
+
The `arguments` passed from an MCP client are available, as well as the `context` values passed in at server initialization.
|
366
|
+
|
367
|
+
| Variable | Context | Description |
|
368
|
+
|----------|---------|-------------|
|
369
|
+
| `arguments` | Within `call` | Hash containing client-provided arguments (symbol keys) |
|
370
|
+
| `context` | Within `call` | Hash containing server configuration context values |
|
371
|
+
| `logger` | Within `call` | Logger instance for logging (e.g., `logger.info("message")`) |
|
372
|
+
|
373
|
+
#### Examples
|
157
374
|
|
158
375
|
This is an example prompt that returns a properly formatted response:
|
159
376
|
|
160
377
|
```ruby
|
161
378
|
class TestPrompt < ModelContextProtocol::Server::Prompt
|
162
|
-
|
163
|
-
|
164
|
-
values = hints.grep(/#{argument_value}/)
|
165
|
-
|
166
|
-
respond_with values:
|
167
|
-
end
|
168
|
-
|
169
|
-
with_metadata do
|
379
|
+
define do
|
380
|
+
# The name of the prompt for programmatic use
|
170
381
|
name "brainstorm_excuses"
|
382
|
+
# The human-readable prompt name for display in UI
|
383
|
+
title "Brainstorm Excuses"
|
384
|
+
# A short description of what the tool does
|
171
385
|
description "A prompt for brainstorming excuses to get out of something"
|
172
|
-
end
|
173
386
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
387
|
+
# Define arguments to be used with your prompt
|
388
|
+
argument do
|
389
|
+
# The name of the argument
|
390
|
+
name "tone"
|
391
|
+
# A short description of the argument
|
392
|
+
description "The general tone to be used in the generated excuses"
|
393
|
+
# If the argument is required
|
394
|
+
required false
|
395
|
+
# Available hints for completions
|
396
|
+
completion ["whiny", "angry", "callous", "desperate", "nervous", "sneaky"]
|
397
|
+
end
|
179
398
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
399
|
+
argument do
|
400
|
+
name "undesirable_activity"
|
401
|
+
description "The thing to get out of"
|
402
|
+
required true
|
403
|
+
end
|
185
404
|
end
|
186
405
|
|
406
|
+
# You can optionally define a custom completion for an argument and pass it to completions.
|
407
|
+
# ToneCompletion = ModelContextProtocol::Server::Completion.define do
|
408
|
+
# hints = ["whiny", "angry", "callous", "desperate", "nervous", "sneaky"]
|
409
|
+
# values = hints.grep(/#{argument_value}/)
|
410
|
+
# respond_with values:
|
411
|
+
# end
|
412
|
+
# ...
|
413
|
+
# define do
|
414
|
+
# argument do
|
415
|
+
# name "tone"
|
416
|
+
# description "The general tone to be used in the generated excuses"
|
417
|
+
# required false
|
418
|
+
# completion ToneCompletion
|
419
|
+
# end
|
420
|
+
# end
|
421
|
+
|
422
|
+
# The call method is invoked by the MCP Server to generate a response to resource/read requests
|
187
423
|
def call
|
424
|
+
# You can use the logger
|
188
425
|
logger.info("Brainstorming excuses...")
|
189
|
-
messages = [
|
190
|
-
{
|
191
|
-
role: "user",
|
192
|
-
content: {
|
193
|
-
type: "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." : "")
|
223
|
-
}
|
224
|
-
}
|
225
|
-
]
|
226
426
|
|
227
|
-
|
427
|
+
# Build an array of user and assistant messages
|
428
|
+
messages = message_history do
|
429
|
+
# Create a message with the user role
|
430
|
+
user_message do
|
431
|
+
# Use any type of content block in a message (text, image, audio, embedded_resource, or resource_link)
|
432
|
+
text_content(text: "My wife wants me to: #{arguments[:undesirable_activity]}... Can you believe it?")
|
433
|
+
end
|
434
|
+
|
435
|
+
# You can also create messages with the assistant role
|
436
|
+
assistant_message do
|
437
|
+
text_content(text: "Oh, that's just downright awful. How can I help?")
|
438
|
+
end
|
439
|
+
|
440
|
+
user_message do
|
441
|
+
# Reference any inputs from the client by accessing the appropriate key in the arguments hash
|
442
|
+
text_content(text: "Can you generate some excuses for me?" + (arguments[:tone] ? " Make them as #{arguments[:tone]} as possible." : ""))
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
# Respond with the messages
|
447
|
+
respond_with messages:
|
228
448
|
end
|
229
449
|
end
|
230
450
|
```
|
231
451
|
|
232
|
-
|
452
|
+
### Resources
|
233
453
|
|
234
|
-
The `ModelContextProtocol::Server::Resource` base class allows subclasses to define a resource that the MCP client can use.
|
454
|
+
The `ModelContextProtocol::Server::Resource` base class allows subclasses to define a resource that the MCP client can use.
|
235
455
|
|
236
|
-
|
456
|
+
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.
|
237
457
|
|
238
|
-
|
458
|
+
#### Resource Definition
|
459
|
+
|
460
|
+
Use the `define` block to set [resource properties](https://spec.modelcontextprotocol.io/specification/2025-06-18/server/resources/) and configure annotations.
|
461
|
+
|
462
|
+
| Property | Description |
|
463
|
+
|----------|-------------|
|
464
|
+
| `name` | The name of the resource |
|
465
|
+
| `title` | Human-readable display name |
|
466
|
+
| `description` | Short description of what the resource contains |
|
467
|
+
| `mime_type` | MIME type of the resource content |
|
468
|
+
| `uri` | URI identifier for the resource |
|
469
|
+
| `annotations` | Block for defining resource annotations |
|
470
|
+
|
471
|
+
#### Annotation Definition
|
472
|
+
|
473
|
+
Define any [resource annotations](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#annotations) using an `annotations` block nested within the `define` block.
|
474
|
+
|
475
|
+
| Property | Description |
|
476
|
+
|----------|-------------|
|
477
|
+
| `audience` | Target audience for the resource (array of symbols like `[:user, :assistant]`) |
|
478
|
+
| `priority` | Priority level (numeric value, e.g., `0.9`) |
|
479
|
+
| `last_modified` | Last modified timestamp (ISO 8601 string) |
|
480
|
+
|
481
|
+
#### Resource Methods
|
482
|
+
|
483
|
+
Define your resource properties and annotations, implement the `call` method to build resource content and `respond_with` to serialize the response.
|
484
|
+
|
485
|
+
| Method | Context | Description |
|
486
|
+
|--------|---------|-------------|
|
487
|
+
| `define` | Class definition | Block for defining resource metadata and annotations |
|
488
|
+
| `call` | Instance method | Main method to implement resource logic and build response |
|
489
|
+
| `respond_with` | Within `call` | Return properly formatted response data (e.g., `respond_with text:` or `respond_with binary:`) |
|
490
|
+
|
491
|
+
#### Available Instance Variables
|
492
|
+
|
493
|
+
Resources are stateless and only have access to their configured properties.
|
494
|
+
|
495
|
+
| Variable | Context | Description |
|
496
|
+
|----------|---------|-------------|
|
497
|
+
| `mime_type` | Within `call` | The configured MIME type for this resource |
|
498
|
+
| `uri` | Within `call` | The configured URI identifier for this resource |
|
499
|
+
|
500
|
+
#### Examples
|
239
501
|
|
240
502
|
This is an example resource that returns a text response:
|
241
503
|
|
242
504
|
```ruby
|
243
505
|
class TestResource < ModelContextProtocol::Server::Resource
|
244
|
-
|
506
|
+
define do
|
245
507
|
name "top-secret-plans.txt"
|
508
|
+
title "Top Secret Plans"
|
246
509
|
description "Top secret plans to do top secret things"
|
247
510
|
mime_type "text/plain"
|
248
511
|
uri "file:///top-secret-plans.txt"
|
249
512
|
end
|
250
513
|
|
251
514
|
def call
|
252
|
-
|
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."
|
515
|
+
respond_with text: "I'm finna eat all my wife's leftovers."
|
258
516
|
end
|
517
|
+
end
|
518
|
+
```
|
259
519
|
|
260
|
-
|
520
|
+
This is an example resource with annotations:
|
521
|
+
|
522
|
+
```ruby
|
523
|
+
class TestAnnotatedResource < ModelContextProtocol::Server::Resource
|
524
|
+
define do
|
525
|
+
name "annotated-document.md"
|
526
|
+
description "A document with annotations showing priority and audience"
|
527
|
+
mime_type "text/markdown"
|
528
|
+
uri "file:///docs/annotated-document.md"
|
529
|
+
annotations do
|
530
|
+
audience [:user, :assistant]
|
531
|
+
priority 0.9
|
532
|
+
last_modified "2025-01-12T15:00:58Z"
|
533
|
+
end
|
534
|
+
end
|
261
535
|
|
262
|
-
def
|
263
|
-
|
264
|
-
authorized_users.any?(user_id)
|
536
|
+
def call
|
537
|
+
respond_with text: "# Annotated Document\n\nThis document has annotations."
|
265
538
|
end
|
266
539
|
end
|
267
540
|
```
|
@@ -270,7 +543,7 @@ This is an example resource that returns binary data:
|
|
270
543
|
|
271
544
|
```ruby
|
272
545
|
class TestBinaryResource < ModelContextProtocol::Server::Resource
|
273
|
-
|
546
|
+
define do
|
274
547
|
name "project-logo.png"
|
275
548
|
description "The logo for the project"
|
276
549
|
mime_type "image/png"
|
@@ -281,53 +554,226 @@ class TestBinaryResource < ModelContextProtocol::Server::Resource
|
|
281
554
|
# In a real implementation, we would retrieve the binary resource
|
282
555
|
# This is a small valid base64 encoded string (represents "test")
|
283
556
|
data = "dGVzdA=="
|
284
|
-
respond_with
|
557
|
+
respond_with binary: data
|
285
558
|
end
|
286
559
|
end
|
287
560
|
```
|
288
561
|
|
289
|
-
|
562
|
+
### Resource Templates
|
563
|
+
|
564
|
+
The `ModelContextProtocol::Server::ResourceTemplate` base class allows subclasses to define a resource template that the MCP client can use.
|
565
|
+
|
566
|
+
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
|
+
|
568
|
+
#### Resource Template Definition
|
569
|
+
|
570
|
+
Use the `define` block to set [resource template properties](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#resource-templates).
|
571
|
+
|
572
|
+
| Property | Description |
|
573
|
+
|----------|-------------|
|
574
|
+
| `name` | The name of the resource template |
|
575
|
+
| `description` | Short description of what the template provides |
|
576
|
+
| `mime_type` | MIME type of resources created from this template |
|
577
|
+
| `uri_template` | URI template with parameters (e.g., `"file:///{name}"`) |
|
578
|
+
|
579
|
+
#### URI Template Configuration
|
580
|
+
|
581
|
+
Define the URI template and configure parameter completions within the `uri_template` block.
|
582
|
+
|
583
|
+
| Method | Context | Description |
|
584
|
+
|--------|---------|-------------|
|
585
|
+
| `completion` | Within `uri_template` block | Define completion for a URI parameter (e.g., `completion :name, ["value1", "value2"]`) |
|
290
586
|
|
291
|
-
|
587
|
+
#### Resource Template Methods
|
588
|
+
|
589
|
+
Resource templates only use the `define` method to configure their properties - they don't have a `call` method.
|
590
|
+
|
591
|
+
| Method | Context | Description |
|
592
|
+
|--------|---------|-------------|
|
593
|
+
| `define` | Class definition | Block for defining resource template metadata and URI template |
|
594
|
+
|
595
|
+
#### Examples
|
292
596
|
|
293
597
|
This is an example resource template that provides a completion for a parameter of the URI template:
|
294
598
|
|
295
599
|
```ruby
|
296
600
|
class TestResourceTemplate < ModelContextProtocol::Server::ResourceTemplate
|
297
|
-
|
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
|
601
|
+
define do
|
307
602
|
name "project-document-resource-template"
|
308
603
|
description "A resource template for retrieving project documents"
|
309
604
|
mime_type "text/plain"
|
310
605
|
uri_template "file:///{name}" do
|
311
|
-
completion :name,
|
606
|
+
completion :name, ["top-secret-plans.txt"]
|
312
607
|
end
|
313
608
|
end
|
609
|
+
|
610
|
+
# You can optionally define a custom completion for an argument and pass it to completions.
|
611
|
+
# Completion = ModelContextProtocol::Server::Completion.define do
|
612
|
+
# hints = {
|
613
|
+
# "name" => ["top-secret-plans.txt"]
|
614
|
+
# }
|
615
|
+
# values = hints[argument_name].grep(/#{argument_value}/)
|
616
|
+
|
617
|
+
# respond_with values:
|
618
|
+
# end
|
619
|
+
|
620
|
+
# define do
|
621
|
+
# name "project-document-resource-template"
|
622
|
+
# description "A resource template for retrieving project documents"
|
623
|
+
# mime_type "text/plain"
|
624
|
+
# uri_template "file:///{name}" do
|
625
|
+
# completion :name, Completion
|
626
|
+
# end
|
627
|
+
# end
|
314
628
|
end
|
315
629
|
```
|
316
630
|
|
317
|
-
|
631
|
+
### Tools
|
632
|
+
|
633
|
+
The `ModelContextProtocol::Server::Tool` base class allows subclasses to define a tool that the MCP client can use.
|
634
|
+
|
635
|
+
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
|
+
|
637
|
+
#### Tool Definition
|
638
|
+
|
639
|
+
Use the `define` block to set [tool properties](https://spec.modelcontextprotocol.io/specification/2025-06-18/server/tools/) and configure schemas.
|
640
|
+
|
641
|
+
| Property | Description |
|
642
|
+
|----------|-------------|
|
643
|
+
| `name` | The programmatic name of the tool |
|
644
|
+
| `title` | Human-readable display name |
|
645
|
+
| `description` | Short description of what the tool does |
|
646
|
+
| `input_schema` | JSON schema block for validating tool inputs |
|
647
|
+
| `output_schema` | JSON schema block for validating structured content outputs |
|
648
|
+
|
649
|
+
#### Tool Methods
|
650
|
+
|
651
|
+
Define your tool properties and schemas, implement the `call` method using content helpers and `respond_with` to serialize responses.
|
652
|
+
|
653
|
+
| Method | Context | Description |
|
654
|
+
|--------|---------|-------------|
|
655
|
+
| `define` | Class definition | Block for defining tool metadata and schemas |
|
656
|
+
| `call` | Instance method | Main method to implement tool logic and build response |
|
657
|
+
| `respond_with` | Within `call` | Return properly formatted response data with various content types |
|
658
|
+
|
659
|
+
#### Content Blocks
|
660
|
+
|
661
|
+
Use content blocks to properly format the content included in tool responses.
|
662
|
+
|
663
|
+
| Method | Context | Description |
|
664
|
+
|--------|---------|-------------|
|
665
|
+
| `text_content` | Within `call` | Create text content block |
|
666
|
+
| `image_content` | Within `call` | Create image content block (requires `data:` and `mime_type:`) |
|
667
|
+
| `audio_content` | Within `call` | Create audio content block (requires `data:` and `mime_type:`) |
|
668
|
+
| `embedded_resource_content` | Within `call` | Create embedded resource content block (requires `resource:`) |
|
669
|
+
| `resource_link` | Within `call` | Create resource link content block (requires `name:` and `uri:`) |
|
670
|
+
|
671
|
+
#### Response Types
|
672
|
+
|
673
|
+
Tools can return different types of responses using `respond_with`.
|
674
|
+
|
675
|
+
| Response Type | Usage | Description |
|
676
|
+
|---------------|-------|-------------|
|
677
|
+
| `structured_content:` | `respond_with structured_content: data` | Return structured data validated against output schema |
|
678
|
+
| `content:` | `respond_with content: content_block` | Return single content block |
|
679
|
+
| `content:` | `respond_with content: [content_blocks]` | Return array of mixed content blocks |
|
680
|
+
| `error:` | `respond_with error: "message"` | Return tool error response |
|
681
|
+
|
682
|
+
#### Available Instance Variables
|
683
|
+
|
684
|
+
Arguments from MCP clients and server context are available, along with logging capabilities.
|
685
|
+
|
686
|
+
| Variable | Context | Description |
|
687
|
+
|----------|---------|-------------|
|
688
|
+
| `arguments` | Within `call` | Hash containing client-provided arguments (symbol keys) |
|
689
|
+
| `context` | Within `call` | Hash containing server configuration context values |
|
690
|
+
| `logger` | Within `call` | Logger instance for logging (e.g., `logger.info("message")`) |
|
691
|
+
|
692
|
+
#### Examples
|
693
|
+
|
694
|
+
This is an example of a tool that returns structured content validated by an output schema:
|
318
695
|
|
319
|
-
|
696
|
+
```ruby
|
697
|
+
class TestToolWithStructuredContentResponse < ModelContextProtocol::Server::Tool
|
698
|
+
define do
|
699
|
+
# The name of the tool for programmatic use
|
700
|
+
name "get_weather_data"
|
701
|
+
# The human-readable tool name for display in UI
|
702
|
+
title "Weather Data Retriever"
|
703
|
+
# A short description of what the tool does
|
704
|
+
description "Get current weather data for a location"
|
705
|
+
# The JSON schema for validating tool inputs
|
706
|
+
input_schema do
|
707
|
+
{
|
708
|
+
type: "object",
|
709
|
+
properties: {
|
710
|
+
location: {
|
711
|
+
type: "string",
|
712
|
+
description: "City name or zip code"
|
713
|
+
}
|
714
|
+
},
|
715
|
+
required: ["location"]
|
716
|
+
}
|
717
|
+
end
|
718
|
+
# The JSON schema for validating structured content
|
719
|
+
output_schema do
|
720
|
+
{
|
721
|
+
type: "object",
|
722
|
+
properties: {
|
723
|
+
temperature: {
|
724
|
+
type: "number",
|
725
|
+
description: "Temperature in celsius"
|
726
|
+
},
|
727
|
+
conditions: {
|
728
|
+
type: "string",
|
729
|
+
description: "Weather conditions description"
|
730
|
+
},
|
731
|
+
humidity: {
|
732
|
+
type: "number",
|
733
|
+
description: "Humidity percentage"
|
734
|
+
}
|
735
|
+
},
|
736
|
+
required: ["temperature", "conditions", "humidity"]
|
737
|
+
}
|
738
|
+
end
|
739
|
+
end
|
320
740
|
|
321
|
-
|
741
|
+
def call
|
742
|
+
# Use values provided by the server as context
|
743
|
+
user_id = context[:user_id]
|
744
|
+
logger.info("Initiating request for user #{user_id}...")
|
322
745
|
|
323
|
-
|
746
|
+
# Use values provided by clients as tool arguments
|
747
|
+
location = arguments[:location]
|
748
|
+
logger.info("Getting weather data for #{location}...")
|
749
|
+
|
750
|
+
# Returns a hash that validates against the output schema
|
751
|
+
weather_data = get_weather_data(location)
|
752
|
+
|
753
|
+
# Respond with structured content
|
754
|
+
respond_with structured_content: weather_data
|
755
|
+
end
|
756
|
+
|
757
|
+
private
|
758
|
+
|
759
|
+
# Simulate calling an external API to get weather data for the provided input
|
760
|
+
def get_weather_data(location)
|
761
|
+
{
|
762
|
+
temperature: 22.5,
|
763
|
+
conditions: "Partly cloudy",
|
764
|
+
humidity: 65
|
765
|
+
}
|
766
|
+
end
|
767
|
+
end
|
768
|
+
```
|
324
769
|
|
325
770
|
This is an example tool that returns a text response:
|
326
771
|
|
327
772
|
```ruby
|
328
773
|
class TestToolWithTextResponse < ModelContextProtocol::Server::Tool
|
329
|
-
|
774
|
+
define do
|
330
775
|
name "double"
|
776
|
+
title "Number Doubler"
|
331
777
|
description "Doubles the provided number"
|
332
778
|
input_schema do
|
333
779
|
{
|
@@ -343,12 +789,15 @@ class TestToolWithTextResponse < ModelContextProtocol::Server::Tool
|
|
343
789
|
end
|
344
790
|
|
345
791
|
def call
|
346
|
-
user_id = context[:user_id]
|
347
|
-
number = arguments[:number].to_i
|
348
792
|
logger.info("Silly user doesn't know how to double a number")
|
793
|
+
number = arguments[:number].to_i
|
349
794
|
calculation = number * 2
|
795
|
+
|
796
|
+
user_id = context[:user_id]
|
350
797
|
salutation = user_id ? "User #{user_id}, " : ""
|
351
|
-
|
798
|
+
text_content = text_content(text: salutation << "#{number} doubled is #{calculation}")
|
799
|
+
|
800
|
+
respond_with content: text_content
|
352
801
|
end
|
353
802
|
end
|
354
803
|
```
|
@@ -357,7 +806,7 @@ This is an example of a tool that returns an image:
|
|
357
806
|
|
358
807
|
```ruby
|
359
808
|
class TestToolWithImageResponse < ModelContextProtocol::Server::Tool
|
360
|
-
|
809
|
+
define do
|
361
810
|
name "custom-chart-generator"
|
362
811
|
description "Generates a chart in various formats"
|
363
812
|
input_schema do
|
@@ -391,68 +840,135 @@ class TestToolWithImageResponse < ModelContextProtocol::Server::Tool
|
|
391
840
|
|
392
841
|
# In a real implementation, we would generate an actual chart
|
393
842
|
# This is a small valid base64 encoded string (represents "test")
|
394
|
-
|
395
|
-
|
843
|
+
data = "dGVzdA=="
|
844
|
+
image_content = image_content(data:, mime_type:)
|
845
|
+
respond_with content: image_content
|
396
846
|
end
|
397
847
|
end
|
398
848
|
```
|
399
849
|
|
400
|
-
|
850
|
+
This is an example of a tool that returns an embedded resource response:
|
401
851
|
|
402
852
|
```ruby
|
403
|
-
class
|
404
|
-
|
405
|
-
name "
|
406
|
-
description "
|
853
|
+
class TestToolWithResourceResponse < ModelContextProtocol::Server::Tool
|
854
|
+
define do
|
855
|
+
name "resource-finder"
|
856
|
+
description "Finds a resource given a name"
|
407
857
|
input_schema do
|
408
858
|
{
|
409
859
|
type: "object",
|
410
860
|
properties: {
|
411
|
-
|
861
|
+
name: {
|
412
862
|
type: "string",
|
413
|
-
description: "
|
863
|
+
description: "The name of the resource"
|
414
864
|
}
|
415
865
|
},
|
416
|
-
required: ["
|
866
|
+
required: ["name"]
|
417
867
|
}
|
418
868
|
end
|
419
869
|
end
|
420
870
|
|
871
|
+
RESOURCE_MAPPINGS = {
|
872
|
+
test_annotated_resource: TestAnnotatedResource,
|
873
|
+
test_binary_resource: TestBinaryResource,
|
874
|
+
test_resource: TestResource
|
875
|
+
}.freeze
|
876
|
+
|
421
877
|
def call
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
878
|
+
name = arguments[:name]
|
879
|
+
resource_klass = RESOURCE_MAPPINGS[name.downcase.to_sym]
|
880
|
+
unless resource_klass
|
881
|
+
return respond_with :error, text: "Resource `#{name}` not found"
|
882
|
+
end
|
883
|
+
|
884
|
+
resource_data = resource_klass.call
|
885
|
+
|
886
|
+
respond_with content: embedded_resource_content(resource: resource_data)
|
426
887
|
end
|
427
888
|
end
|
428
889
|
```
|
429
890
|
|
430
|
-
This is an example of a tool that returns
|
891
|
+
This is an example of a tool that returns mixed content:
|
431
892
|
|
432
893
|
```ruby
|
433
|
-
class
|
434
|
-
|
435
|
-
name "
|
436
|
-
description "
|
894
|
+
class TestToolWithMixedContentResponse < ModelContextProtocol::Server::Tool
|
895
|
+
define do
|
896
|
+
name "get_temperature_history"
|
897
|
+
description "Gets comprehensive temperature history for a zip code"
|
898
|
+
input_schema do
|
899
|
+
{
|
900
|
+
type: "object",
|
901
|
+
properties: {
|
902
|
+
zip: {
|
903
|
+
type: "string"
|
904
|
+
}
|
905
|
+
},
|
906
|
+
required: ["zip"]
|
907
|
+
}
|
908
|
+
end
|
909
|
+
end
|
910
|
+
|
911
|
+
def call
|
912
|
+
logger.info("Getting comprehensive temperature history data")
|
913
|
+
|
914
|
+
zip = arguments[:zip]
|
915
|
+
temperature_history = retrieve_temperature_history(zip:)
|
916
|
+
temperature_history_block = text_content(text: temperature_history.join(", "))
|
917
|
+
|
918
|
+
temperature_chart = generate_weather_history_chart(temperature_history)
|
919
|
+
temperature_chart_block = image_content(
|
920
|
+
data: temperature_chart[:base64_chart_data],
|
921
|
+
mime_type: temperature_chart[:mime_type]
|
922
|
+
)
|
923
|
+
|
924
|
+
respond_with content: [temperature_history_block, temperature_chart_block]
|
925
|
+
end
|
926
|
+
|
927
|
+
private
|
928
|
+
|
929
|
+
def retrieve_temperature_history(zip:)
|
930
|
+
# Simulates a call to an API or DB to retrieve weather history
|
931
|
+
[85.2, 87.4, 89.0, 95.3, 96.0]
|
932
|
+
end
|
933
|
+
|
934
|
+
def generate_weather_history_chart(history)
|
935
|
+
# SImulate a call to generate a chart given the weather history
|
936
|
+
{
|
937
|
+
base64_chart_data: "dGVzdA==",
|
938
|
+
mime_type: "image/png"
|
939
|
+
}
|
940
|
+
end
|
941
|
+
end
|
942
|
+
```
|
943
|
+
|
944
|
+
This is an example of a tool that returns a tool error response:
|
945
|
+
|
946
|
+
```ruby
|
947
|
+
class TestToolWithToolErrorResponse < ModelContextProtocol::Server::Tool
|
948
|
+
define do
|
949
|
+
name "api-caller"
|
950
|
+
description "Makes calls to external APIs"
|
437
951
|
input_schema do
|
438
952
|
{
|
439
953
|
type: "object",
|
440
954
|
properties: {
|
441
|
-
|
955
|
+
api_endpoint: {
|
956
|
+
type: "string",
|
957
|
+
description: "API endpoint URL"
|
958
|
+
},
|
959
|
+
method: {
|
442
960
|
type: "string",
|
443
|
-
description: "
|
961
|
+
description: "HTTP method (GET, POST, etc)"
|
444
962
|
}
|
445
963
|
},
|
446
|
-
required: ["
|
964
|
+
required: ["api_endpoint", "method"]
|
447
965
|
}
|
448
966
|
end
|
449
967
|
end
|
450
968
|
|
451
969
|
def call
|
452
|
-
|
453
|
-
|
454
|
-
document = "richtextdata"
|
455
|
-
respond_with :resource, uri: "resource://document/#{title}", text: document, mime_type: "application/rtf"
|
970
|
+
# Simulate an API call failure
|
971
|
+
respond_with error: "Failed to call API at #{arguments[:api_endpoint]}: Connection timed out"
|
456
972
|
end
|
457
973
|
end
|
458
974
|
```
|
@@ -461,7 +977,27 @@ end
|
|
461
977
|
|
462
978
|
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
979
|
|
464
|
-
|
980
|
+
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
|
+
|
982
|
+
#### Completion Methods
|
983
|
+
|
984
|
+
Completions only implement the `call` method to provide completion logic.
|
985
|
+
|
986
|
+
| Method | Context | Description |
|
987
|
+
|--------|---------|-------------|
|
988
|
+
| `call` | Instance method | Main method to implement completion logic and build response |
|
989
|
+
| `respond_with` | Within `call` | Return properly formatted completion response (e.g., `respond_with values:`) |
|
990
|
+
|
991
|
+
#### Available Instance Variables
|
992
|
+
|
993
|
+
Completions receive the argument name and current value being completed.
|
994
|
+
|
995
|
+
| Variable | Context | Description |
|
996
|
+
|----------|---------|-------------|
|
997
|
+
| `argument_name` | Within `call` | String name of the argument being completed |
|
998
|
+
| `argument_value` | Within `call` | Current partial value being typed by the user |
|
999
|
+
|
1000
|
+
#### Examples
|
465
1001
|
|
466
1002
|
This is an example completion that returns an array of values in the response:
|
467
1003
|
|
@@ -500,19 +1036,30 @@ gem install model-context-protocol-rb
|
|
500
1036
|
|
501
1037
|
## Development
|
502
1038
|
|
503
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `
|
1039
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rspec` to run the tests.
|
504
1040
|
|
505
|
-
Generate
|
1041
|
+
Generate executables that you can use for testing:
|
506
1042
|
|
507
1043
|
```bash
|
508
|
-
|
1044
|
+
# generates bin/dev for STDIO transport
|
1045
|
+
bundle exec rake mcp:generate_stdio_server
|
1046
|
+
|
1047
|
+
# generates bin/dev-http for streamable HTTP transport
|
1048
|
+
bundle exec rake mcp:generate_streamable_http_server
|
509
1049
|
```
|
510
1050
|
|
511
|
-
|
1051
|
+
You can also run `bin/console` for an interactive prompt that will allow you to experiment. Execute command `rp` to reload the project.
|
1052
|
+
|
1053
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
1054
|
+
|
1055
|
+
### Releases
|
512
1056
|
|
513
|
-
|
1057
|
+
To release a new version, update the version number in `version.rb`, and submit a PR. After the PR has been merged to main, run `bundle exec rake release`, which will:
|
1058
|
+
* create a git tag for the version,
|
1059
|
+
* push the created tag,
|
1060
|
+
* and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
514
1061
|
|
515
|
-
|
1062
|
+
Then, draft and publish release notes in Github.
|
516
1063
|
|
517
1064
|
## Contributing
|
518
1065
|
|