mcp 0.18.0 → 0.20.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/lib/mcp/server.rb CHANGED
@@ -58,6 +58,32 @@ module MCP
58
58
  end
59
59
  end
60
60
 
61
+ # Raised when a requested resource URI does not exist. Per SEP-2164,
62
+ # resource-not-found errors use the standard JSON-RPC Invalid Params code (-32602)
63
+ # with the requested URI in the error `data` member. Raise this from
64
+ # a `resources_read_handler` block for unknown URIs:
65
+ #
66
+ # server.resources_read_handler do |params|
67
+ # raise MCP::Server::ResourceNotFoundError.new(params[:uri], params) unless known?(params[:uri])
68
+ # do_something(params[:uri])
69
+ # end
70
+ #
71
+ # https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2164
72
+ class ResourceNotFoundError < RequestHandlerError
73
+ def initialize(uri, request = nil)
74
+ # The explicit `error_code` keeps the descriptive message in the JSON-RPC
75
+ # error response; `error_type: :invalid_params` alone would replace it
76
+ # with the generic "Invalid params" string.
77
+ super(
78
+ "Resource not found: #{uri}",
79
+ request,
80
+ error_type: :invalid_params,
81
+ error_code: JsonRpcHandler::ErrorCode::INVALID_PARAMS,
82
+ error_data: { uri: uri },
83
+ )
84
+ end
85
+ end
86
+
61
87
  class MethodAlreadyDefinedError < StandardError
62
88
  attr_reader :method_name
63
89
 
@@ -846,7 +872,7 @@ module MCP
846
872
  uri = ref[:uri]
847
873
  found = @resource_index.key?(uri) || @resource_templates.any? { |t| t.uri_template == uri }
848
874
  unless found
849
- raise RequestHandlerError.new("Resource not found: #{uri}", params, error_type: :invalid_params)
875
+ raise ResourceNotFoundError.new(uri, params)
850
876
  end
851
877
  else
852
878
  raise RequestHandlerError.new("Invalid ref type: #{ref[:type]}", params, error_type: :invalid_params)
@@ -12,9 +12,9 @@ module MCP
12
12
  end
13
13
 
14
14
  def missing_required_arguments(arguments)
15
- return [] unless schema[:required].is_a?(Array)
15
+ return [] unless @schema[:required].is_a?(Array)
16
16
 
17
- (schema[:required] - arguments.keys.map(&:to_s))
17
+ (@schema[:required] - arguments.keys.map(&:to_s))
18
18
  end
19
19
 
20
20
  def validate_arguments(arguments)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "digest"
4
- require "json-schema"
4
+ require "json_schemer"
5
5
 
6
6
  module MCP
7
7
  class Tool
@@ -38,11 +38,10 @@ module MCP
38
38
 
39
39
  # JSON Schema 2020-12 is the default dialect for MCP schema definitions
40
40
  # per MCP 2025-11-25 (SEP-1613). Note: emission only — runtime validation
41
- # is still performed against the JSON Schema draft-04 metaschema because
42
- # the `json-schema` gem does not yet support 2020-12.
41
+ # is still performed against the JSON Schema draft-04 metaschema.
43
42
  JSON_SCHEMA_2020_12_URI = "https://json-schema.org/draft/2020-12/schema"
44
43
 
45
- attr_reader :schema
44
+ DRAFT4_META_SCHEMA_URI = "http://json-schema.org/draft-04/schema#"
46
45
 
47
46
  def initialize(schema = {})
48
47
  @schema = JSON.parse(JSON.dump(schema), symbolize_names: true)
@@ -51,7 +50,7 @@ module MCP
51
50
  end
52
51
 
53
52
  def ==(other)
54
- other.is_a?(self.class) && schema == other.schema
53
+ other.is_a?(self.class) && @schema == other.instance_variable_get(:@schema)
55
54
  end
56
55
 
57
56
  def to_h
@@ -62,8 +61,38 @@ module MCP
62
61
 
63
62
  private
64
63
 
64
+ def stringify(obj)
65
+ case obj
66
+ when Hash
67
+ obj.each_with_object({}) { |(k, v), h| h[k.to_s] = stringify(v) }
68
+ when Array
69
+ obj.map { |v| stringify(v) }
70
+ when Symbol
71
+ obj.to_s
72
+ else
73
+ obj
74
+ end
75
+ end
76
+
77
+ # Lazily built so a cache hit in `validate_schema!` avoids the schemer construction cost.
78
+ # Memoized per Schema instance because schema content is fixed at construction,
79
+ # so the compiled schemer is reusable across many `fully_validate` calls.
80
+ #
81
+ # `format: false` preserves the legacy behavior of the previous `json-schema` based implementation,
82
+ # which did not enforce `format` keywords. `RegexpError` from a malformed `pattern` is re-raised as
83
+ # `ArgumentError` so callers see the same exception class they used to.
84
+ def schemer
85
+ @schemer ||= JSONSchemer.schema(
86
+ stringify(schema_for_validation),
87
+ meta_schema: DRAFT4_META_SCHEMA_URI,
88
+ format: false,
89
+ )
90
+ rescue RegexpError => e
91
+ raise ArgumentError, "Invalid JSON Schema: #{e.message}"
92
+ end
93
+
65
94
  def fully_validate(data)
66
- JSON::Validator.fully_validate(schema_for_validation, data)
95
+ schemer.validate(stringify(data)).map { |validation_error| validation_error.fetch("error") }
67
96
  end
68
97
 
69
98
  def validate_schema!
@@ -75,16 +104,7 @@ module MCP
75
104
  key = Digest::SHA256.hexdigest(JSON.generate(target, max_nesting: false))
76
105
  return if VALIDATION_CACHE.validated?(key)
77
106
 
