mcp 0.4.0 → 0.11.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/LICENSE +216 -0
- data/README.md +550 -63
- data/lib/json_rpc_handler.rb +171 -0
- data/lib/mcp/annotations.rb +21 -0
- data/lib/mcp/client/http.rb +23 -7
- data/lib/mcp/client/stdio.rb +222 -0
- data/lib/mcp/client.rb +109 -34
- data/lib/mcp/configuration.rb +11 -9
- data/lib/mcp/content.rb +29 -2
- data/lib/mcp/icon.rb +22 -0
- data/lib/mcp/instrumentation.rb +1 -1
- data/lib/mcp/logging_message_notification.rb +30 -0
- data/lib/mcp/methods.rb +3 -0
- data/lib/mcp/progress.rb +24 -0
- data/lib/mcp/prompt/message.rb +1 -1
- data/lib/mcp/prompt/result.rb +1 -1
- data/lib/mcp/prompt.rb +22 -5
- data/lib/mcp/resource/contents.rb +2 -2
- data/lib/mcp/resource/embedded.rb +2 -1
- data/lib/mcp/resource.rb +7 -2
- data/lib/mcp/resource_template.rb +4 -2
- data/lib/mcp/server/transports/stdio_transport.rb +41 -4
- data/lib/mcp/server/transports/streamable_http_transport.rb +456 -85
- data/lib/mcp/server/transports.rb +10 -0
- data/lib/mcp/server.rb +403 -67
- data/lib/mcp/server_context.rb +58 -0
- data/lib/mcp/server_session.rb +107 -0
- data/lib/mcp/string_utils.rb +3 -3
- data/lib/mcp/tool/annotations.rb +1 -1
- data/lib/mcp/tool/input_schema.rb +6 -55
- data/lib/mcp/tool/output_schema.rb +3 -54
- data/lib/mcp/tool/response.rb +1 -1
- data/lib/mcp/tool/schema.rb +48 -0
- data/lib/mcp/tool.rb +39 -5
- data/lib/mcp/transport.rb +15 -2
- data/lib/mcp/version.rb +1 -1
- data/lib/mcp.rb +12 -31
- metadata +21 -42
- data/.gitattributes +0 -4
- data/.github/dependabot.yml +0 -6
- data/.github/workflows/ci.yml +0 -33
- data/.github/workflows/release.yml +0 -25
- data/.gitignore +0 -10
- data/.rubocop.yml +0 -12
- data/AGENTS.md +0 -119
- data/CHANGELOG.md +0 -87
- data/CODE_OF_CONDUCT.md +0 -74
- data/Gemfile +0 -27
- data/LICENSE.txt +0 -21
- data/Rakefile +0 -17
- data/bin/console +0 -15
- data/bin/rake +0 -31
- data/bin/setup +0 -8
- data/dev.yml +0 -31
- data/examples/README.md +0 -197
- data/examples/http_client.rb +0 -184
- data/examples/http_server.rb +0 -170
- data/examples/stdio_server.rb +0 -94
- data/examples/streamable_http_client.rb +0 -203
- data/examples/streamable_http_server.rb +0 -172
- data/mcp.gemspec +0 -32
data/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# MCP Ruby SDK [](https://rubygems.org/gems/mcp) [](https://rubygems.org/gems/mcp) [](https://github.com/modelcontextprotocol/ruby-sdk/blob/main/LICENSE) [](https://github.com/modelcontextprotocol/ruby-sdk/actions/workflows/ci.yml)
|
|
2
2
|
|
|
3
3
|
The official Ruby SDK for Model Context Protocol servers and clients.
|
|
4
4
|
|
|
@@ -38,6 +38,7 @@ It implements the Model Context Protocol specification, handling model context r
|
|
|
38
38
|
- Supports resource registration and retrieval
|
|
39
39
|
- Supports stdio & Streamable HTTP (including SSE) transports
|
|
40
40
|
- Supports notifications for list changes (tools, prompts, resources)
|
|
41
|
+
- Supports sampling (server-to-client LLM completion requests)
|
|
41
42
|
|
|
42
43
|
### Supported Methods
|
|
43
44
|
|
|
@@ -50,6 +51,8 @@ It implements the Model Context Protocol specification, handling model context r
|
|
|
50
51
|
- `resources/list` - Lists all registered resources and their schemas
|
|
51
52
|
- `resources/read` - Retrieves a specific resource by name
|
|
52
53
|
- `resources/templates/list` - Lists all registered resource templates and their schemas
|
|
54
|
+
- `completion/complete` - Returns autocompletion suggestions for prompt arguments and resource URIs
|
|
55
|
+
- `sampling/createMessage` - Requests LLM completion from the client (server-to-client)
|
|
53
56
|
|
|
54
57
|
### Custom Methods
|
|
55
58
|
|
|
@@ -102,17 +105,184 @@ end
|
|
|
102
105
|
- Raises `MCP::Server::MethodAlreadyDefinedError` if trying to override an existing method
|
|
103
106
|
- Supports the same exception reporting and instrumentation as standard methods
|
|
104
107
|
|
|
108
|
+
### Sampling
|
|
109
|
+
|
|
110
|
+
The Model Context Protocol allows servers to request LLM completions from clients through the `sampling/createMessage` method.
|
|
111
|
+
This enables servers to leverage the client's LLM capabilities without needing direct access to AI models.
|
|
112
|
+
|
|
113
|
+
**Key Concepts:**
|
|
114
|
+
|
|
115
|
+
- **Server-to-Client Request**: Unlike typical MCP methods (client→server), sampling is initiated by the server
|
|
116
|
+
- **Client Capability**: Clients must declare `sampling` capability during initialization
|
|
117
|
+
- **Tool Support**: When using tools in sampling requests, clients must declare `sampling.tools` capability
|
|
118
|
+
- **Human-in-the-Loop**: Clients can implement user approval before forwarding requests to LLMs
|
|
119
|
+
|
|
120
|
+
**Usage Example (Stdio transport):**
|
|
121
|
+
|
|
122
|
+
`Server#create_sampling_message` is for single-client transports (e.g., `StdioTransport`).
|
|
123
|
+
For multi-client transports (e.g., `StreamableHTTPTransport`), use `server_context.create_sampling_message` inside tools instead,
|
|
124
|
+
which routes the request to the correct client session.
|
|
125
|
+
|
|
126
|
+
```ruby
|
|
127
|
+
server = MCP::Server.new(name: "my_server")
|
|
128
|
+
transport = MCP::Server::Transports::StdioTransport.new(server)
|
|
129
|
+
server.transport = transport
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Client must declare sampling capability during initialization.
|
|
133
|
+
This happens automatically when the client connects.
|
|
134
|
+
|
|
135
|
+
```ruby
|
|
136
|
+
result = server.create_sampling_message(
|
|
137
|
+
messages: [
|
|
138
|
+
{ role: "user", content: { type: "text", text: "What is the capital of France?" } }
|
|
139
|
+
],
|
|
140
|
+
max_tokens: 100,
|
|
141
|
+
system_prompt: "You are a helpful assistant.",
|
|
142
|
+
temperature: 0.7
|
|
143
|
+
)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Result contains the LLM response:
|
|
147
|
+
|
|
148
|
+
```ruby
|
|
149
|
+
{
|
|
150
|
+
role: "assistant",
|
|
151
|
+
content: { type: "text", text: "The capital of France is Paris." },
|
|
152
|
+
model: "claude-3-sonnet-20240307",
|
|
153
|
+
stopReason: "endTurn"
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Parameters:**
|
|
158
|
+
|
|
159
|
+
Required:
|
|
160
|
+
|
|
161
|
+
- `messages:` (Array) - Array of message objects with `role` and `content`
|
|
162
|
+
- `max_tokens:` (Integer) - Maximum tokens in the response
|
|
163
|
+
|
|
164
|
+
Optional:
|
|
165
|
+
|
|
166
|
+
- `system_prompt:` (String) - System prompt for the LLM
|
|
167
|
+
- `model_preferences:` (Hash) - Model selection preferences (e.g., `{ intelligencePriority: 0.8 }`)
|
|
168
|
+
- `include_context:` (String) - Context inclusion: `"none"`, `"thisServer"`, or `"allServers"` (soft-deprecated)
|
|
169
|
+
- `temperature:` (Float) - Sampling temperature
|
|
170
|
+
- `stop_sequences:` (Array) - Sequences that stop generation
|
|
171
|
+
- `metadata:` (Hash) - Additional metadata
|
|
172
|
+
- `tools:` (Array) - Tools available to the LLM (requires `sampling.tools` capability)
|
|
173
|
+
- `tool_choice:` (Hash) - Tool selection mode (e.g., `{ mode: "auto" }`)
|
|
174
|
+
|
|
175
|
+
**Using Sampling in Tools (works with both Stdio and HTTP transports):**
|
|
176
|
+
|
|
177
|
+
Tools that accept a `server_context:` parameter can call `create_sampling_message` on it.
|
|
178
|
+
The request is automatically routed to the correct client session.
|
|
179
|
+
Set `server.server_context = server` so that `server_context.create_sampling_message` delegates to the server:
|
|
180
|
+
|
|
181
|
+
```ruby
|
|
182
|
+
class SummarizeTool < MCP::Tool
|
|
183
|
+
description "Summarize text using LLM"
|
|
184
|
+
input_schema(
|
|
185
|
+
properties: {
|
|
186
|
+
text: { type: "string" }
|
|
187
|
+
},
|
|
188
|
+
required: ["text"]
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
def self.call(text:, server_context:)
|
|
192
|
+
result = server_context.create_sampling_message(
|
|
193
|
+
messages: [
|
|
194
|
+
{ role: "user", content: { type: "text", text: "Please summarize: #{text}" } }
|
|
195
|
+
],
|
|
196
|
+
max_tokens: 500
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
MCP::Tool::Response.new([{
|
|
200
|
+
type: "text",
|
|
201
|
+
text: result[:content][:text]
|
|
202
|
+
}])
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
server = MCP::Server.new(name: "my_server", tools: [SummarizeTool])
|
|
207
|
+
server.server_context = server
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**Tool Use in Sampling:**
|
|
211
|
+
|
|
212
|
+
When tools are provided in a sampling request, the LLM can call them during generation.
|
|
213
|
+
The server must handle tool calls and continue the conversation with tool results:
|
|
214
|
+
|
|
215
|
+
```ruby
|
|
216
|
+
result = server.create_sampling_message(
|
|
217
|
+
messages: [
|
|
218
|
+
{ role: "user", content: { type: "text", text: "What's the weather in Paris?" } }
|
|
219
|
+
],
|
|
220
|
+
max_tokens: 1000,
|
|
221
|
+
tools: [
|
|
222
|
+
{
|
|
223
|
+
name: "get_weather",
|
|
224
|
+
description: "Get weather for a city",
|
|
225
|
+
inputSchema: {
|
|
226
|
+
type: "object",
|
|
227
|
+
properties: { city: { type: "string" } },
|
|
228
|
+
required: ["city"]
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
],
|
|
232
|
+
tool_choice: { mode: "auto" }
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
if result[:stopReason] == "toolUse"
|
|
236
|
+
tool_results = result[:content].map do |tool_use|
|
|
237
|
+
weather_data = get_weather(tool_use[:input][:city])
|
|
238
|
+
|
|
239
|
+
{
|
|
240
|
+
type: "tool_result",
|
|
241
|
+
toolUseId: tool_use[:id],
|
|
242
|
+
content: [{ type: "text", text: weather_data.to_json }]
|
|
243
|
+
}
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
final_result = server.create_sampling_message(
|
|
247
|
+
messages: [
|
|
248
|
+
{ role: "user", content: { type: "text", text: "What's the weather in Paris?" } },
|
|
249
|
+
{ role: "assistant", content: result[:content] },
|
|
250
|
+
{ role: "user", content: tool_results }
|
|
251
|
+
],
|
|
252
|
+
max_tokens: 1000,
|
|
253
|
+
tools: [...]
|
|
254
|
+
)
|
|
255
|
+
end
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**Error Handling:**
|
|
259
|
+
|
|
260
|
+
- Raises `RuntimeError` if transport is not set
|
|
261
|
+
- Raises `RuntimeError` if client does not support `sampling` capability
|
|
262
|
+
- Raises `RuntimeError` if `tools` are used but client lacks `sampling.tools` capability
|
|
263
|
+
- Raises `StandardError` if client returns an error response
|
|
264
|
+
|
|
105
265
|
### Notifications
|
|
106
266
|
|
|
107
267
|
The server supports sending notifications to clients when lists of tools, prompts, or resources change. This enables real-time updates without polling.
|
|
108
268
|
|
|
109
269
|
#### Notification Methods
|
|
110
270
|
|
|
111
|
-
The server provides
|
|
271
|
+
The server provides the following notification methods:
|
|
112
272
|
|
|
113
273
|
- `notify_tools_list_changed` - Send a notification when the tools list changes
|
|
114
274
|
- `notify_prompts_list_changed` - Send a notification when the prompts list changes
|
|
115
275
|
- `notify_resources_list_changed` - Send a notification when the resources list changes
|
|
276
|
+
- `notify_log_message` - Send a structured logging notification message
|
|
277
|
+
|
|
278
|
+
#### Session Scoping
|
|
279
|
+
|
|
280
|
+
When using Streamable HTTP transport with multiple clients, each client connection gets its own session. Notifications are scoped as follows:
|
|
281
|
+
|
|
282
|
+
- **`report_progress`** and **`notify_log_message`** called via `server_context` inside a tool handler are automatically sent only to the requesting client.
|
|
283
|
+
No extra configuration is needed.
|
|
284
|
+
- **`notify_tools_list_changed`**, **`notify_prompts_list_changed`**, and **`notify_resources_list_changed`** are always broadcast to all connected clients,
|
|
285
|
+
as they represent server-wide state changes. These should be called on the `server` instance directly.
|
|
116
286
|
|
|
117
287
|
#### Notification Format
|
|
118
288
|
|
|
@@ -121,6 +291,179 @@ Notifications follow the JSON-RPC 2.0 specification and use these method names:
|
|
|
121
291
|
- `notifications/tools/list_changed`
|
|
122
292
|
- `notifications/prompts/list_changed`
|
|
123
293
|
- `notifications/resources/list_changed`
|
|
294
|
+
- `notifications/progress`
|
|
295
|
+
- `notifications/message`
|
|
296
|
+
|
|
297
|
+
### Progress
|
|
298
|
+
|
|
299
|
+
The MCP Ruby SDK supports progress tracking for long-running tool operations,
|
|
300
|
+
following the [MCP Progress specification](https://modelcontextprotocol.io/specification/latest/server/utilities/progress).
|
|
301
|
+
|
|
302
|
+
#### How Progress Works
|
|
303
|
+
|
|
304
|
+
1. **Client Request**: The client sends a `progressToken` in the `_meta` field when calling a tool
|
|
305
|
+
2. **Server Notification**: The server sends `notifications/progress` messages back to the client during tool execution
|
|
306
|
+
3. **Tool Integration**: Tools call `server_context.report_progress` to report incremental progress
|
|
307
|
+
|
|
308
|
+
#### Server-Side: Tool with Progress
|
|
309
|
+
|
|
310
|
+
Tools that accept a `server_context:` parameter can call `report_progress` on it.
|
|
311
|
+
The server automatically wraps the context in an `MCP::ServerContext` instance that provides this method:
|
|
312
|
+
|
|
313
|
+
```ruby
|
|
314
|
+
class LongRunningTool < MCP::Tool
|
|
315
|
+
description "A tool that reports progress during execution"
|
|
316
|
+
input_schema(
|
|
317
|
+
properties: {
|
|
318
|
+
count: { type: "integer" },
|
|
319
|
+
},
|
|
320
|
+
required: ["count"]
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
def self.call(count:, server_context:)
|
|
324
|
+
count.times do |i|
|
|
325
|
+
# Do work here.
|
|
326
|
+
server_context.report_progress(i + 1, total: count, message: "Processing item #{i + 1}")
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
MCP::Tool::Response.new([{ type: "text", text: "Done" }])
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
The `server_context.report_progress` method accepts:
|
|
335
|
+
|
|
336
|
+
- `progress` (required) — current progress value (numeric)
|
|
337
|
+
- `total:` (optional) — total expected value, so clients can display a percentage
|
|
338
|
+
- `message:` (optional) — human-readable status message
|
|
339
|
+
|
|
340
|
+
**Key Features:**
|
|
341
|
+
|
|
342
|
+
- Tools report progress via `server_context.report_progress`
|
|
343
|
+
- `report_progress` is a no-op when no `progressToken` was provided by the client
|
|
344
|
+
- Supports both numeric and string progress tokens
|
|
345
|
+
|
|
346
|
+
### Completions
|
|
347
|
+
|
|
348
|
+
MCP spec includes [Completions](https://modelcontextprotocol.io/specification/latest/server/utilities/completion),
|
|
349
|
+
which enable servers to provide autocompletion suggestions for prompt arguments and resource URIs.
|
|
350
|
+
|
|
351
|
+
To enable completions, declare the `completions` capability and register a handler:
|
|
352
|
+
|
|
353
|
+
```ruby
|
|
354
|
+
server = MCP::Server.new(
|
|
355
|
+
name: "my_server",
|
|
356
|
+
prompts: [CodeReviewPrompt],
|
|
357
|
+
resource_templates: [FileTemplate],
|
|
358
|
+
capabilities: { completions: {} },
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
server.completion_handler do |params|
|
|
362
|
+
ref = params[:ref]
|
|
363
|
+
argument = params[:argument]
|
|
364
|
+
value = argument[:value]
|
|
365
|
+
|
|
366
|
+
case ref[:type]
|
|
367
|
+
when "ref/prompt"
|
|
368
|
+
values = case argument[:name]
|
|
369
|
+
when "language"
|
|
370
|
+
["python", "pytorch", "pyside"].select { |v| v.start_with?(value) }
|
|
371
|
+
else
|
|
372
|
+
[]
|
|
373
|
+
end
|
|
374
|
+
{ completion: { values: values, hasMore: false } }
|
|
375
|
+
when "ref/resource"
|
|
376
|
+
{ completion: { values: [], hasMore: false } }
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
The handler receives a `params` hash with:
|
|
382
|
+
|
|
383
|
+
- `ref` - The reference (`{ type: "ref/prompt", name: "..." }` or `{ type: "ref/resource", uri: "..." }`)
|
|
384
|
+
- `argument` - The argument being completed (`{ name: "...", value: "..." }`)
|
|
385
|
+
- `context` (optional) - Previously resolved arguments (`{ arguments: { ... } }`)
|
|
386
|
+
|
|
387
|
+
The handler must return a hash with a `completion` key containing `values` (array of strings), and optionally `total` and `hasMore`.
|
|
388
|
+
The SDK automatically enforces the 100-item limit per the MCP specification.
|
|
389
|
+
|
|
390
|
+
The server validates that the referenced prompt, resource, or resource template is registered before calling the handler.
|
|
391
|
+
Requests for unknown references return an error.
|
|
392
|
+
|
|
393
|
+
### Logging
|
|
394
|
+
|
|
395
|
+
The MCP Ruby SDK supports structured logging through the `notify_log_message` method, following the [MCP Logging specification](https://modelcontextprotocol.io/specification/latest/server/utilities/logging).
|
|
396
|
+
|
|
397
|
+
The `notifications/message` notification is used for structured logging between client and server.
|
|
398
|
+
|
|
399
|
+
#### Log Levels
|
|
400
|
+
|
|
401
|
+
The SDK supports 8 log levels with increasing severity:
|
|
402
|
+
|
|
403
|
+
- `debug` - Detailed debugging information
|
|
404
|
+
- `info` - General informational messages
|
|
405
|
+
- `notice` - Normal but significant events
|
|
406
|
+
- `warning` - Warning conditions
|
|
407
|
+
- `error` - Error conditions
|
|
408
|
+
- `critical` - Critical conditions
|
|
409
|
+
- `alert` - Action must be taken immediately
|
|
410
|
+
- `emergency` - System is unusable
|
|
411
|
+
|
|
412
|
+
#### How Logging Works
|
|
413
|
+
|
|
414
|
+
1. **Client Configuration**: The client sends a `logging/setLevel` request to configure the minimum log level
|
|
415
|
+
2. **Server Filtering**: The server only sends log messages at the configured level or higher severity
|
|
416
|
+
3. **Notification Delivery**: Log messages are sent as `notifications/message` to the client
|
|
417
|
+
|
|
418
|
+
For example, if the client sets the level to `"error"` (severity 4), the server will send messages with levels: `error`, `critical`, `alert`, and `emergency`.
|
|
419
|
+
|
|
420
|
+
For more details, see the [MCP Logging specification](https://modelcontextprotocol.io/specification/latest/server/utilities/logging).
|
|
421
|
+
|
|
422
|
+
**Usage Example:**
|
|
423
|
+
|
|
424
|
+
```ruby
|
|
425
|
+
server = MCP::Server.new(name: "my_server")
|
|
426
|
+
transport = MCP::Server::Transports::StdioTransport.new(server)
|
|
427
|
+
server.transport = transport
|
|
428
|
+
|
|
429
|
+
# The client first configures the logging level (on the client side):
|
|
430
|
+
transport.send_request(
|
|
431
|
+
request: {
|
|
432
|
+
jsonrpc: "2.0",
|
|
433
|
+
method: "logging/setLevel",
|
|
434
|
+
params: { level: "info" },
|
|
435
|
+
id: session_id # Unique request ID within the session
|
|
436
|
+
}
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
# Send log messages at different severity levels
|
|
440
|
+
server.notify_log_message(
|
|
441
|
+
data: { message: "Application started successfully" },
|
|
442
|
+
level: "info"
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
server.notify_log_message(
|
|
446
|
+
data: { message: "Configuration file not found, using defaults" },
|
|
447
|
+
level: "warning"
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
server.notify_log_message(
|
|
451
|
+
data: {
|
|
452
|
+
error: "Database connection failed",
|
|
453
|
+
details: { host: "localhost", port: 5432 }
|
|
454
|
+
},
|
|
455
|
+
level: "error",
|
|
456
|
+
logger: "DatabaseLogger" # Optional logger name
|
|
457
|
+
)
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
**Key Features:**
|
|
461
|
+
|
|
462
|
+
- Supports 8 log levels (debug, info, notice, warning, error, critical, alert, emergency) based on https://modelcontextprotocol.io/specification/2025-06-18/server/utilities/logging#log-levels
|
|
463
|
+
- Server has capability `logging` to send log messages
|
|
464
|
+
- Messages are only sent if a transport is configured
|
|
465
|
+
- Messages are filtered based on the client's configured log level
|
|
466
|
+
- If the log level hasn't been set by the client, no messages will be sent
|
|
124
467
|
|
|
125
468
|
#### Transport Support
|
|
126
469
|
|
|
@@ -131,7 +474,10 @@ Notifications follow the JSON-RPC 2.0 specification and use these method names:
|
|
|
131
474
|
|
|
132
475
|
```ruby
|
|
133
476
|
server = MCP::Server.new(name: "my_server")
|
|
477
|
+
|
|
478
|
+
# Default Streamable HTTP - session oriented
|
|
134
479
|
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server)
|
|
480
|
+
|
|
135
481
|
server.transport = transport
|
|
136
482
|
|
|
137
483
|
# When tools change, notify clients
|
|
@@ -139,35 +485,63 @@ server.define_tool(name: "new_tool") { |**args| { result: "ok" } }
|
|
|
139
485
|
server.notify_tools_list_changed
|
|
140
486
|
```
|
|
141
487
|
|
|
142
|
-
|
|
488
|
+
You can use Stateless Streamable HTTP, where notifications are not supported and all calls are request/response interactions.
|
|
489
|
+
This mode allows for easy multi-node deployment.
|
|
490
|
+
Set `stateless: true` in `MCP::Server::Transports::StreamableHTTPTransport.new` (`stateless` defaults to `false`):
|
|
491
|
+
|
|
492
|
+
```ruby
|
|
493
|
+
# Stateless Streamable HTTP - session-less
|
|
494
|
+
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server, stateless: true)
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
By default, sessions do not expire. To mitigate session hijacking risks, you can set a `session_idle_timeout` (in seconds).
|
|
498
|
+
When configured, sessions that receive no HTTP requests for this duration are automatically expired and cleaned up:
|
|
499
|
+
|
|
500
|
+
```ruby
|
|
501
|
+
# Session timeout of 30 minutes
|
|
502
|
+
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server, session_idle_timeout: 1800)
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### Unsupported Features (to be implemented in future versions)
|
|
143
506
|
|
|
144
|
-
- Log Level
|
|
145
507
|
- Resource subscriptions
|
|
146
|
-
-
|
|
508
|
+
- Elicitation
|
|
147
509
|
|
|
148
510
|
### Usage
|
|
149
511
|
|
|
512
|
+
> [!IMPORTANT]
|
|
513
|
+
> `MCP::Server::Transports::StreamableHTTPTransport` stores session and SSE stream state in memory,
|
|
514
|
+
> so it must run in a single process. Use a single-process server (e.g., Puma with `workers 0`).
|
|
515
|
+
> Multi-process configurations (Unicorn, or Puma with `workers > 0`) fork separate processes that
|
|
516
|
+
> do not share memory, which breaks session management and SSE connections.
|
|
517
|
+
> Stateless mode (`stateless: true`) does not use sessions and works with any server configuration.
|
|
518
|
+
|
|
150
519
|
#### Rails Controller
|
|
151
520
|
|
|
152
521
|
When added to a Rails controller on a route that handles POST requests, your server will be compliant with non-streaming
|
|
153
|
-
[Streamable HTTP](https://modelcontextprotocol.io/specification/
|
|
522
|
+
[Streamable HTTP](https://modelcontextprotocol.io/specification/latest/basic/transports#streamable-http) transport
|
|
154
523
|
requests.
|
|
155
524
|
|
|
156
|
-
You can use
|
|
525
|
+
You can use `StreamableHTTPTransport#handle_request` to handle requests with proper HTTP
|
|
526
|
+
status codes (e.g., 202 Accepted for notifications).
|
|
157
527
|
|
|
158
528
|
```ruby
|
|
159
|
-
class
|
|
160
|
-
def
|
|
529
|
+
class McpController < ActionController::Base
|
|
530
|
+
def create
|
|
161
531
|
server = MCP::Server.new(
|
|
162
532
|
name: "my_server",
|
|
163
|
-
title: "Example Server Display Name",
|
|
533
|
+
title: "Example Server Display Name",
|
|
164
534
|
version: "1.0.0",
|
|
165
535
|
instructions: "Use the tools of this server as a last resort",
|
|
166
536
|
tools: [SomeTool, AnotherTool],
|
|
167
537
|
prompts: [MyPrompt],
|
|
168
538
|
server_context: { user_id: current_user.id },
|
|
169
539
|
)
|
|
170
|
-
|
|
540
|
+
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server)
|
|
541
|
+
server.transport = transport
|
|
542
|
+
status, headers, body = transport.handle_request(request)
|
|
543
|
+
|
|
544
|
+
render(json: body.first, status: status, headers: headers)
|
|
171
545
|
end
|
|
172
546
|
end
|
|
173
547
|
```
|
|
@@ -286,6 +660,50 @@ server = MCP::Server.new(
|
|
|
286
660
|
|
|
287
661
|
This hash is then passed as the `server_context` argument to tool and prompt calls, and is included in exception and instrumentation callbacks.
|
|
288
662
|
|
|
663
|
+
#### Request-specific `_meta` Parameter
|
|
664
|
+
|
|
665
|
+
The MCP protocol supports a special [`_meta` parameter](https://modelcontextprotocol.io/specification/2025-06-18/basic#general-fields) in requests that allows clients to pass request-specific metadata. The server automatically extracts this parameter and makes it available to tools and prompts as a nested field within the `server_context`.
|
|
666
|
+
|
|
667
|
+
**Access Pattern:**
|
|
668
|
+
|
|
669
|
+
When a client includes `_meta` in the request params, it becomes available as `server_context[:_meta]`:
|
|
670
|
+
|
|
671
|
+
```ruby
|
|
672
|
+
class MyTool < MCP::Tool
|
|
673
|
+
def self.call(message:, server_context:)
|
|
674
|
+
# Access provider-specific metadata
|
|
675
|
+
session_id = server_context.dig(:_meta, :session_id)
|
|
676
|
+
request_id = server_context.dig(:_meta, :request_id)
|
|
677
|
+
|
|
678
|
+
# Access server's original context
|
|
679
|
+
user_id = server_context.dig(:user_id)
|
|
680
|
+
|
|
681
|
+
MCP::Tool::Response.new([{
|
|
682
|
+
type: "text",
|
|
683
|
+
text: "Processing for user #{user_id} in session #{session_id}"
|
|
684
|
+
}])
|
|
685
|
+
end
|
|
686
|
+
end
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
**Client Request Example:**
|
|
690
|
+
|
|
691
|
+
```json
|
|
692
|
+
{
|
|
693
|
+
"jsonrpc": "2.0",
|
|
694
|
+
"id": 1,
|
|
695
|
+
"method": "tools/call",
|
|
696
|
+
"params": {
|
|
697
|
+
"name": "my_tool",
|
|
698
|
+
"arguments": { "message": "Hello" },
|
|
699
|
+
"_meta": {
|
|
700
|
+
"session_id": "abc123",
|
|
701
|
+
"request_id": "req_456"
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
```
|
|
706
|
+
|
|
289
707
|
#### Configuration Block Data
|
|
290
708
|
|
|
291
709
|
##### Exception Reporter
|
|
@@ -307,10 +725,16 @@ The instrumentation callback receives a hash with the following possible keys:
|
|
|
307
725
|
|
|
308
726
|
- `method`: (String) The protocol method called (e.g., "ping", "tools/list")
|
|
309
727
|
- `tool_name`: (String, optional) The name of the tool called
|
|
728
|
+
- `tool_arguments`: (Hash, optional) The arguments passed to the tool
|
|
310
729
|
- `prompt_name`: (String, optional) The name of the prompt called
|
|
311
730
|
- `resource_uri`: (String, optional) The URI of the resource called
|
|
312
731
|
- `error`: (String, optional) Error code if a lookup failed
|
|
313
732
|
- `duration`: (Float) Duration of the call in seconds
|
|
733
|
+
- `client`: (Hash, optional) Client information with `name` and `version` keys, from the initialize request
|
|
734
|
+
|
|
735
|
+
> [!NOTE]
|
|
736
|
+
> `tool_name`, `prompt_name` and `resource_uri` are only populated if a matching handler is registered.
|
|
737
|
+
> This is to avoid potential issues with metric cardinality.
|
|
314
738
|
|
|
315
739
|
**Type:**
|
|
316
740
|
|
|
@@ -322,9 +746,11 @@ instrumentation_callback = ->(data) { ... }
|
|
|
322
746
|
**Example:**
|
|
323
747
|
|
|
324
748
|
```ruby
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
}
|
|
749
|
+
MCP.configure do |config|
|
|
750
|
+
config.instrumentation_callback = ->(data) {
|
|
751
|
+
puts "Instrumentation: #{data.inspect}"
|
|
752
|
+
}
|
|
753
|
+
end
|
|
328
754
|
```
|
|
329
755
|
|
|
330
756
|
### Server Protocol Version
|
|
@@ -336,6 +762,9 @@ configuration = MCP::Configuration.new(protocol_version: "2024-11-05")
|
|
|
336
762
|
MCP::Server.new(name: "test_server", configuration: configuration)
|
|
337
763
|
```
|
|
338
764
|
|
|
765
|
+
If no protocol version is specified, the latest stable version will be applied by default.
|
|
766
|
+
The latest stable version includes new features from the [draft version](https://modelcontextprotocol.io/specification/draft).
|
|
767
|
+
|
|
339
768
|
This will make all new server instances use the specified protocol version instead of the default version. The protocol version can be reset to the default by setting it to `nil`:
|
|
340
769
|
|
|
341
770
|
```ruby
|
|
@@ -368,7 +797,7 @@ If no exception reporter is configured, a default no-op reporter is used that si
|
|
|
368
797
|
|
|
369
798
|
### Tools
|
|
370
799
|
|
|
371
|
-
MCP spec includes [Tools](https://modelcontextprotocol.io/specification/
|
|
800
|
+
MCP spec includes [Tools](https://modelcontextprotocol.io/specification/latest/server/tools) which provide functionality to LLM apps.
|
|
372
801
|
|
|
373
802
|
This gem provides a `MCP::Tool` class that can be used to create tools in three ways:
|
|
374
803
|
|
|
@@ -376,7 +805,7 @@ This gem provides a `MCP::Tool` class that can be used to create tools in three
|
|
|
376
805
|
|
|
377
806
|
```ruby
|
|
378
807
|
class MyTool < MCP::Tool
|
|
379
|
-
title "My Tool"
|
|
808
|
+
title "My Tool"
|
|
380
809
|
description "This tool performs specific functionality..."
|
|
381
810
|
input_schema(
|
|
382
811
|
properties: {
|
|
@@ -413,13 +842,13 @@ tool = MyTool
|
|
|
413
842
|
```ruby
|
|
414
843
|
tool = MCP::Tool.define(
|
|
415
844
|
name: "my_tool",
|
|
416
|
-
title: "My Tool",
|
|
845
|
+
title: "My Tool",
|
|
417
846
|
description: "This tool performs specific functionality...",
|
|
418
847
|
annotations: {
|
|
419
848
|
read_only_hint: true,
|
|
420
849
|
title: "My Tool"
|
|
421
850
|
}
|
|
422
|
-
) do |args, server_context
|
|
851
|
+
) do |args, server_context:|
|
|
423
852
|
MCP::Tool::Response.new([{ type: "text", text: "OK" }])
|
|
424
853
|
end
|
|
425
854
|
```
|
|
@@ -435,7 +864,7 @@ server.define_tool(
|
|
|
435
864
|
title: "My Tool",
|
|
436
865
|
read_only_hint: true
|
|
437
866
|
}
|
|
438
|
-
) do |args, server_context
|
|
867
|
+
) do |args, server_context:|
|
|
439
868
|
Tool::Response.new([{ type: "text", text: "OK" }])
|
|
440
869
|
end
|
|
441
870
|
```
|
|
@@ -525,7 +954,7 @@ tool = MCP::Tool.define(
|
|
|
525
954
|
},
|
|
526
955
|
required: ["mean", "median", "count"]
|
|
527
956
|
}
|
|
528
|
-
) do |args, server_context
|
|
957
|
+
) do |args, server_context:|
|
|
529
958
|
# Calculate statistics and validate against schema
|
|
530
959
|
MCP::Tool::Response.new([{ type: "text", text: "Statistics calculated" }])
|
|
531
960
|
end
|
|
@@ -551,7 +980,7 @@ Output schema may also describe an array of objects:
|
|
|
551
980
|
class WeatherTool < MCP::Tool
|
|
552
981
|
output_schema(
|
|
553
982
|
type: "array",
|
|
554
|
-
|
|
983
|
+
items: {
|
|
555
984
|
properties: {
|
|
556
985
|
temperature: { type: "number" },
|
|
557
986
|
condition: { type: "string" },
|
|
@@ -566,7 +995,7 @@ end
|
|
|
566
995
|
Please note: in this case, you must provide `type: "array"`. The default type
|
|
567
996
|
for output schemas is `object`.
|
|
568
997
|
|
|
569
|
-
MCP spec for the [Output Schema](https://modelcontextprotocol.io/specification/
|
|
998
|
+
MCP spec for the [Output Schema](https://modelcontextprotocol.io/specification/latest/server/tools#output-schema) specifies that:
|
|
570
999
|
|
|
571
1000
|
- **Server Validation**: Servers MUST provide structured results that conform to the output schema
|
|
572
1001
|
- **Client Validation**: Clients SHOULD validate structured results against the output schema
|
|
@@ -582,10 +1011,10 @@ Tools can return structured data alongside text content using the `structured_co
|
|
|
582
1011
|
The structured content will be included in the JSON-RPC response as the `structuredContent` field.
|
|
583
1012
|
|
|
584
1013
|
```ruby
|
|
585
|
-
class
|
|
1014
|
+
class WeatherTool < MCP::Tool
|
|
586
1015
|
description "Get current weather and return structured data"
|
|
587
1016
|
|
|
588
|
-
def self.call(
|
|
1017
|
+
def self.call(location:, units: "celsius", server_context:)
|
|
589
1018
|
# Call weather API and structure the response
|
|
590
1019
|
api_response = WeatherAPI.fetch(location, units)
|
|
591
1020
|
weather_data = {
|
|
@@ -607,9 +1036,35 @@ class APITool < MCP::Tool
|
|
|
607
1036
|
end
|
|
608
1037
|
```
|
|
609
1038
|
|
|
1039
|
+
### Tool Responses with Errors
|
|
1040
|
+
|
|
1041
|
+
Tools can return error information alongside text content using the `error` parameter.
|
|
1042
|
+
|
|
1043
|
+
The error will be included in the JSON-RPC response as the `isError` field.
|
|
1044
|
+
|
|
1045
|
+
```ruby
|
|
1046
|
+
class WeatherTool < MCP::Tool
|
|
1047
|
+
description "Get current weather and return structured data"
|
|
1048
|
+
|
|
1049
|
+
def self.call(server_context:)
|
|
1050
|
+
# Do something here
|
|
1051
|
+
content = {}
|
|
1052
|
+
|
|
1053
|
+
MCP::Tool::Response.new(
|
|
1054
|
+
[{
|
|
1055
|
+
type: "text",
|
|
1056
|
+
text: content.to_json
|
|
1057
|
+
}],
|
|
1058
|
+
structured_content: content,
|
|
1059
|
+
error: true
|
|
1060
|
+
)
|
|
1061
|
+
end
|
|
1062
|
+
end
|
|
1063
|
+
```
|
|
1064
|
+
|
|
610
1065
|
### Prompts
|
|
611
1066
|
|
|
612
|
-
MCP spec includes [Prompts](https://modelcontextprotocol.io/specification/
|
|
1067
|
+
MCP spec includes [Prompts](https://modelcontextprotocol.io/specification/latest/server/prompts), which enable servers to define reusable prompt templates and workflows that clients can easily surface to users and LLMs.
|
|
613
1068
|
|
|
614
1069
|
The `MCP::Prompt` class provides three ways to create prompts:
|
|
615
1070
|
|
|
@@ -618,7 +1073,7 @@ The `MCP::Prompt` class provides three ways to create prompts:
|
|
|
618
1073
|
```ruby
|
|
619
1074
|
class MyPrompt < MCP::Prompt
|
|
620
1075
|
prompt_name "my_prompt" # Optional - defaults to underscored class name
|
|
621
|
-
title "My Prompt"
|
|
1076
|
+
title "My Prompt"
|
|
622
1077
|
description "This prompt performs specific functionality..."
|
|
623
1078
|
arguments [
|
|
624
1079
|
MCP::Prompt::Argument.new(
|
|
@@ -657,7 +1112,7 @@ prompt = MyPrompt
|
|
|
657
1112
|
```ruby
|
|
658
1113
|
prompt = MCP::Prompt.define(
|
|
659
1114
|
name: "my_prompt",
|
|
660
|
-
title: "My Prompt",
|
|
1115
|
+
title: "My Prompt",
|
|
661
1116
|
description: "This prompt performs specific functionality...",
|
|
662
1117
|
arguments: [
|
|
663
1118
|
MCP::Prompt::Argument.new(
|
|
@@ -745,34 +1200,9 @@ The server will handle prompt listing and execution through the MCP protocol met
|
|
|
745
1200
|
- `prompts/list` - Lists all registered prompts and their schemas
|
|
746
1201
|
- `prompts/get` - Retrieves and executes a specific prompt with arguments
|
|
747
1202
|
|
|
748
|
-
### Instrumentation
|
|
749
|
-
|
|
750
|
-
The server allows registering a callback to receive information about instrumentation.
|
|
751
|
-
To register a handler pass a proc/lambda to as `instrumentation_callback` into the server constructor.
|
|
752
|
-
|
|
753
|
-
```ruby
|
|
754
|
-
MCP.configure do |config|
|
|
755
|
-
config.instrumentation_callback = ->(data) {
|
|
756
|
-
puts "Got instrumentation data #{data.inspect}"
|
|
757
|
-
}
|
|
758
|
-
end
|
|
759
|
-
```
|
|
760
|
-
|
|
761
|
-
The data contains the following keys:
|
|
762
|
-
|
|
763
|
-
- `method`: the method called, e.g. `ping`, `tools/list`, `tools/call` etc
|
|
764
|
-
- `tool_name`: the name of the tool called
|
|
765
|
-
- `prompt_name`: the name of the prompt called
|
|
766
|
-
- `resource_uri`: the uri of the resource called
|
|
767
|
-
- `error`: if looking up tools/prompts etc failed, e.g. `tool_not_found`
|
|
768
|
-
- `duration`: the duration of the call in seconds
|
|
769
|
-
|
|
770
|
-
`tool_name`, `prompt_name` and `resource_uri` are only populated if a matching handler is registered.
|
|
771
|
-
This is to avoid potential issues with metric cardinality
|
|
772
|
-
|
|
773
1203
|
### Resources
|
|
774
1204
|
|
|
775
|
-
MCP spec includes [Resources](https://modelcontextprotocol.io/specification/
|
|
1205
|
+
MCP spec includes [Resources](https://modelcontextprotocol.io/specification/latest/server/resources).
|
|
776
1206
|
|
|
777
1207
|
### Reading Resources
|
|
778
1208
|
|
|
@@ -782,7 +1212,7 @@ The `MCP::Resource` class provides a way to register resources with the server.
|
|
|
782
1212
|
resource = MCP::Resource.new(
|
|
783
1213
|
uri: "https://example.com/my_resource",
|
|
784
1214
|
name: "my-resource",
|
|
785
|
-
title: "My Resource",
|
|
1215
|
+
title: "My Resource",
|
|
786
1216
|
description: "Lorem ipsum dolor sit amet",
|
|
787
1217
|
mime_type: "text/html",
|
|
788
1218
|
)
|
|
@@ -815,7 +1245,7 @@ The `MCP::ResourceTemplate` class provides a way to register resource templates
|
|
|
815
1245
|
resource_template = MCP::ResourceTemplate.new(
|
|
816
1246
|
uri_template: "https://example.com/my_resource_template",
|
|
817
1247
|
name: "my-resource-template",
|
|
818
|
-
title: "My Resource Template",
|
|
1248
|
+
title: "My Resource Template",
|
|
819
1249
|
description: "Lorem ipsum dolor sit amet",
|
|
820
1250
|
mime_type: "text/html",
|
|
821
1251
|
)
|
|
@@ -835,7 +1265,11 @@ This class supports:
|
|
|
835
1265
|
- Tool listing via the `tools/list` method (`MCP::Client#tools`)
|
|
836
1266
|
- Tool invocation via the `tools/call` method (`MCP::Client#call_tools`)
|
|
837
1267
|
- Resource listing via the `resources/list` method (`MCP::Client#resources`)
|
|
1268
|
+
- Resource template listing via the `resources/templates/list` method (`MCP::Client#resource_templates`)
|
|
838
1269
|
- Resource reading via the `resources/read` method (`MCP::Client#read_resources`)
|
|
1270
|
+
- Prompt listing via the `prompts/list` method (`MCP::Client#prompts`)
|
|
1271
|
+
- Prompt retrieval via the `prompts/get` method (`MCP::Client#get_prompt`)
|
|
1272
|
+
- Completion requests via the `completion/complete` method (`MCP::Client#complete`)
|
|
839
1273
|
- Automatic JSON-RPC 2.0 message formatting
|
|
840
1274
|
- UUID request ID generation
|
|
841
1275
|
|
|
@@ -864,6 +1298,52 @@ class CustomTransport
|
|
|
864
1298
|
end
|
|
865
1299
|
```
|
|
866
1300
|
|
|
1301
|
+
### Stdio Transport Layer
|
|
1302
|
+
|
|
1303
|
+
Use the `MCP::Client::Stdio` transport to interact with MCP servers running as subprocesses over standard input/output.
|
|
1304
|
+
|
|
1305
|
+
`MCP::Client::Stdio.new` accepts the following keyword arguments:
|
|
1306
|
+
|
|
1307
|
+
| Parameter | Required | Description |
|
|
1308
|
+
|---|---|---|
|
|
1309
|
+
| `command:` | Yes | The command to spawn the server process (e.g., `"ruby"`, `"bundle"`, `"npx"`). |
|
|
1310
|
+
| `args:` | No | An array of arguments passed to the command. Defaults to `[]`. |
|
|
1311
|
+
| `env:` | No | A hash of environment variables to set for the server process. Defaults to `nil`. |
|
|
1312
|
+
| `read_timeout:` | No | Timeout in seconds for waiting for a server response. Defaults to `nil` (no timeout). |
|
|
1313
|
+
|
|
1314
|
+
Example usage:
|
|
1315
|
+
|
|
1316
|
+
```ruby
|
|
1317
|
+
stdio_transport = MCP::Client::Stdio.new(
|
|
1318
|
+
command: "bundle",
|
|
1319
|
+
args: ["exec", "ruby", "path/to/server.rb"],
|
|
1320
|
+
env: { "API_KEY" => "my_secret_key" },
|
|
1321
|
+
read_timeout: 30
|
|
1322
|
+
)
|
|
1323
|
+
client = MCP::Client.new(transport: stdio_transport)
|
|
1324
|
+
|
|
1325
|
+
# List available tools.
|
|
1326
|
+
tools = client.tools
|
|
1327
|
+
tools.each do |tool|
|
|
1328
|
+
puts "Tool: #{tool.name} - #{tool.description}"
|
|
1329
|
+
end
|
|
1330
|
+
|
|
1331
|
+
# Call a specific tool.
|
|
1332
|
+
response = client.call_tool(
|
|
1333
|
+
tool: tools.first,
|
|
1334
|
+
arguments: { message: "Hello, world!" }
|
|
1335
|
+
)
|
|
1336
|
+
|
|
1337
|
+
# Close the transport when done.
|
|
1338
|
+
stdio_transport.close
|
|
1339
|
+
```
|
|
1340
|
+
|
|
1341
|
+
The stdio transport automatically handles:
|
|
1342
|
+
|
|
1343
|
+
- Spawning the server process with `Open3.popen3`
|
|
1344
|
+
- MCP protocol initialization handshake (`initialize` request + `notifications/initialized`)
|
|
1345
|
+
- JSON-RPC 2.0 message framing over newline-delimited JSON
|
|
1346
|
+
|
|
867
1347
|
### HTTP Transport Layer
|
|
868
1348
|
|
|
869
1349
|
Use the `MCP::Client::HTTP` transport to interact with MCP servers using simple HTTP requests.
|
|
@@ -896,8 +1376,17 @@ response = client.call_tool(
|
|
|
896
1376
|
tool: tools.first,
|
|
897
1377
|
arguments: { message: "Hello, world!" }
|
|
898
1378
|
)
|
|
1379
|
+
|
|
1380
|
+
# Call a tool with progress tracking.
|
|
1381
|
+
response = client.call_tool(
|
|
1382
|
+
tool: tools.first,
|
|
1383
|
+
arguments: { count: 10 },
|
|
1384
|
+
progress_token: "my-progress-token"
|
|
1385
|
+
)
|
|
899
1386
|
```
|
|
900
1387
|
|
|
1388
|
+
The server will send `notifications/progress` back to the client during execution.
|
|
1389
|
+
|
|
901
1390
|
#### HTTP Authorization
|
|
902
1391
|
|
|
903
1392
|
By default, the HTTP transport layer provides no authentication to the server, but you can provide custom headers if you need authentication. For example, to use Bearer token authentication:
|
|
@@ -924,15 +1413,13 @@ The client provides a wrapper class for tools returned by the server:
|
|
|
924
1413
|
|
|
925
1414
|
This class provides easy access to tool properties like name, description, input schema, and output schema.
|
|
926
1415
|
|
|
927
|
-
##
|
|
1416
|
+
## Conformance Testing
|
|
928
1417
|
|
|
929
|
-
|
|
1418
|
+
The `conformance/` directory contains a test server and runner that validate the SDK against the MCP specification using [`@modelcontextprotocol/conformance`](https://github.com/modelcontextprotocol/conformance).
|
|
930
1419
|
|
|
931
|
-
|
|
1420
|
+
See [conformance/README.md](conformance/README.md) for usage instructions.
|
|
932
1421
|
|
|
933
|
-
|
|
934
|
-
1. **Update CHANGELOG.md**, backfilling the changes since the last release if necessary, and adding a new section for the new version, clearing out the Unreleased section
|
|
935
|
-
1. **Create a PR and get approval from a maintainer**
|
|
936
|
-
1. **Merge your PR to the main branch** - This will automatically trigger the release workflow via GitHub Actions
|
|
1422
|
+
## Documentation
|
|
937
1423
|
|
|
938
|
-
|
|
1424
|
+
- [SDK API documentation](https://rubydoc.info/gems/mcp)
|
|
1425
|
+
- [Model Context Protocol documentation](https://modelcontextprotocol.io)
|