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.
- checksums.yaml +4 -4
- data/README.md +92 -3
- data/lib/json_rpc_handler.rb +7 -2
- data/lib/mcp/client/http.rb +68 -7
- data/lib/mcp/client/oauth/client_credentials_provider.rb +89 -0
- data/lib/mcp/client/oauth/discovery.rb +55 -1
- data/lib/mcp/client/oauth/flow.rb +138 -9
- data/lib/mcp/client/oauth/provider.rb +42 -27
- data/lib/mcp/client/oauth/storage_backed_provider.rb +43 -0
- data/lib/mcp/client/oauth.rb +3 -1
- data/lib/mcp/client.rb +71 -79
- data/lib/mcp/configuration.rb +1 -0
- data/lib/mcp/resource.rb +6 -2
- data/lib/mcp/resource_template.rb +4 -2
- data/lib/mcp/server/transports/streamable_http_transport.rb +51 -31
- data/lib/mcp/server.rb +27 -1
- data/lib/mcp/tool/input_schema.rb +2 -2
- data/lib/mcp/tool/schema.rb +38 -19
- data/lib/mcp/trace_context.rb +23 -0
- data/lib/mcp/version.rb +1 -1
- data/lib/mcp.rb +1 -0
- metadata +8 -5
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
|
|
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)
|
data/lib/mcp/tool/schema.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "digest"
|
|
4
|
-
require "
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
96
|
-
#
|
|
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
data/lib/mcp.rb
CHANGED
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.
|
|
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:
|
|
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
|
|
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
|
|
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.
|
|
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
|