78
- gem_path = File.realpath(Gem.loaded_specs["json-schema"].full_gem_path)
79
- schema_reader = JSON::Schema::Reader.new(
80
- accept_uri: false,
81
- accept_file: ->(path) { File.realpath(path.to_s).start_with?(gem_path) },
82
- )
83
- metaschema_path = Pathname.new(JSON::Validator.validator_for_name("draft4").metaschema)
84
- # Converts metaschema to a file URI for cross-platform compatibility
85
- metaschema_uri = JSON::Util::URI.file_uri(metaschema_path.expand_path.cleanpath.to_s.tr("\\", "/"))
86
- metaschema = metaschema_uri.to_s
87
- errors = JSON::Validator.fully_validate(metaschema, target, schema_reader: schema_reader)
107
+ errors = schemer.validate_schema.map { |validation_error| validation_error.fetch("error") }
88
108
  if errors.any?
89
109
  raise ArgumentError, "Invalid JSON Schema: #{errors.join(", ")}"
90
110
  end
@@ -92,9 +112,8 @@ module MCP
92
112
  VALIDATION_CACHE.store(key)
93
113
  end
94
114
 
95
- # The `json-schema` gem's draft-04 validator cannot resolve newer or unknown `$schema`
96
- # dialect URIs. Strip the top-level `$schema` before validation so a dialect URI
97
- # (whether SDK-injected by `to_h` or user-supplied) does not break the validator.
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.
98
117
  def schema_for_validation
99
118
  return @schema unless @schema.key?(:"$schema")
100
119
 
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MCP
4
+ # Reserved `_meta` keys for W3C Trace Context propagation, per SEP-414.
5
+ #
6
+ # The MCP spec reserves the un-prefixed `_meta` keys `traceparent`, `tracestate`, and `baggage`
7
+ # (an explicit exception to the reverse-DNS prefix rule for `_meta` keys) so that clients and
8
+ # servers can propagate distributed-tracing context across MCP requests.
9
+ # The SDK guarantees these keys pass through incoming request `_meta` untouched; tool, prompt,
10
+ # and resource handlers can read them from `server_context[:_meta]` and bridge them to a tracing
11
+ # system such as the `opentelemetry-ruby` gems. The SDK itself does not depend on OpenTelemetry.
12
+ #
13
+ # - https://github.com/modelcontextprotocol/modelcontextprotocol/pull/414
14
+ # - https://www.w3.org/TR/trace-context/
15
+ # - https://www.w3.org/TR/baggage/
16
+ module TraceContext
17
+ TRACEPARENT_META_KEY = "traceparent"
18
+ TRACESTATE_META_KEY = "tracestate"
19
+ BAGGAGE_META_KEY = "baggage"
20
+
21
+ META_KEYS = [TRACEPARENT_META_KEY, TRACESTATE_META_KEY, BAGGAGE_META_KEY].freeze
22
+ end
23
+ 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.18.0"
4
+ VERSION = "0.20.0"
5
5
  end
data/lib/mcp.rb CHANGED
@@ -19,6 +19,7 @@ module MCP
19
19
  autoload :Server, "mcp/server"
20
20
  autoload :ServerSession, "mcp/server_session"
21
21
  autoload :Tool, "mcp/tool"
22
+ autoload :TraceContext, "mcp/trace_context"
22
23
 
23
24
  class << self
24
25
  def configure
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.18.0
4
+ version: 0.20.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Model Context Protocol
@@ -10,19 +10,19 @@ cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
- name: json-schema
13
+ name: json_schemer
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: '4.1'
18
+ version: '2.4'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
- version: '4.1'
25
+ version: '2.4'
26
26
  description: The official Ruby SDK for Model Context Protocol servers and clients
27
27
  email:
28
28
  - mcp-support@anthropic.com
@@ -42,11 +42,13 @@ files:
42
42
  - lib/mcp/client.rb
43
43
  - lib/mcp/client/http.rb
44
44
  - lib/mcp/client/oauth.rb
45
+ - lib/mcp/client/oauth/client_credentials_provider.rb
45
46
  - lib/mcp/client/oauth/discovery.rb
46
47
  - lib/mcp/client/oauth/flow.rb
47
48
  - lib/mcp/client/oauth/in_memory_storage.rb
48
49
  - lib/mcp/client/oauth/pkce.rb
49
50
  - lib/mcp/client/oauth/provider.rb
51
+ - lib/mcp/client/oauth/storage_backed_provider.rb
50
52
  - lib/mcp/client/paginated_result.rb
51
53
  - lib/mcp/client/stdio.rb
52
54
  - lib/mcp/client/tool.rb
@@ -80,6 +82,7 @@ files:
80
82
  - lib/mcp/tool/output_schema.rb
81
83
  - lib/mcp/tool/response.rb
82
84
  - lib/mcp/tool/schema.rb
85
+ - lib/mcp/trace_context.rb
83
86
  - lib/mcp/transport.rb
84
87
  - lib/mcp/version.rb
85
88
  homepage: https://ruby.sdk.modelcontextprotocol.io
@@ -87,7 +90,7 @@ licenses:
87
90
  - Apache-2.0
88
91
  metadata:
89
92
  allowed_push_host: https://rubygems.org
90
- changelog_uri: https://github.com/modelcontextprotocol/ruby-sdk/releases/tag/v0.18.0
93
+ changelog_uri: https://github.com/modelcontextprotocol/ruby-sdk/releases/tag/v0.20.0
91
94
  homepage_uri: https://ruby.sdk.modelcontextprotocol.io
92
95
  source_code_uri: https://github.com/modelcontextprotocol/ruby-sdk
93
96
  bug_tracker_uri: https://github.com/modelcontextprotocol/ruby-sdk/issues