mcp 0.15.0 → 0.16.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0d7b34843d1b915df5d3df424b025c93bba1d50a5e19486f2dcd4a646227a749
4
- data.tar.gz: 4327576e74518a21d1dbe57f7f22a6f17c8e486b7a9fb9c281c11d206dcd007e
3
+ metadata.gz: 5b7c0c225e89be4cfc9c73a0707b8a6a61d0d76a8a21340b20b3dd276f36eec6
4
+ data.tar.gz: fdd1b11cbe6ac733820bc604f72c95c6f0aa67162776c8778de7adb04aa7ca39
5
5
  SHA512:
6
- metadata.gz: afe69100125bcc47dbfca963983eca401f5bf29b31c01748dd1a5e99537542a4cb2b021573d3635c94bb410cdd430c0e3ff023796d91299da366cc32c7999fba
7
- data.tar.gz: 815153266ba50a7e3045d7058af383d2ba852e1eefbaa62bc78299da89621bb1c0e22c5d2738f56470f50b4e8bf85f0d83135b1789f2faa9c841cff5e29fa766
6
+ metadata.gz: c6dce7fe76f5f3996c9f5caffe884237147c74840d4d68dce5ec6ec24be49e65e0eea39306c2c52353c5014c8247295491b3337e166cec662eca19742565d741
7
+ data.tar.gz: b944ae1938952c5e4fd20fb4b5d1ade071cf5ffa193b6c0cd56ba25e79aa583e2de38804045ce0d038eb2e38b5ea5bed4fd6b6073a16fea8bdba02f7e1e8b148
data/README.md CHANGED
@@ -645,6 +645,19 @@ MCP spec for the [Output Schema](https://modelcontextprotocol.io/specification/l
645
645
 
646
646
  The output schema follows standard JSON Schema format and helps ensure consistent data exchange between MCP servers and clients.
647
647
 
648
+ By default, server-side validation of tool results against `output_schema` is disabled for backwards compatibility. To validate successful tool responses, enable `validate_tool_call_results`:
649
+
650
+ ```ruby
651
+ configuration = MCP::Configuration.new(validate_tool_call_results: true)
652
+ server = MCP::Server.new(
653
+ name: "example_server",
654
+ tools: [WeatherTool],
655
+ configuration: configuration
656
+ )
657
+ ```
658
+
659
+ When enabled, successful tool responses for tools with an `output_schema` must include `structured_content` that conforms to the schema. Error responses are not validated against the output schema.
660
+
648
661
  ### Tool Responses with Structured Content
649
662
 
650
663
  Tools can return structured data alongside text content using the `structured_content` parameter.
data/lib/mcp/client.rb CHANGED
@@ -123,6 +123,7 @@ module MCP
123
123
  name: tool["name"],
124
124
  description: tool["description"],
125
125
  input_schema: tool["inputSchema"],
126
+ output_schema: tool["outputSchema"],
126
127
  )
127
128
  end
128
129
 
@@ -16,7 +16,7 @@ module MCP
16
16
  attr_writer :instrumentation_callback
17
17
 
18
18
  def initialize(exception_reporter: nil, around_request: nil, instrumentation_callback: nil, protocol_version: nil,
19
- validate_tool_call_arguments: true)
19
+ validate_tool_call_arguments: true, validate_tool_call_results: false)
20
20
  @exception_reporter = exception_reporter
21
21
  @around_request = around_request
22
22
  @instrumentation_callback = instrumentation_callback
@@ -25,8 +25,10 @@ module MCP
25
25
  validate_protocol_version!(protocol_version)
26
26
  end
27
27
  validate_value_of_validate_tool_call_arguments!(validate_tool_call_arguments)
28
+ validate_value_of_validate_tool_call_results!(validate_tool_call_results)
28
29
 
29
30
  @validate_tool_call_arguments = validate_tool_call_arguments
31
+ @validate_tool_call_results = validate_tool_call_results
30
32
  end
31
33
 
32
34
  def protocol_version=(protocol_version)
@@ -41,6 +43,12 @@ module MCP
41
43
  @validate_tool_call_arguments = validate_tool_call_arguments
42
44
  end
43
45
 
