mcp 0.3.0 → 0.5.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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +6 -0
  3. data/.github/workflows/ci.yml +22 -7
  4. data/.github/workflows/release.yml +34 -2
  5. data/.rubocop.yml +3 -0
  6. data/AGENTS.md +107 -0
  7. data/CHANGELOG.md +58 -0
  8. data/Gemfile +6 -4
  9. data/README.md +135 -39
  10. data/RELEASE.md +12 -0
  11. data/bin/generate-gh-pages.sh +119 -0
  12. data/dev.yml +1 -2
  13. data/docs/_config.yml +6 -0
  14. data/docs/index.md +7 -0
  15. data/docs/latest/index.html +19 -0
  16. data/examples/http_server.rb +0 -2
  17. data/examples/stdio_server.rb +0 -1
  18. data/examples/streamable_http_server.rb +0 -2
  19. data/lib/json_rpc_handler.rb +151 -0
  20. data/lib/mcp/client/http.rb +23 -7
  21. data/lib/mcp/client.rb +62 -5
  22. data/lib/mcp/configuration.rb +38 -14
  23. data/lib/mcp/content.rb +2 -3
  24. data/lib/mcp/icon.rb +22 -0
  25. data/lib/mcp/instrumentation.rb +1 -1
  26. data/lib/mcp/methods.rb +3 -0
  27. data/lib/mcp/prompt/argument.rb +9 -5
  28. data/lib/mcp/prompt/message.rb +1 -2
  29. data/lib/mcp/prompt/result.rb +1 -2
  30. data/lib/mcp/prompt.rb +32 -4
  31. data/lib/mcp/resource/contents.rb +1 -2
  32. data/lib/mcp/resource/embedded.rb +1 -2
  33. data/lib/mcp/resource.rb +4 -3
  34. data/lib/mcp/resource_template.rb +4 -3
  35. data/lib/mcp/server/transports/streamable_http_transport.rb +96 -18
  36. data/lib/mcp/server.rb +92 -26
  37. data/lib/mcp/string_utils.rb +3 -4
  38. data/lib/mcp/tool/annotations.rb +1 -1
  39. data/lib/mcp/tool/input_schema.rb +6 -52
  40. data/lib/mcp/tool/output_schema.rb +3 -51
  41. data/lib/mcp/tool/response.rb +5 -4
  42. data/lib/mcp/tool/schema.rb +65 -0
  43. data/lib/mcp/tool.rb +47 -8
  44. data/lib/mcp/version.rb +1 -1
  45. data/lib/mcp.rb +2 -0
  46. data/mcp.gemspec +5 -2
  47. metadata +16 -18
  48. data/.cursor/rules/release-changelogs.mdc +0 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 984645dda3d0d04a93b2831354691c475b42d2826462156167a3f1e1104b85d0
4
- data.tar.gz: 20f96310129418791e0f5ae7f11b8a67605ff82e7ad29dfdfc414fd24157cf97
3
+ metadata.gz: fa42259e96ff9b07eb17a7e65ec9ca1324a1cce6f969295a4cb452872302aee9
4
+ data.tar.gz: f353de6d9331617ae6bf14f559b6de94e45885ce16feabbb23f65996dc8a850f
5
5
  SHA512:
6
- metadata.gz: e9c323d818625f25999d1a2bb7ed1f16783cc295f8676c47bb58a96c284da133a2a5cc5c17086bc72216783325317543031288f1f8f804165503286ec0b1d2e8
7
- data.tar.gz: f0b2c995f44682257a642316c6df3aa20bde04db6de92842e35b323460238860890d3e197cc916ec68f96a57f8c24f12877805fc14b8fd27e46999bf4b3d2aa4
6
+ metadata.gz: 7b19b451b27926590498eb8320088cf8737c8b20e1897088f7a033e33fa8fec976c88c89e80d9e78d96202ae142e02c1698cc6ece52e9240085ad25b7fd5d4ac
7
+ data.tar.gz: 88f67864aecba8e4b475a53ba49a8651a10f8909c3c7e07138603ce4ea2c489580856494519a7cc6e7e6803e47bb99c38ae32a7802cb11fa268b5c18f9c40cb3
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: 'github-actions'
4
+ directory: '/'
5
+ schedule:
6
+ interval: 'weekly'
@@ -7,13 +7,17 @@ jobs:
7
7
  strategy:
8
8
  matrix:
9
9
  entry:
10
- - { ruby: 3.2, allowed-failure: false }
11
- - { ruby: 3.3, allowed-failure: false }
12
- - { ruby: 3.4, allowed-failure: false }
13
- - { ruby: head, allowed-failure: true }
10
+ - { ruby: '2.7', allowed-failure: false }
11
+ - { ruby: '3.0', allowed-failure: false }
12
+ - { ruby: '3.1', allowed-failure: false }
13
+ - { ruby: '3.2', allowed-failure: false }
14
+ - { ruby: '3.3', allowed-failure: false }
15
+ - { ruby: '3.4', allowed-failure: false }
16
+ - { ruby: '4.0', allowed-failure: false }
17
+ - { ruby: 'head', allowed-failure: true }
14
18
  name: Test Ruby ${{ matrix.entry.ruby }}
15
19
  steps:
16
- - uses: actions/checkout@v3
20
+ - uses: actions/checkout@v6
17
21
  - uses: ruby/setup-ruby@v1
18
22
  with:
19
23
  ruby-version: ${{ matrix.entry.ruby }}
@@ -25,9 +29,20 @@ jobs:
25
29
  runs-on: ubuntu-latest
26
30
  name: RuboCop
27
31
  steps:
28
- - uses: actions/checkout@v3
32
+ - uses: actions/checkout@v6
29
33
  - uses: ruby/setup-ruby@v1
30
34
  with:
31
- ruby-version: 3.2 # Specify the oldest supported Ruby version.
35
+ ruby-version: 4.0 # Specify the latest supported Ruby version.
32
36
  bundler-cache: true
33
37
  - run: bundle exec rake rubocop
38
+
39
+ yard:
40
+ runs-on: ubuntu-latest
41
+ name: YARD Documentation
42
+ steps:
43
+ - uses: actions/checkout@v6
44
+ - uses: ruby/setup-ruby@v1
45
+ with:
46
+ ruby-version: 4.0 # Specify the latest supported Ruby version.
47
+ bundler-cache: true
48
+ - run: bundle exec yard --no-output
@@ -16,10 +16,42 @@ jobs:
16
16
  id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
17
17
  contents: write # IMPORTANT: this permission is required for `rake release` to push the release tag
18
18
  steps:
19
- - uses: actions/checkout@v4
19
+ - uses: actions/checkout@v6
20
20
  - name: Set up Ruby
21
21
  uses: ruby/setup-ruby@v1
22
22
  with:
23
23
  bundler-cache: true
24
- ruby-version: 3.4
24
+ ruby-version: 4.0
25
25
  - uses: rubygems/release-gem@v1
26
+
27
+ publish_gh_pages:
28
+ if: github.repository_owner == 'modelcontextprotocol'
29
+ name: Publish Documentation to GitHub Pages
30
+ runs-on: ubuntu-latest
31
+ needs: [publish_gem]
32
+
33
+ permissions:
34
+ contents: write
35
+
36
+ steps:
37
+ - uses: actions/checkout@v6
38
+ with:
39
+ fetch-depth: 0 # Fetch all history for all branches and tags
40
+
41
+ - name: Configure Git
42
+ run: |
43
+ git config --global user.name "github-actions[bot]"
44
+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
45
+
46
+ - name: Get version tag
47
+ id: version
48
+ run: |
49
+ git fetch --tags
50
+ TAG=$(git describe --tags --exact-match HEAD)
51
+ echo "tag=${TAG}" >> $GITHUB_OUTPUT
52
+
53
+ - name: Generate GitHub Pages
54
+ run: ./bin/generate-gh-pages.sh ${{ steps.version.outputs.tag }}
55
+
56
+ - name: Push to gh-pages
57
+ run: git push origin gh-pages
data/.rubocop.yml CHANGED
@@ -5,6 +5,9 @@ plugins:
5
5
  - rubocop-minitest
6
6
  - rubocop-rake
7
7
 
8
+ AllCops:
9
+ TargetRubyVersion: 2.7
10
+
8
11
  Gemspec/DevelopmentDependencies:
9
12
  Enabled: true
10
13
 
