mcp 0.21.0 → 0.23.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.
@@ -36,16 +36,29 @@ module MCP
36
36
  end
37
37
  VALIDATION_CACHE = ValidationCache.new
38
38
 
39
- # JSON Schema 2020-12 is the default dialect for MCP schema definitions
40
- # per MCP 2025-11-25 (SEP-1613). Note: emission only — runtime validation
41
- # is still performed against the JSON Schema draft-04 metaschema.
39
+ # JSON Schema 2020-12 is the default dialect for MCP schema definitions per MCP 2025-11-25 (SEP-1613),
40
+ # and SEP-2106 requires tool schemas to conform to the full 2020-12 vocabulary. Both emission and
41
+ # runtime validation use this dialect. Because MCP mandates 2020-12, the SDK validates against it
42
+ # regardless of any `$schema` a document embeds; for compliant schemas this is the same dialect
43
+ # the Python SDK's `jsonschema.validate` resolves to.
42
44
  JSON_SCHEMA_2020_12_URI = "https://json-schema.org/draft/2020-12/schema"
43
45
 
44
- DRAFT4_META_SCHEMA_URI = "http://json-schema.org/draft-04/schema#"
46
+ # Resource bounds for schema compilation, mirroring the TypeScript SDK's schema bounds (SEP-2106):
47
+ # schemas may use the full JSON Schema 2020-12 vocabulary including composition keywords and `$ref`,
48
+ # so adversarial documents must be rejected before they can cause excessive validation cost.
49
+ # Only same-document references (starting with `#`) are accepted, so schema handling can never trigger network
50
+ # or file access.
51
+ MAX_SCHEMA_DEPTH = 64
52
+ MAX_SUBSCHEMA_COUNT = 10_000
53
+
54
+ # Reference keywords whose targets the SDK refuses to dereference. Both `$ref` and `$dynamicRef` may carry
55
+ # an absolute URI under JSON Schema 2020-12, so a non-same-document value is an external reference.
56
+ REFERENCE_KEYWORDS = [:"$ref", :"$dynamicRef"].freeze
45
57
 
46
58
  def initialize(schema = {})
47
59
  @schema = JSON.parse(JSON.dump(schema), symbolize_names: true)
48
- @schema[:type] ||= "object"
60
+ apply_default_root_type!
61
+ validate_schema_bounds!
49
62
  validate_schema!
50
63
  end
51
64
 
@@ -61,6 +74,48 @@ module MCP
61
74
 
62
75
  private
63
76
 
77
+ # Root-type defaulting hook. The base class preserves the historical behavior of defaulting the root
78
+ # to an object schema; `OutputSchema` overrides this because SEP-2106 allows any root schema there.
79
+ def apply_default_root_type!
80
+ @schema[:type] ||= "object"
81
+ end
82
+
83
+ # Enforces `MAX_SCHEMA_DEPTH` / `MAX_SUBSCHEMA_COUNT` and the same-document reference rule over
84
+ # the whole schema document.
85
+ def validate_schema_bounds!
86
+ subschema_count = 0
87
+ stack = [[@schema, 1]]
88
+
89
+ until stack.empty?
90
+ node, depth = stack.pop
91
+ if depth > MAX_SCHEMA_DEPTH
92
+ raise ArgumentError,
93
+ "Invalid JSON Schema: nesting exceeds the maximum depth of #{MAX_SCHEMA_DEPTH}."
94
+ end
95
+
96
+ case node
97
+ when Hash
98
+ subschema_count += 1
99
+ if subschema_count > MAX_SUBSCHEMA_COUNT
100
+ raise ArgumentError,
101
+ "Invalid JSON Schema: document exceeds the maximum of #{MAX_SUBSCHEMA_COUNT} subschema objects."
102
+ end
103
+
104
+ REFERENCE_KEYWORDS.each do |keyword|
105
+ ref = node[keyword]
106
+ next unless ref.is_a?(String) && !ref.start_with?("#")
107
+
108
+ raise ArgumentError,
109
+ "Invalid JSON Schema: only same-document #{keyword} (starting with '#') is supported, got #{ref.inspect}."
110
+ end
111
+
112
+ node.each_value { |child| stack << [child, depth + 1] }
113
+ when Array
114
+ node.each { |child| stack << [child, depth + 1] }
115
+ end
116
+ end
117
+ end
118
+
64
119
  def stringify(obj)
65
120
  case obj
66
121
  when Hash
@@ -78,13 +133,16 @@ module MCP
78
133
  # Memoized per Schema instance because schema content is fixed at construction,
79
134
  # so the compiled schemer is reusable across many `fully_validate` calls.
80
135
  #
136
+ # Validated against the JSON Schema 2020-12 metaschema per SEP-2106, so `$defs`/`$ref` and
137
+ # the rest of the 2020-12 vocabulary resolve natively.
138
+ #
81
139
  # `format: false` preserves the legacy behavior of the previous `json-schema` based implementation,
82
140
  # which did not enforce `format` keywords. `RegexpError` from a malformed `pattern` is re-raised as
83
141
  # `ArgumentError` so callers see the same exception class they used to.
84
142
  def schemer
85
143
  @schemer ||= JSONSchemer.schema(
86
144
  stringify(schema_for_validation),
87
- meta_schema: DRAFT4_META_SCHEMA_URI,
145
+ meta_schema: JSON_SCHEMA_2020_12_URI,
88
146
  format: false,
89
147
  )
90
148
  rescue RegexpError => e
@@ -112,8 +170,8 @@ module MCP
112
170
  VALIDATION_CACHE.store(key)
113
171
  end
114
172
 
115
- # `json_schemer` is pinned to the draft-04 metaschema, so strip top-level `$schema` before validation:
116
- # this preserves the legacy behavior of ignoring the advertised dialect URI when the SDK validates schemas.
173
+ # Strip the top-level `$schema` before validation so the SDK always validates against
174
+ # the 2020-12 metaschema (SEP-2106) regardless of any dialect URI a caller embedded in the document.
117
175
  def schema_for_validation
118
176
  return @schema unless @schema.key?(:"$schema")
119
177
 
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.21.0"
4
+ VERSION = "0.23.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.21.0
4
+ version: 0.23.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Model Context Protocol
@@ -90,7 +90,7 @@ licenses:
90
90
  - Apache-2.0
91
91
  metadata:
92
92
  allowed_push_host: https://rubygems.org
93
- changelog_uri: https://github.com/modelcontextprotocol/ruby-sdk/releases/tag/v0.21.0
93
+ changelog_uri: https://github.com/modelcontextprotocol/ruby-sdk/releases/tag/v0.23.0
94
94
  homepage_uri: https://ruby.sdk.modelcontextprotocol.io
95
95
  source_code_uri: https://github.com/modelcontextprotocol/ruby-sdk
96
96
  bug_tracker_uri: https://github.com/modelcontextprotocol/ruby-sdk/issues