46
+ def validate_tool_call_results=(validate_tool_call_results)
47
+ validate_value_of_validate_tool_call_results!(validate_tool_call_results)
48
+
49
+ @validate_tool_call_results = validate_tool_call_results
50
+ end
51
+
44
52
  def protocol_version
45
53
  @protocol_version || LATEST_STABLE_PROTOCOL_VERSION
46
54
  end
@@ -80,11 +88,16 @@ module MCP
80
88
  end
81
89
 
82
90
  attr_reader :validate_tool_call_arguments
91
+ attr_reader :validate_tool_call_results
83
92
 
84
93
  def validate_tool_call_arguments?
85
94
  !!@validate_tool_call_arguments
86
95
  end
87
96
 
97
+ def validate_tool_call_results?
98
+ !!@validate_tool_call_results
99
+ end
100
+
88
101
  def merge(other)
89
102
  return self if other.nil?
90
103
 
@@ -113,6 +126,7 @@ module MCP
113
126
  end
114
127
 
115
128
  validate_tool_call_arguments = other.validate_tool_call_arguments
129
+ validate_tool_call_results = other.validate_tool_call_results
116
130
 
117
131
  Configuration.new(
118
132
  exception_reporter: exception_reporter,
@@ -120,6 +134,7 @@ module MCP
120
134
  instrumentation_callback: instrumentation_callback,
121
135
  protocol_version: protocol_version,
122
136
  validate_tool_call_arguments: validate_tool_call_arguments,
137
+ validate_tool_call_results: validate_tool_call_results,
123
138
  )
124
139
  end
125
140
 
@@ -138,6 +153,12 @@ module MCP
138
153
  end
139
154
  end
140
155
 
156
+ def validate_value_of_validate_tool_call_results!(validate_tool_call_results)
157
+ unless validate_tool_call_results.is_a?(TrueClass) || validate_tool_call_results.is_a?(FalseClass)
158
+ raise ArgumentError, "validate_tool_call_results must be a boolean"
159
+ end
160
+ end
161
+
141
162
  def default_exception_reporter
142
163
  @default_exception_reporter ||= ->(exception, server_context) {}
143
164
  end
data/lib/mcp/server.rb CHANGED
@@ -162,8 +162,8 @@ module MCP
162
162
  end
163
163
  end
164
164
 
165
- def define_tool(name: nil, title: nil, description: nil, input_schema: nil, annotations: nil, meta: nil, &block)
166
- tool = Tool.define(name: name, title: title, description: description, input_schema: input_schema, annotations: annotations, meta: meta, &block)
165
+ def define_tool(name: nil, title: nil, description: nil, input_schema: nil, output_schema: nil, annotations: nil, meta: nil, &block)
166
+ tool = Tool.define(name: name, title: title, description: description, input_schema: input_schema, output_schema: output_schema, annotations: annotations, meta: meta, &block)
167
167
  tool_name = tool.name_value
168
168
 
169
169
  @tool_names << tool_name
@@ -586,9 +586,11 @@ module MCP
586
586
 
587
587
  progress_token = request.dig(:_meta, :progressToken)
588
588
 
589
- call_tool_with_args(
589
+ result = call_tool_with_args(
590
590
  tool, arguments, server_context_with_meta(request), progress_token: progress_token, session: session, related_request_id: related_request_id, cancellation: cancellation
591
591
  )
592
+ validate_tool_call_result!(tool, result)
593
+ result
592
594
  rescue RequestHandlerError, CancelledError
593
595
  # CancelledError is intentionally not wrapped so `handle_request` can turn it into
594
596
  # `JsonRpcHandler::NO_RESPONSE` per the MCP cancellation spec.
@@ -745,6 +747,14 @@ module MCP
745
747
  ).to_h
746
748
  end
747
749
 
750
+ def validate_tool_call_result!(tool, result)
751
+ return unless configuration.validate_tool_call_results
752
+ return unless tool.output_schema
753
+ return if result[:isError]
754
+
755
+ tool.output_schema.validate_result(result[:structuredContent])
756
+ end
757
+
748
758
  # Whether a tool/prompt handler opts in to receiving an `MCP::ServerContext`.