data/AGENTS.md ADDED
@@ -0,0 +1,107 @@
1
+ # AGENTS.md
2
+
3
+ ## Project overview
4
+
5
+ This is the official Ruby SDK for the Model Context Protocol (MCP), implementing both server and client functionality for JSON-RPC 2.0 based communication between LLM applications and context providers.
6
+
7
+ ## Dev environment setup
8
+
9
+ - Ruby 3.2.0+ required to run the full test suite, including all Sorbet-related features
10
+ - Run `bundle install` to install dependencies
11
+ - Dependencies: `json-schema` >= 4.1 - Schema validation
12
+
13
+ ## Build and test commands
14
+
15
+ - `bundle install` - Install dependencies
16
+ - `rake test` - Run all tests
17
+ - `rake rubocop` - Run linter
18
+ - `rake` - Run tests and linting (default task)
19
+ - `ruby -I lib -I test test/path/to/specific_test.rb` - Run single test file
20
+ - `gem build mcp.gemspec` - Build the gem
21
+
22
+ ## Testing instructions
23
+
24
+ - Test files are in `test/` directory with `_test.rb` suffix
25
+ - Run full test suite with `rake test`
26
+ - Run individual tests with `ruby -I lib -I test test/path/to/file_test.rb`
27
+ - Tests should pass before submitting PRs
28
+
29
+ ## Code style guidelines
30
+
31
+ - Follow RuboCop rules (run `rake rubocop`)
32
+ - Use frozen string literals
33
+ - Follow Ruby community conventions
34
+ - Keep dependencies minimal
35
+
36
+ ## Commit message conventions
37
+
38
+ - Use conventional commit format when possible
39
+ - Include clear, descriptive commit messages
40
+ - Releases are triggered by updating version in `lib/mcp/version.rb` and merging to main
41
+
42
+ ## Release process
43
+
44
+ - Follow [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) format in CHANGELOG.md
45
+ - Update CHANGELOG.md before cutting releases
46
+ - Use git history and PR merge commits to construct changelog entries
47
+ - Format entries as: "Terse description of the change (#nnn)"
48
+ - Keep entries in flat list format (no nesting)
49
+ - Git tags mark commits that cut new releases
50
+ - Exclude maintenance PRs that don't concern end users
51
+ - Check upstream remote for PRs if available
52
+
53
+ ## Architecture overview
54
+
55
+ ### Core Components
56
+
57
+ **MCP::Server** (`lib/mcp/server.rb`):
58
+
59
+ - Main server class handling JSON-RPC requests
60
+ - Implements MCP protocol methods: initialize, ping, tools/list, tools/call, prompts/list, prompts/get, resources/list, resources/read
61
+ - Supports custom method registration via `define_custom_method`
62
+ - Handles instrumentation, exception reporting, and notifications
63
+ - Uses JsonRpcHandler for request processing
64
+
65
+ **MCP::Client** (`lib/mcp/client.rb`):
66
+
67
+ - Client interface for communicating with MCP servers
68
+ - Transport-agnostic design with pluggable transport layers
69
+ - Supports tool listing and invocation
70
+
71
+ **Transport Layer**:
72
+
73
+ - `MCP::Server::Transports::StdioTransport` - Command-line stdio transport
74
+ - `MCP::Server::Transports::StreamableHttpTransport` - HTTP with streaming support
75
+ - `MCP::Client::HTTP` - HTTP client transport (requires faraday gem)
76
+
77
+ **Protocol Components**:
78
+
79
+ - `MCP::Tool` - Tool definition with input/output schemas and annotations
80
+ - `MCP::Prompt` - Prompt templates with argument validation
81
+ - `MCP::Resource` - Resource registration and retrieval
82
+ - `MCP::Configuration` - Global configuration with exception reporting and instrumentation
83
+
84
+ ### Key Patterns
85
+
86
+ **Three Ways to Define Components**:
87
+
88
+ 1. Class inheritance (e.g., `class MyTool < MCP::Tool`)
89
+ 2. Define methods (e.g., `MCP::Tool.define(name: "my_tool") { ... }`)
90
+ 3. Server registration (e.g., `server.define_tool(name: "my_tool") { ... }`)
91
+
92
+ **Schema Validation**:
93
+
94
+ - Tools support input_schema and output_schema for JSON Schema validation
95
+ - Protocol version 2025-03-26+ supports tool annotations (destructive_hint, idempotent_hint, etc.)
96
+ - Validation is configurable via `configuration.validate_tool_call_arguments`
97
+
98
+ **Context Passing**:
99
+
100
+ - `server_context` hash passed through tool/prompt calls for request-specific data
101
+ - Methods can accept `server_context:` keyword argument for accessing context
102
+
103
+ ### Integration patterns
104
+
105
+ - **Rails controllers**: Use `server.handle_json(request.body.read)` for HTTP endpoints
106
+ - **Command-line tools**: Use `StdioTransport.new(server).open` for CLI applications
107
+ - **HTTP services**: Use `StreamableHttpTransport` for web-based servers
data/CHANGELOG.md CHANGED
@@ -7,6 +7,64 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.5.0] - 2026-01-11
11
+
12
+ ### Added
13
+
14
+ - Protocol specification version "2025-11-25" support (#184)
15
+ - `icons` parameter support (#205)
16
+ - `websiteUrl` parameter in `serverInfo` (#188)
17
+ - `description` parameter in `serverInfo` (#201)
18
+ - `additionalProperties` support for schema validation (#198)
19
+ - "Draft" protocol version to supported versions (#179)
20
+ - `stateless` mode for high availability (#101)
21
+ - Exception messages for tool call errors (#194)
22
+ - Elicitation skeleton (#178)
23
+ - `prompts/list` and `prompts/get` support to client (#163)
24
+ - Accept header validation for HTTP client transport (#207)
25
+ - Ruby 2.7 - Ruby 3.1 support (#206)
26
+
27
+ ### Changed
28
+
29
+ - Make tool names stricter (#204)
30
+
31
+ ### Fixed
32
+
33
+ - Symlink path comparison in schema validation (#193)
34
+ - Duplicate tool names across namespaces now raise an error (#199)
35
+ - Tool error handling to follow MCP spec (#165)
36
+ - XSS vulnerability in json_rpc_handler (#175)
37
+
38
+ ## [0.4.0] - 2025-10-15
39
+
40
+ ### Added
41
+
42
+ - Client resources support with `resources/list` and `resources/read` methods (#160)
43
+ - `_meta` field support for Tool schema (#124)
44
+ - `_meta` field support for Prompt
45
+ - `title` field support for prompt arguments
46
+ - `call_tool_raw` method to client for accessing full tool responses (#149)
47
+ - Structured content support in tool responses (#147)
48
+ - AGENTS.md development guidance documentation (#134)
49
+ - Dependabot configuration for automated dependency updates (#138)
50
+
51
+ ### Changed
52
+
53
+ - Set default `content` to empty array instead of `nil` (#150)
54
+ - Improved prompt spec compliance (#153)
55
+ - Allow output schema to be array of objects (#144)
56
+ - Return 202 response code for accepted JSON-RPC notifications (#114)
57
+ - Added validation to `MCP::Configuration` setters (#145)
58
+ - Updated metaschema URI format for cross-OS compatibility
59
+
60
+ ### Fixed
61
+
62
+ - Client tools functionality and test coverage (#166)
63
+ - Client resources test for empty responses (#162)
64
+ - Documentation typos and incorrect examples (#157, #146)
65
+ - Removed redundant transport requires (#154)
66
+ - Cleaned up unused block parameters and magic comments
67
+
10
68
  ## [0.3.0] - 2025-09-14
11
69
 
12
70
  ### Added
data/Gemfile CHANGED
@@ -8,16 +8,18 @@ gemspec
8
8
  # Specify development dependencies below
9
9
  gem "rubocop-minitest", require: false
10
10
  gem "rubocop-rake", require: false
11
- gem "rubocop-shopify", require: false
11
+ gem "rubocop-shopify", ">= 2.18", require: false if RUBY_VERSION >= "3.1"
12
12
 
13
13
  gem "puma", ">= 5.0.0"
14
- gem "rack", ">= 2.0.0"
15
14
  gem "rackup", ">= 2.1.0"
16
15
 
17
16
  gem "activesupport"
18
- gem "debug"
17
+ # Fix io-console install error when Ruby 3.0.
18
+ gem "debug" if RUBY_VERSION >= "3.1"
19
19
  gem "rake", "~> 13.0"
20
- gem "sorbet-static-and-runtime"
20
+ gem "sorbet-static-and-runtime" if RUBY_VERSION >= "3.0"
21
+ gem "yard", "~> 0.9"
22
+ gem "yard-sorbet", "~> 0.9" if RUBY_VERSION >= "3.1"
21
23
 
22
24
  group :test do
23
25
  gem "faraday", ">= 2.0"
data/README.md CHANGED
@@ -131,7 +131,10 @@ Notifications follow the JSON-RPC 2.0 specification and use these method names:
131
131
 
132
132
  ```ruby
133
133
  server = MCP::Server.new(name: "my_server")
134
- transport = MCP::Transports::HTTP.new(server)
134
+
135
+ # Default Streamable HTTP - session oriented
136
+ transport = MCP::Server::Transports::StreamableHTTPTransport.new(server)
137
+
135
138
  server.transport = transport
136
139
 
137
140
  # When tools change, notify clients
@@ -139,18 +142,28 @@ server.define_tool(name: "new_tool") { |**args| { result: "ok" } }
139
142
  server.notify_tools_list_changed
140
143
  ```
141
144
 
142
- ### Unsupported Features ( to be implemented in future versions )
145
+ You can use Stateless Streamable HTTP, where notifications are not supported and all calls are request/response interactions.
146
+ This mode allows for easy multi-node deployment.
147
+ Set `stateless: true` in `MCP::Server::Transports::StreamableHTTPTransport.new` (`stateless` defaults to `false`):
148
+
149
+ ```ruby
150
+ # Stateless Streamable HTTP - session-less
151
+ transport = MCP::Server::Transports::StreamableHTTPTransport.new(server, stateless: true)
152
+ ```
153
+
154
+ ### Unsupported Features (to be implemented in future versions)
143
155
 
144
156
  - Log Level
145
157
  - Resource subscriptions
146
158
  - Completions
159
+ - Elicitation
147
160
 
148
161
  ### Usage
149
162
 
150
163
  #### Rails Controller
151
164
 
152
165
  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/2025-06-18/basic/transports#streamable-http) transport
166
+ [Streamable HTTP](https://modelcontextprotocol.io/specification/latest/basic/transports#streamable-http) transport
154
167
  requests.
155
168
 
156
169
  You can use the `Server#handle_json` method to handle requests.
@@ -160,7 +173,7 @@ class ApplicationController < ActionController::Base
160
173
  def index
161
174
  server = MCP::Server.new(
162
175
  name: "my_server",
163
- title: "Example Server Display Name", # WARNING: This is a `Draft` and is not supported in the `Version 2025-06-18 (latest)` specification.
176
+ title: "Example Server Display Name",
164
177
  version: "1.0.0",
165
178
  instructions: "Use the tools of this server as a last resort",
166
179
  tools: [SomeTool, AnotherTool],
@@ -178,7 +191,6 @@ If you want to build a local command-line application, you can use the stdio tra
178
191
 
179
192
  ```ruby
180
193
  require "mcp"
181
- require "mcp/server/transports/stdio_transport"
182
194
 
183
195
  # Create a simple tool
184
196
  class ExampleTool < MCP::Tool
@@ -337,6 +349,9 @@ configuration = MCP::Configuration.new(protocol_version: "2024-11-05")
337
349
  MCP::Server.new(name: "test_server", configuration: configuration)
338
350
  ```
339
351
 
352
+ If no protocol version is specified, the latest stable version will be applied by default.
353
+ The latest stable version includes new features from the [draft version](https://modelcontextprotocol.io/specification/draft).
354
+
340
355
  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`:
341
356
 
342
357
  ```ruby
@@ -369,7 +384,7 @@ If no exception reporter is configured, a default no-op reporter is used that si
369
384
 
370
385
  ### Tools
371
386
 
372
- MCP spec includes [Tools](https://modelcontextprotocol.io/specification/2025-06-18/server/tools) which provide functionality to LLM apps.
387
+ MCP spec includes [Tools](https://modelcontextprotocol.io/specification/latest/server/tools) which provide functionality to LLM apps.
373
388
 
374
389
  This gem provides a `MCP::Tool` class that can be used to create tools in three ways:
375
390
 
@@ -377,7 +392,7 @@ This gem provides a `MCP::Tool` class that can be used to create tools in three
377
392
 
378
393
  ```ruby
379
394
  class MyTool < MCP::Tool
380
- title "My Tool" # WARNING: This is a `Draft` and is not supported in the `Version 2025-06-18 (latest)` specification.
395
+ title "My Tool"
381
396
  description "This tool performs specific functionality..."
382
397
  input_schema(
383
398
  properties: {
@@ -414,21 +429,21 @@ tool = MyTool
414
429
  ```ruby
415
430
  tool = MCP::Tool.define(
416
431
  name: "my_tool",
417
- title: "My Tool", # WARNING: This is a `Draft` and is not supported in the `Version 2025-06-18 (latest)` specification.
432
+ title: "My Tool",
418
433
  description: "This tool performs specific functionality...",
419
434
  annotations: {
420
435
  read_only_hint: true,
421
436
  title: "My Tool"
422
437
  }
423
- ) do |args, server_context|
438
+ ) do |args, server_context:|
424
439
  MCP::Tool::Response.new([{ type: "text", text: "OK" }])
425
440
  end
426
441
  ```
427
442
 
428
- 3. By using the `ModelContextProtocol::Server#define_tool` method with a block:
443
+ 3. By using the `MCP::Server#define_tool` method with a block:
429
444
 
430
445
  ```ruby
431
- server = ModelContextProtocol::Server.new
446
+ server = MCP::Server.new
432
447
  server.define_tool(
433
448
  name: "my_tool",
434
449
  description: "This tool performs specific functionality...",
@@ -436,7 +451,7 @@ server.define_tool(
436
451
  title: "My Tool",
437
452
  read_only_hint: true
438
453
  }
439
- ) do |args, server_context|
454
+ ) do |args, server_context:|
440
455
  Tool::Response.new([{ type: "text", text: "OK" }])
441
456
  end
442
457
  ```
@@ -526,7 +541,7 @@ tool = MCP::Tool.define(
526
541
  },
527
542
  required: ["mean", "median", "count"]
528
543
  }
529
- ) do |args, server_context|
544
+ ) do |args, server_context:|
530
545
  # Calculate statistics and validate against schema
531
546
  MCP::Tool::Response.new([{ type: "text", text: "Statistics calculated" }])
532
547
  end
@@ -546,7 +561,28 @@ class DataTool < MCP::Tool
546
561
  end
547
562
  ```
548
563
 
549
- MCP spec for the [Output Schema](https://modelcontextprotocol.io/specification/2025-06-18/server/tools#output-schema) specifies that:
564
+ Output schema may also describe an array of objects:
565
+
566
+ ```ruby
567
+ class WeatherTool < MCP::Tool
568
+ output_schema(
569
+ type: "array",
570
+ items: {
571
+ properties: {
572
+ temperature: { type: "number" },
573
+ condition: { type: "string" },
574
+ humidity: { type: "integer" }
575
+ },
576
+ required: ["temperature", "condition", "humidity"]
577
+ }
578
+ )
579
+ end
580
+ ```
581
+
582
+ Please note: in this case, you must provide `type: "array"`. The default type
583
+ for output schemas is `object`.
584
+
585
+ MCP spec for the [Output Schema](https://modelcontextprotocol.io/specification/latest/server/tools#output-schema) specifies that:
550
586
 
551
587
  - **Server Validation**: Servers MUST provide structured results that conform to the output schema
552
588
  - **Client Validation**: Clients SHOULD validate structured results against the output schema
@@ -555,9 +591,67 @@ MCP spec for the [Output Schema](https://modelcontextprotocol.io/specification/2
555
591
 
556
592
  The output schema follows standard JSON Schema format and helps ensure consistent data exchange between MCP servers and clients.
557
593
 
594
+ ### Tool Responses with Structured Content
595
+
596
+ Tools can return structured data alongside text content using the `structured_content` parameter.
597
+
598
+ The structured content will be included in the JSON-RPC response as the `structuredContent` field.
599
+
600
+ ```ruby
601
+ class WeatherTool < MCP::Tool
602
+ description "Get current weather and return structured data"
603
+
604
+ def self.call(location:, units: "celsius", server_context:)
605
+ # Call weather API and structure the response
606
+ api_response = WeatherAPI.fetch(location, units)
607
+ weather_data = {
608
+ temperature: api_response.temp,
609
+ condition: api_response.description,
610
+ humidity: api_response.humidity_percent
611
+ }
612
+
613
+ output_schema.validate_result(weather_data)
614
+
615
+ MCP::Tool::Response.new(
616
+ [{
617
+ type: "text",
618
+ text: weather_data.to_json
619
+ }],
620
+ structured_content: weather_data
621
+ )
622
+ end
623
+ end
624
+ ```
625
+
626
+ ### Tool Responses with Errors
627
+
628
+ Tools can return error information alongside text content using the `error` parameter.
629
+
630
+ The error will be included in the JSON-RPC response as the `isError` field.
631
+
632
+ ```ruby
633
+ class WeatherTool < MCP::Tool
634
+ description "Get current weather and return structured data"
635
+
636
+ def self.call(server_context:)
637
+ # Do something here
638
+ content = {}
639
+
640
+ MCP::Tool::Response.new(
641
+ [{
642
+ type: "text",
643
+ text: content.to_json
644
+ }],
645
+ structured_content: content,
646
+ error: true
647
+ )
648
+ end
649
+ end
650
+ ```
651
+
558
652
  ### Prompts
559
653
 
560
- MCP spec includes [Prompts](https://modelcontextprotocol.io/specification/2025-06-18/server/prompts), which enable servers to define reusable prompt templates and workflows that clients can easily surface to users and LLMs.
654
+ 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.
561
655
 
562
656
  The `MCP::Prompt` class provides three ways to create prompts:
563
657
 
@@ -566,15 +660,17 @@ The `MCP::Prompt` class provides three ways to create prompts:
566
660
  ```ruby
567
661
  class MyPrompt < MCP::Prompt
568
662
  prompt_name "my_prompt" # Optional - defaults to underscored class name
569
- title "My Prompt" # WARNING: This is a `Draft` and is not supported in the `Version 2025-06-18 (latest)` specification.
663
+ title "My Prompt"
570
664
  description "This prompt performs specific functionality..."
571
665
  arguments [
572
666
  MCP::Prompt::Argument.new(
573
667
  name: "message",
668
+ title: "Message Title",
574
669
  description: "Input message",
575
670
  required: true
576
671
  )
577
672
  ]
673
+ meta({ version: "1.0", category: "example" })
578
674
 
579
675
  class << self
580
676
  def template(args, server_context:)
@@ -603,15 +699,17 @@ prompt = MyPrompt
603
699
  ```ruby
604
700
  prompt = MCP::Prompt.define(
605
701
  name: "my_prompt",
606
- title: "My Prompt", # WARNING: This is a `Draft` and is not supported in the `Version 2025-06-18 (latest)` specification.
702
+ title: "My Prompt",
607
703
  description: "This prompt performs specific functionality...",
608
704
  arguments: [
609
705
  MCP::Prompt::Argument.new(
610
706
  name: "message",
707
+ title: "Message Title",
611
708
  description: "Input message",
612
709
  required: true
613
710
  )
614
- ]
711
+ ],
712
+ meta: { version: "1.0", category: "example" }
615
713
  ) do |args, server_context:|
616
714
  MCP::Prompt::Result.new(
617
715
  description: "Response description",
@@ -629,20 +727,22 @@ prompt = MCP::Prompt.define(
629
727
  end
630
728
  ```
631
729
 
632
- 3. Using the `ModelContextProtocol::Server#define_protocol` method:
730
+ 3. Using the `MCP::Server#define_prompt` method:
633
731
 
634
732
  ```ruby
635
- server = ModelContextProtocol::Server.new
636
- server.define_protocol(
733
+ server = MCP::Server.new
734
+ server.define_prompt(
637
735
  name: "my_prompt",
638
736
  description: "This prompt performs specific functionality...",
639
737
  arguments: [
640
738
  Prompt::Argument.new(
641
739
  name: "message",
740
+ title: "Message Title",
642
741
  description: "Input message",
643
742
  required: true
644
743
  )
645
- ]
744
+ ],
745
+ meta: { version: "1.0", category: "example" }
646
746
  ) do |args, server_context:|
647
747
  Prompt::Result.new(
648
748
  description: "Response description",
@@ -665,7 +765,7 @@ e.g. around authentication state or user preferences.
665
765
 
666
766
  ### Key Components
667
767
 
668
- - `MCP::Prompt::Argument` - Defines input parameters for the prompt template
768
+ - `MCP::Prompt::Argument` - Defines input parameters for the prompt template with name, title, description, and required flag
669
769
  - `MCP::Prompt::Message` - Represents a message in the conversation with a role and content
670
770
  - `MCP::Prompt::Result` - The output of a prompt template containing description and messages
671
771
  - `MCP::Content::Text` - Text content for messages
@@ -714,7 +814,7 @@ This is to avoid potential issues with metric cardinality
714
814
 
715
815
  ### Resources
716
816
 
717
- MCP spec includes [Resources](https://modelcontextprotocol.io/specification/2025-06-18/server/resources).
817
+ MCP spec includes [Resources](https://modelcontextprotocol.io/specification/latest/server/resources).
718
818
 
719
819
  ### Reading Resources
720
820
 
@@ -724,7 +824,7 @@ The `MCP::Resource` class provides a way to register resources with the server.
724
824
  resource = MCP::Resource.new(
725
825
  uri: "https://example.com/my_resource",
726
826
  name: "my-resource",
727
- title: "My Resource", # WARNING: This is a `Draft` and is not supported in the `Version 2025-06-18 (latest)` specification.
827
+ title: "My Resource",
728
828
  description: "Lorem ipsum dolor sit amet",
729
829
  mime_type: "text/html",
730
830
  )
@@ -757,7 +857,7 @@ The `MCP::ResourceTemplate` class provides a way to register resource templates
757
857
  resource_template = MCP::ResourceTemplate.new(
758
858
  uri_template: "https://example.com/my_resource_template",
759
859
  name: "my-resource-template",
760
- title: "My Resource Template", # WARNING: This is a `Draft` and is not supported in the `Version 2025-06-18 (latest)` specification.
860
+ title: "My Resource Template",
761
861
  description: "Lorem ipsum dolor sit amet",
762
862
  mime_type: "text/html",
763
863
  )
@@ -774,8 +874,12 @@ The `MCP::Client` class provides an interface for interacting with MCP servers.
774
874
 
775
875
  This class supports:
776
876
 
777
- - Tool listing via the `tools/list` method
778
- - Tool invocation via the `tools/call` method
877
+ - Tool listing via the `tools/list` method (`MCP::Client#tools`)
878
+ - Tool invocation via the `tools/call` method (`MCP::Client#call_tools`)
879
+ - Resource listing via the `resources/list` method (`MCP::Client#resources`)
880
+ - Resource reading via the `resources/read` method (`MCP::Client#read_resources`)
881
+ - Prompt listing via the `prompts/list` method (`MCP::Client#prompts`)
882
+ - Prompt retrieval via the `prompts/get` method (`MCP::Client#get_prompt`)
779
883
  - Automatic JSON-RPC 2.0 message formatting
780
884
  - UUID request ID generation
781
885
 
@@ -864,15 +968,7 @@ The client provides a wrapper class for tools returned by the server:
864
968
 
865
969
  This class provides easy access to tool properties like name, description, input schema, and output schema.
866
970
 
867
- ## Releases
868
-
869
- This gem is published to [RubyGems.org](https://rubygems.org/gems/mcp)
870
-
871
- Releases are triggered by PRs to the `main` branch updating the version number in `lib/mcp/version.rb`.
872
-
873
- 1. **Update the version number** in `lib/mcp/version.rb`, following [semver](https://semver.org/)
874
- 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
875
- 1. **Create a PR and get approval from a maintainer**
876
- 1. **Merge your PR to the main branch** - This will automatically trigger the release workflow via GitHub Actions
971
+ ## Documentation
877
972
 
878
- When changes are merged to the `main` branch, the GitHub Actions workflow (`.github/workflows/release.yml`) is triggered and the gem is published to RubyGems.
973
+ - [SDK API documentation](https://rubydoc.info/gems/mcp)
974
+ - [Model Context Protocol documentation](https://modelcontextprotocol.io)