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.
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/2024-11-05/) in Ruby.
4
-
5
- This SDK is experimental and subject to change. The initial focus is to implement MCP server support with the goal of providing a stable API by version `0.4`. MCP client support will follow.
6
-
7
- You are welcome to contribute.
8
-
9
- TODO's:
10
-
11
- * [Pagination](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/utilities/pagination/)
12
- * [Prompt list changed notifications](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/prompts/#list-changed-notification)
13
- * [Resource list changed notifications](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/resources/#list-changed-notification)
14
- * [Resource subscriptions](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/resources/#subscriptions)
15
- * [Tool list changed notifications](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/tools/#list-changed-notification)
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
- config.name = "MCP Development Server"
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
- # Environment Variables - https://modelcontextprotocol.io/docs/tools/debugging#environment-variables
36
- # Require specific environment variables to be set
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
- # Set environment variables programmatically
103
+ # Optional: set environment variables programmatically
40
104
  config.set_environment_variable("DEBUG_MODE", "true")
41
105
 
42
- # Provide prompts, resources, and tools with contextual variables
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
- ### Transport Configuration
147
+ #### Server Configuration Options
71
148
 
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.
149
+ The following table details all available configuration options for the MCP server:
73
150
 
74
- #### Stdio Transport (Default)
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
- When no transport is specified, the server uses stdio transport, which is suitable for single-process communication:
163
+ #### Pagination Configuration Options
77
164
 
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
165
+ When `pagination` is set to a Hash, the following options are available:
85
166
 
86
- server.start
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
- #### Streamable HTTP Transport
175
+ #### Transport Configuration Options
90
176
 
91
- For distributed deployments with load balancers and multiple server instances, use the streamable HTTP transport with Redis-backed session management:
177
+ The transport configuration supports two types: `:stdio` (default) and `:streamable_http`.
92
178
 
179
+ ##### STDIO Transport
93
180
  ```ruby
94
- require 'redis'
181
+ config.transport = { type: :stdio } # This is the default, can be omitted
182
+ ```
95
183
 
96
- server = ModelContextProtocol::Server.new do |config|
97
- config.name = "MCP Development Server"
98
- config.version = "1.0.0"
184
+ ##### Streamable HTTP Transport
185
+ When using `:streamable_http`, the following options are available:
99
186
 
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
- }
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
- config.registry = ModelContextProtocol::Server::Registry.new
108
- end
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
- # 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: {...}}
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
- **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
225
+ #### Integration with Rails
120
226
 
121
- **Integration Example (Rails):**
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
- class McpController < ApplicationController
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 = "Rails MCP Server"
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
- request: request,
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.registry = build_registry
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
- render json: result[:json], status: result[:status], headers: result[:headers]
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
- 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.
301
+ ### Prompts
145
302
 
146
- ### Server features
303
+ The `ModelContextProtocol::Server::Prompt` base class allows subclasses to define a prompt that the MCP client can use.
147
304
 
148
- #### Prompts
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
- 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.
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
- 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.
309
+ #### Prompt Definition
153
310
 
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.
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
- You can also log from within your prompt by calling a valid logger level method on the `logger` and passing a string message.
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
- 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
-
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
- with_argument do
175
- name "undesirable_activity"
176
- description "The thing to get out of"
177
- required true
178
- end
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
- with_argument do
181
- name "tone"
182
- description "The general tone to be used in the generated excuses"
183
- required false
184
- completion ToneCompletion
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
- respond_with messages: messages
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
- #### Resources
452
+ ### Resources
233
453
 
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.
454
+ The `ModelContextProtocol::Server::Resource` base class allows subclasses to define a resource that the MCP client can use.
235
455
 
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.
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
- You can also log from within your resource by calling a valid logger level method on the `logger` and passing a string message.
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
- with_metadata do
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
- 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."
515
+ respond_with text: "I'm finna eat all my wife's leftovers."
258
516
  end
517
+ end
518
+ ```
259
519
 
260
- private
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 authorized?(user_id)
263
- authorized_users = ["42", "123456"]
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
- with_metadata do
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 :binary, blob: data
557
+ respond_with binary: data
285
558
  end
286
559
  end
287
560
  ```
288
561
 
289
- #### Resource Templates
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
- 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.
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
- 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
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, Completion
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
- #### Tools
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
- 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.
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
- 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.
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
- You can also log from within your tool by calling a valid logger level method on the `logger` and passing a string message.
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
- with_metadata do
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
- respond_with :text, text: salutation << "#{number} doubled is #{calculation}"
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
- with_metadata do
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
- chart_data = "dGVzdA=="
395
- respond_with :image, data: chart_data, mime_type:
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
- If you don't provide a mime type, it will default to `image/png`.
850
+ This is an example of a tool that returns an embedded resource response:
401
851
 
402
852
  ```ruby
403
- class TestToolWithImageResponseDefaultMimeType < ModelContextProtocol::Server::Tool
404
- with_metadata do
405
- name "other-custom-chart-generator"
406
- description "Generates a chart"
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
- chart_type: {
861
+ name: {
412
862
  type: "string",
413
- description: "Type of chart (pie, bar, line)"
863
+ description: "The name of the resource"
414
864
  }
415
865
  },
416
- required: ["chart_type"]
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
- # In a real implementation, we would generate an actual chart
423
- # This is a small valid base64 encoded string (represents "test")
424
- chart_data = "dGVzdA=="
425
- respond_with :image, data: chart_data
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 a resource response:
891
+ This is an example of a tool that returns mixed content:
431
892
 
432
893
  ```ruby
433
- class TestToolWithResourceResponse < ModelContextProtocol::Server::Tool
434
- with_metadata do
435
- name "document-finder"
436
- description "Finds a the document with the given title"
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
- title: {
955
+ api_endpoint: {
956
+ type: "string",
957
+ description: "API endpoint URL"
958
+ },
959
+ method: {
442
960
  type: "string",
443
- description: "The title of the document"
961
+ description: "HTTP method (GET, POST, etc)"
444
962
  }
445
963
  },
446
- required: ["title"]
964
+ required: ["api_endpoint", "method"]
447
965
  }
448
966
  end
449
967
  end
450
968
 
451
969
  def call
452
- title = arguments[:title].downcase
453
- # In a real implementation, we would do a lookup to get the document data
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
- implement the `call` method to build your completion. Use the `respond_with` instance method to ensure your completion responds with appropriately formatted response data.
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 `rake spec` to run the tests.
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 an executable that you can use for testing:
1041
+ Generate executables that you can use for testing:
506
1042
 
507
1043
  ```bash
508
- bundle exec rake mcp:generate_executable
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
- This will generate a `bin/dev` executable you can provide to MCP clients.
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
- You can also run `bin/console` for an interactive prompt that will allow you to experiment.
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
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
1062
+ Then, draft and publish release notes in Github.
516
1063
 
517
1064
  ## Contributing
518
1065