749
759
  # Recognizes `:keyrest` (`**kwargs`) because tools are invoked without a positional argument
750
760
  # (`tool.call(**args, server_context:)`), soa `**kwargs`-only signature safely captures `server_context:`.
@@ -5,6 +5,12 @@ require "json-schema"
5
5
  module MCP
6
6
  class Tool
7
7
  class Schema
8
+ # JSON Schema 2020-12 is the default dialect for MCP schema definitions
9
+ # per MCP 2025-11-25 (SEP-1613). Note: emission only — runtime validation
10
+ # is still performed against the JSON Schema draft-04 metaschema because
11
+ # the `json-schema` gem does not yet support 2020-12.
12
+ JSON_SCHEMA_2020_12_URI = "https://json-schema.org/draft/2020-12/schema"
13
+
8
14
  attr_reader :schema
9
15
 
10
16
  def initialize(schema = {})
@@ -18,17 +24,18 @@ module MCP
18
24
  end
19
25
 
20
26
  def to_h
21
- @schema
27
+ return @schema if @schema.key?(:"$schema")
28
+
29
+ { "$schema": JSON_SCHEMA_2020_12_URI }.merge(@schema)
22
30
  end
23
31
 
24
32
  private
25
33
 
26
34
  def fully_validate(data)
27
- JSON::Validator.fully_validate(to_h, data)
35
+ JSON::Validator.fully_validate(schema_for_validation, data)
28
36
  end
29
37
 
30
38
  def validate_schema!
31
- schema = to_h
32
39
  gem_path = File.realpath(Gem.loaded_specs["json-schema"].full_gem_path)
33
40
  schema_reader = JSON::Schema::Reader.new(
34
41
  accept_uri: false,
@@ -38,11 +45,22 @@ module MCP
38
45
  # Converts metaschema to a file URI for cross-platform compatibility
39
46
  metaschema_uri = JSON::Util::URI.file_uri(metaschema_path.expand_path.cleanpath.to_s.tr("\\", "/"))
40
47
  metaschema = metaschema_uri.to_s
41
- errors = JSON::Validator.fully_validate(metaschema, schema, schema_reader: schema_reader)
48
+ errors = JSON::Validator.fully_validate(metaschema, schema_for_validation, schema_reader: schema_reader)
42
49
  if errors.any?
43
50
  raise ArgumentError, "Invalid JSON Schema: #{errors.join(", ")}"
44
51
  end
45
52
  end
53
+
54
+ # The `json-schema` gem's draft-04 validator cannot resolve newer or unknown `$schema`
55
+ # dialect URIs. Strip the top-level `$schema` before validation so a dialect URI
56
+ # (whether SDK-injected by `to_h` or user-supplied) does not break the validator.
57
+ def schema_for_validation
58
+ return @schema unless @schema.key?(:"$schema")
59
+
60
+ copy = @schema.dup
61
+ copy.delete(:"$schema")
62
+ copy
63
+ end
46
64
  end
47
65
  end
48
66
  end
data/lib/mcp/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MCP
4
- VERSION = "0.15.0"
4
+ VERSION = "0.16.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mcp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.0
4
+ version: 0.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Model Context Protocol
@@ -81,7 +81,7 @@ licenses:
81
81
  - Apache-2.0
82
82
  metadata:
83
83
  allowed_push_host: https://rubygems.org
84
- changelog_uri: https://github.com/modelcontextprotocol/ruby-sdk/releases/tag/v0.15.0
84
+ changelog_uri: https://github.com/modelcontextprotocol/ruby-sdk/releases/tag/v0.16.0
85
85
  homepage_uri: https://ruby.sdk.modelcontextprotocol.io
86
86
  source_code_uri: https://github.com/modelcontextprotocol/ruby-sdk
87
87
  bug_tracker_uri: https://github.com/modelcontextprotocol/ruby-sdk/issues
@@ -100,7 +100,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
100
  - !ruby/object:Gem::Version
101
101
  version: '0'
102
102
  requirements: []
103
- rubygems_version: 4.0.6
103
+ rubygems_version: 4.0.10
104
104
  specification_version: 4
105
105
  summary: The official Ruby SDK for Model Context Protocol servers and clients
106
106
  test_files: []