mcp 0.23.0 → 0.24.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
@@ -102,8 +102,11 @@ module MCP
102
102
  include Instrumentation
103
103
  include Pagination
104
104
 
105
- attr_accessor :description, :icons, :name, :title, :version, :website_url, :instructions, :tools, :prompts, :resources, :server_context, :configuration, :capabilities, :transport, :logging_message_notification
106
- attr_reader :page_size, :client_capabilities
105
+ # Allowed values for the SEP-2549 `cacheScope` cache hint.
106
+ CACHE_SCOPES = ["public", "private"].freeze
107
+
108
+ attr_accessor :description, :icons, :name, :title, :version, :website_url, :instructions, :tools, :prompts, :resource_templates, :server_context, :configuration, :capabilities, :transport, :logging_message_notification
109
+ attr_reader :resources, :page_size, :client_capabilities, :ttl_ms, :cache_scope
107
110
 
108
111
  def initialize(
109
112
  description: nil,
@@ -121,6 +124,8 @@ module MCP
121
124
  configuration: nil,
122
125
  capabilities: nil,
123
126
  page_size: nil,
127
+ ttl_ms: nil,
128
+ cache_scope: nil,
124
129
  transport: nil
125
130
  )
126
131
  @description = description
@@ -138,6 +143,8 @@ module MCP
138
143
  @resource_index = index_resources_by_uri(resources)
139
144
  @server_context = server_context
140
145
  self.page_size = page_size
146
+ self.ttl_ms = ttl_ms
147
+ self.cache_scope = cache_scope
141
148
  @configuration = MCP.configuration.merge(configuration)
142
149
  @client = nil
143
150
 
@@ -154,7 +161,7 @@ module MCP
154
161
 
155
162
  @handlers = {
156
163
  Methods::RESOURCES_LIST => method(:list_resources),
157
- Methods::RESOURCES_READ => method(:read_resource_no_content),
164
+ Methods::RESOURCES_READ => method(:read_resource),
158
165
  Methods::RESOURCES_TEMPLATES_LIST => method(:list_resource_templates),
159
166
  Methods::RESOURCES_SUBSCRIBE => ->(_) { {} },
160
167
  Methods::RESOURCES_UNSUBSCRIBE => ->(_) { {} },
@@ -163,6 +170,7 @@ module MCP
163
170
  Methods::PROMPTS_LIST => method(:list_prompts),
164
171
  Methods::PROMPTS_GET => method(:get_prompt),
165
172
  Methods::INITIALIZE => method(:init),
173
+ Methods::SERVER_DISCOVER => method(:discover),
166
174
  Methods::PING => ->(_) { {} },
167
175
  Methods::NOTIFICATIONS_INITIALIZED => ->(_) {},
168
176
  Methods::NOTIFICATIONS_PROGRESS => ->(_) {},
@@ -216,6 +224,34 @@ module MCP
216
224
  validate!
217
225
  end
218
226
 
227
+ def define_resource(uri: nil, name: nil, title: nil, description: nil, icons: [], mime_type: nil, annotations: nil, size: nil, meta: nil, &block)
228
+ resource = Resource.define(
229
+ uri: uri, name: name, title: title, description: description, icons: icons,
230
+ mime_type: mime_type, annotations: annotations, size: size, meta: meta,
231
+ &block
232
+ )
233
+ @resources << resource
234
+ @resource_index[resource.uri] = resource
235
+
236
+ validate!
237
+ end
238
+
239
+ def define_resource_template(uri_template: nil, name: nil, title: nil, description: nil, icons: [], mime_type: nil, annotations: nil, meta: nil, &block)
240
+ resource_template = ResourceTemplate.define(
241
+ uri_template: uri_template, name: name, title: title, description: description, icons: icons,
242
+ mime_type: mime_type, annotations: annotations, meta: meta,
243
+ &block
244
+ )
245
+ @resource_templates << resource_template
246
+
247
+ validate!
248
+ end
249
+
250
+ def resources=(resources)
251
+ @resources = resources
252
+ @resource_index = index_resources_by_uri(resources)
253
+ end
254
+
219
255
  def define_custom_method(method_name:, &block)
220
256
  if @handlers.key?(method_name)
221
257
  raise MethodAlreadyDefinedError, method_name
@@ -232,6 +268,27 @@ module MCP
232
268
  @page_size = page_size
233
269
  end
234
270
 
271
+ # SEP-2549 cache hint: freshness lifetime in milliseconds for list and read results
272
+ # (max-age semantics; 0 means do not cache). Emission is opt-in: when both `ttl_ms`
273
+ # and `cache_scope` are nil, results are serialized exactly as before.
274
+ def ttl_ms=(ttl_ms)
275
+ unless ttl_ms.nil? || (ttl_ms.is_a?(Integer) && ttl_ms >= 0)
276
+ raise ArgumentError, "ttl_ms must be nil or a non-negative integer"
277
+ end
278
+
279
+ @ttl_ms = ttl_ms
280
+ end
281
+
282
+ # SEP-2549 cache hint: whether shared intermediaries may cache the result ("public")
283
+ # or only the requesting client ("private").
284
+ def cache_scope=(cache_scope)
285
+ unless cache_scope.nil? || CACHE_SCOPES.include?(cache_scope)
286
+ raise ArgumentError, "cache_scope must be nil, \"public\", or \"private\""
287
+ end
288
+
289
+ @cache_scope = cache_scope
290
+ end
291
+
235
292
  def notify_tools_list_changed
236
293
  return unless @transport
237
294
 
@@ -472,8 +529,9 @@ module MCP
472
529
  when Methods::INITIALIZE
473
530
  init(params, session: session)
474
531
  when Methods::RESOURCES_READ
475
- { contents: read_resource_contents(params, session: session, related_request_id: related_request_id, cancellation: cancellation) }
532
+ build_read_resource_result(read_resource_contents(params, session: session, related_request_id: related_request_id, cancellation: cancellation))
476
533
  when Methods::RESOURCES_SUBSCRIBE, Methods::RESOURCES_UNSUBSCRIBE
534
+ validate_resource_subscription_params!(params)
477
535
  dispatch_optional_context_handler(@handlers[method], params, session: session, related_request_id: related_request_id, cancellation: cancellation)
478
536
  {}
479
537
  when Methods::TOOLS_CALL
@@ -548,6 +606,8 @@ module MCP
548
606
  end
549
607
 
550
608
  def init(params, session: nil)
609
+ validate_initialize_params!(params)
610
+
551
611
  # MCP spec: the initialization phase MUST be the first interaction between client and server.
552
612
  # Reject duplicate `initialize` on an already-initialized session so the negotiated
553
613
  # client identity and capabilities cannot be silently overwritten.
@@ -555,15 +615,13 @@ module MCP
555
615
  raise RequestHandlerError.new("Invalid Request: Server already initialized", params, error_type: :invalid_request)
556
616
  end
557
617
 
558
- if params
559
- if session
560
- session.store_client_info(client: params[:clientInfo], capabilities: params[:capabilities])
561
- else
562
- @client = params[:clientInfo]
563
- @client_capabilities = params[:capabilities]
564
- end
565
- protocol_version = params[:protocolVersion]
618
+ if session
619
+ session.store_client_info(client: params[:clientInfo], capabilities: params[:capabilities])
620
+ else
621
+ @client = params[:clientInfo]
622
+ @client_capabilities = params[:capabilities]
566
623
  end
624
+ protocol_version = params[:protocolVersion]
567
625
 
568
626
  negotiated_version = if Configuration::SUPPORTED_STABLE_PROTOCOL_VERSIONS.include?(protocol_version)
569
627
  protocol_version
@@ -592,6 +650,47 @@ module MCP
592
650
  }.compact
593
651
  end
594
652
 
653
+ def validate_resource_subscription_params!(params)
654
+ unless params.is_a?(Hash) && params[:uri].is_a?(String)
655
+ raise RequestHandlerError.new("Missing or invalid uri", params, error_type: :invalid_params)
656
+ end
657
+ end
658
+
659
+ def validate_initialize_params!(params)
660
+ unless params.is_a?(Hash)
661
+ raise RequestHandlerError.new("Invalid params", params, error_type: :invalid_params)
662
+ end
663
+
664
+ unless params[:protocolVersion].is_a?(String)
665
+ raise RequestHandlerError.new("Missing or invalid protocolVersion", params, error_type: :invalid_params)
666
+ end
667
+
668
+ unless params[:capabilities].is_a?(Hash)
669
+ raise RequestHandlerError.new("Missing or invalid capabilities", params, error_type: :invalid_params)
670
+ end
671
+
672
+ client_info = params[:clientInfo]
673
+ if !client_info.is_a?(Hash) || client_info[:name].nil? || client_info[:version].nil?
674
+ raise RequestHandlerError.new("Missing or invalid clientInfo", params, error_type: :invalid_params)
675
+ end
676
+ end
677
+
678
+ # Handles `server/discover` (MCP 2026-07-28 draft, SEP-2575): sessionless capability discovery.
679
+ # Unlike `init`, this is state-free and idempotent: it stores no client info, does not mark
680
+ # the session initialized, and responds regardless of capability declarations or initialization state,
681
+ # so clients can probe a server before (or instead of) `initialize`. `serverInfo` is returned unfiltered
682
+ # because discovery happens before version negotiation. The draft's `ttlMs`/`cacheScope` cache hints
683
+ # are not included here yet.
684
+ # https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2575
685
+ def discover(_request)
686
+ {
687
+ supportedVersions: Configuration::SUPPORTED_STABLE_PROTOCOL_VERSIONS,
688
+ capabilities: capabilities,
689
+ serverInfo: server_info,
690
+ instructions: instructions,
691
+ }.compact
692
+ end
693
+
595
694
  def configure_logging_level(request, session: nil)
596
695
  if capabilities[:logging].nil?
597
696
  raise RequestHandlerError.new("Server does not support logging", request, error_type: :internal_error)
@@ -611,7 +710,7 @@ module MCP
611
710
  def list_tools(request)
612
711
  page = paginate(@tools.values, cursor: cursor_from(request), page_size: @page_size, request: request, &:to_h)
613
712
 
614
- { tools: page[:items], nextCursor: page[:next_cursor] }.compact
713
+ apply_cache_metadata({ tools: page[:items], nextCursor: page[:next_cursor] }.compact)
615
714
  end
616
715
 
617
716
  def call_tool(request, session: nil, related_request_id: nil, cancellation: nil)
@@ -667,7 +766,7 @@ module MCP
667
766
  def list_prompts(request)
668
767
  page = paginate(@prompts.values, cursor: cursor_from(request), page_size: @page_size, request: request, &:to_h)
669
768
 
670
- { prompts: page[:items], nextCursor: page[:next_cursor] }.compact
769
+ apply_cache_metadata({ prompts: page[:items], nextCursor: page[:next_cursor] }.compact)
671
770
  end
672
771
 
673
772
  def get_prompt(request, session: nil, related_request_id: nil, cancellation: nil)
@@ -696,19 +795,91 @@ module MCP
696
795
  def list_resources(request)
697
796
  page = paginate(@resources, cursor: cursor_from(request), page_size: @page_size, request: request, &:to_h)
698
797
 
699
- { resources: page[:items], nextCursor: page[:next_cursor] }.compact
798
+ apply_cache_metadata({ resources: page[:items], nextCursor: page[:next_cursor] }.compact)
799
+ end
800
+
801
+ # Default `resources/read` handler: routes to class-based resources and resource templates.
802
+ # Fully replaced when `resources_read_handler` is set. When no class-based resource or template is registered,
803
+ # unknown URIs keep the historical no-op `[]` response instead of raising.
804
+ def read_resource(request, server_context: nil)
805
+ uri = request[:uri]
806
+ add_instrumentation_data(resource_uri: uri)
807
+
808
+ resource = @resource_index[uri]
809
+ if resource.is_a?(Class)
810
+ return normalize_resource_contents(call_resource_contents(resource, server_context))
811
+ end
812
+
813
+ @resource_templates.each do |template|
814
+ next unless template.is_a?(Class)
815
+
816
+ params = template.match_uri(uri)
817
+ next unless params
818
+
819
+ add_instrumentation_data(resource_template: template.uri_template)
820
+ return normalize_resource_contents(call_template_contents(template, params, server_context))
821
+ end
822
+
823
+ return [] unless class_based_resources_registered?
824
+
825
+ raise ResourceNotFoundError.new(uri, request)
700
826
  end
701
827
 
702
- # Server implementation should set `resources_read_handler` to override no-op default
703
- def read_resource_no_content(request)
704
- add_instrumentation_data(resource_uri: request[:uri])
705
- []
828
+ def call_resource_contents(resource, server_context)
829
+ if accepts_server_context?(resource.method(:contents))
830
+ resource.contents(server_context: server_context)
831
+ else
832
+ resource.contents
833
+ end
834
+ end
835
+
836
+ def call_template_contents(template, params, server_context)
837
+ if accepts_server_context?(template.method(:contents))
838
+ template.contents(**params, server_context: server_context)
839
+ else
840
+ template.contents(**params)
841
+ end
842
+ end
843
+
844
+ def normalize_resource_contents(result)
845
+ contents = result.is_a?(Array) ? result : [result]
846
+ contents.map(&:to_h)
847
+ end
848
+
849
+ def class_based_resources_registered?
850
+ @resources.any? { |resource| resource.is_a?(Class) } ||
851
+ @resource_templates.any? { |template| template.is_a?(Class) }
706
852
  end
707
853
 
708
854
  def list_resource_templates(request)
709
855
  page = paginate(@resource_templates, cursor: cursor_from(request), page_size: @page_size, request: request, &:to_h)
710
856
 
711
- { resourceTemplates: page[:items], nextCursor: page[:next_cursor] }.compact
857
+ apply_cache_metadata({ resourceTemplates: page[:items], nextCursor: page[:next_cursor] }.compact)
858
+ end
859
+
860
+ # Builds the `resources/read` result. The documented handler contract is "return value becomes `contents`";
861
+ # a Hash with a `:contents` key is also accepted as a full result so a handler can override the server-level
862
+ # `ttlMs`/`cacheScope` cache hints per result (SEP-2549).
863
+ def build_read_resource_result(handler_result)
864
+ result = if handler_result.is_a?(Hash) && handler_result.key?(:contents)
865
+ handler_result
866
+ else
867
+ { contents: handler_result }
868
+ end
869
+
870
+ apply_cache_metadata(result)
871
+ end
872
+
873
+ # Adds the SEP-2549 cache hints (`ttlMs`, `cacheScope`) to a result. Emission is opt-in: nothing is added
874
+ # unless the server was configured with `ttl_ms`/`cache_scope` or the result already carries one of the fields, in
875
+ # which case the missing one is filled with the spec defaults (`ttlMs: 0` = do not cache, `cacheScope: "public"`).
876
+ # Values already in the result win, enabling per-result overrides.
877
+ # https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2549
878
+ def apply_cache_metadata(result)
879
+ explicit = result.key?(:ttlMs) || result.key?(:cacheScope)
880
+ return result if @ttl_ms.nil? && @cache_scope.nil? && !explicit
881
+
882
+ { ttlMs: @ttl_ms || 0, cacheScope: @cache_scope || "public" }.merge(result)
712
883
  end
713
884
 
714
885
  def complete(params, session: nil, related_request_id: nil, cancellation: nil)
@@ -54,6 +54,9 @@ module MCP
54
54
  end
55
55
 
56
56
  # Delegates to the session so the request is scoped to the originating client.
57
+ # The originating request id is stamped as `related_request_id`, satisfying
58
+ # SEP-2260's requirement that server-to-client requests be associated with
59
+ # the client request being processed.
57
60
  # @deprecated MCP Roots (`roots/list` and
58
61
  # `notifications/roots/list_changed`) is deprecated as of MCP protocol
59
62
  # version 2026-07-28 (SEP-2577). Use tool parameters, resource URIs,
@@ -91,6 +94,11 @@ module MCP
91
94
  # Delegates to the session so the request is scoped to the originating client.
92
95
  # Falls back to `@context` (via `method_missing`) when `@notification_target`
93
96
  # does not support sampling.
97
+ #
98
+ # The originating request id is stamped as `related_request_id` and cannot be
99
+ # overridden by callers (the literal keyword after `**kwargs` wins),
100
+ # satisfying SEP-2260's requirement that server-to-client requests be
101
+ # associated with the client request being processed.
94
102
  # @deprecated MCP Sampling (`sampling/createMessage`) is deprecated as of
95
103
  # MCP protocol version 2026-07-28 (SEP-2577). Use direct LLM provider
96
104
  # APIs instead.
@@ -107,6 +115,8 @@ module MCP
107
115
  # Delegates to the session so the request is scoped to the originating client.
108
116
  # Falls back to `@context` (via `method_missing`) when `@notification_target`
109
117
  # does not support elicitation.
118
+ # The originating request id is stamped as a non-overridable
119
+ # `related_request_id`, as with `create_sampling_message` (SEP-2260).
110
120
  def create_form_elicitation(**kwargs)
111
121
  if @notification_target.respond_to?(:create_form_elicitation)
112
122
  @notification_target.create_form_elicitation(**kwargs, related_request_id: @related_request_id)
@@ -119,6 +129,8 @@ module MCP
119
129
 
120
130
  # Delegates to the session so the request is scoped to the originating client.
121
131
  # Falls back to `@context` when `@notification_target` does not support URL mode elicitation.
132
+ # The originating request id is stamped as a non-overridable `related_request_id`,
133
+ # as with `create_sampling_message` (SEP-2260).
122
134
  def create_url_elicitation(**kwargs)
123
135
  if @notification_target.respond_to?(:create_url_elicitation)
124
136
  @notification_target.create_url_elicitation(**kwargs, related_request_id: @related_request_id)
@@ -98,11 +98,17 @@ module MCP
98
98
  end
99
99
 
100
100
  # Sends a `roots/list` request scoped to this session.
101
+ #
102
+ # Per SEP-2260, the request must be associated with an originating client
103
+ # request; prefer `server_context.list_roots` inside a handler, which stamps
104
+ # the association automatically.
101
105
  # @deprecated MCP Roots (`roots/list` and
102
106
  # `notifications/roots/list_changed`) is deprecated as of MCP protocol
103
107
  # version 2026-07-28 (SEP-2577). Use tool parameters, resource URIs,
104
108
  # server configuration, or environment variables instead.
105
109
  def list_roots(related_request_id: nil)
110
+ warn_unassociated_request(__method__, related_request_id)
111
+
106
112
  unless client_capabilities&.dig(:roots)
107
113
  raise "Client does not support roots."
108
114
  end
@@ -119,16 +125,28 @@ module MCP
119
125
  end
120
126
 
121
127
  # Sends a `sampling/createMessage` request scoped to this session.
128
+ #
129
+ # Per SEP-2260, the request must be associated with an originating client
130
+ # request; prefer `server_context.create_sampling_message` inside a handler,
131
+ # which stamps the association automatically.
122
132
  # @deprecated MCP Sampling (`sampling/createMessage`) is deprecated as of
123
133
  # MCP protocol version 2026-07-28 (SEP-2577). Use direct LLM provider
124
134
  # APIs instead.
125
135
  def create_sampling_message(related_request_id: nil, **kwargs)
136
+ warn_unassociated_request(__method__, related_request_id)
137
+
126
138
  params = @server.build_sampling_params(client_capabilities, **kwargs)
127
139
  send_to_transport_request(Methods::SAMPLING_CREATE_MESSAGE, params, related_request_id: related_request_id)
128
140
  end
129
141
 
130
142
  # Sends an `elicitation/create` request (form mode) scoped to this session.
143
+ #
144
+ # Per SEP-2260, the request must be associated with an originating client
145
+ # request; prefer `server_context.create_form_elicitation` inside a handler,
146
+ # which stamps the association automatically.
131
147
  def create_form_elicitation(message:, requested_schema:, related_request_id: nil)
148
+ warn_unassociated_request(__method__, related_request_id)
149
+
132
150
  unless client_capabilities&.dig(:elicitation)
133
151
  raise "Client does not support elicitation. " \
134
152
  "The client must declare the `elicitation` capability during initialization."
@@ -139,7 +157,13 @@ module MCP
139
157
  end
140
158
 
141
159
  # Sends an `elicitation/create` request (URL mode) scoped to this session.
160
+ #
161
+ # Per SEP-2260, the request must be associated with an originating client
162
+ # request; prefer `server_context.create_url_elicitation` inside a handler,
163
+ # which stamps the association automatically.
142
164
  def create_url_elicitation(message:, url:, elicitation_id:, related_request_id: nil)
165
+ warn_unassociated_request(__method__, related_request_id)
166
+
143
167
  unless client_capabilities&.dig(:elicitation, :url)
144
168
  raise "Client does not support URL mode elicitation. " \
145
169
  "The client must declare the `elicitation.url` capability during initialization."
@@ -264,5 +288,21 @@ module MCP
264
288
  # The explicit splat suppresses that conversion and is a no-op when `supported` is empty.
265
289
  transport_method.call(method, params, **supported)
266
290
  end
291
+
292
+ # Per SEP-2260, servers MUST send `roots/list`, `sampling/createMessage`, and `elicitation/create` only
293
+ # in association with an originating client request (`ping` is exempt). A request without `related_request_id:` is
294
+ # delivered on the standalone GET stream by the Streamable HTTP transport, which the 2026-07-28 spec forbids;
295
+ # warn so callers migrate to the `server_context` helpers before this becomes an error.
296
+ # https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2260
297
+ def warn_unassociated_request(method_name, related_request_id)
298
+ return if related_request_id
299
+
300
+ warn(
301
+ "Calling `ServerSession##{method_name}` without `related_request_id:` is deprecated (SEP-2260): " \
302
+ "server-to-client #{method_name} requests must be associated with an originating client request. " \
303
+ "Use `server_context.#{method_name}` inside a handler, or pass `related_request_id:` explicitly.",
304
+ uplevel: 2,
305
+ )
306
+ end
267
307
  end
268
308
  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.23.0"
4
+ VERSION = "0.24.0"
5
5
  end
data/lib/mcp.rb CHANGED
@@ -8,14 +8,17 @@ require_relative "mcp/version"
8
8
 
9
9
  module MCP
10
10
  autoload :Annotations, "mcp/annotations"
11
+ autoload :Apps, "mcp/apps"
11
12
  autoload :Cancellation, "mcp/cancellation"
12
13
  autoload :CancelledError, "mcp/cancelled_error"
13
14
  autoload :Client, "mcp/client"
14
15
  autoload :Content, "mcp/content"
16
+ autoload :ErrorCodes, "mcp/error_codes"
15
17
  autoload :Icon, "mcp/icon"
16
18
  autoload :Prompt, "mcp/prompt"
17
19
  autoload :Resource, "mcp/resource"
18
20
  autoload :ResourceTemplate, "mcp/resource_template"
21
+ autoload :ResultType, "mcp/result_type"
19
22
  autoload :Server, "mcp/server"
20
23
  autoload :ServerSession, "mcp/server_session"
21
24
  autoload :Tool, "mcp/tool"
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.23.0
4
+ version: 0.24.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Model Context Protocol
@@ -37,15 +37,18 @@ files:
37
37
  - lib/json_rpc_handler.rb
38
38
  - lib/mcp.rb
39
39
  - lib/mcp/annotations.rb
40
+ - lib/mcp/apps.rb
40
41
  - lib/mcp/cancellation.rb
41
42
  - lib/mcp/cancelled_error.rb
42
43
  - lib/mcp/client.rb
44
+ - lib/mcp/client/elicitation.rb
43
45
  - lib/mcp/client/http.rb
44
46
  - lib/mcp/client/oauth.rb
45
47
  - lib/mcp/client/oauth/client_credentials_provider.rb
46
48
  - lib/mcp/client/oauth/discovery.rb
47
49
  - lib/mcp/client/oauth/flow.rb
48
50
  - lib/mcp/client/oauth/in_memory_storage.rb
51
+ - lib/mcp/client/oauth/jwt_client_assertion.rb
49
52
  - lib/mcp/client/oauth/pkce.rb
50
53
  - lib/mcp/client/oauth/provider.rb
51
54
  - lib/mcp/client/oauth/storage_backed_provider.rb
@@ -54,6 +57,7 @@ files:
54
57
  - lib/mcp/client/tool.rb
55
58
  - lib/mcp/configuration.rb
56
59
  - lib/mcp/content.rb
60
+ - lib/mcp/error_codes.rb
57
61
  - lib/mcp/icon.rb
58
62
  - lib/mcp/instrumentation.rb
59
63
  - lib/mcp/logging_message_notification.rb
@@ -67,6 +71,7 @@ files:
67
71
  - lib/mcp/resource/contents.rb
68
72
  - lib/mcp/resource/embedded.rb
69
73
  - lib/mcp/resource_template.rb
74
+ - lib/mcp/result_type.rb
70
75
  - lib/mcp/server.rb
71
76
  - lib/mcp/server/capabilities.rb
72
77
  - lib/mcp/server/pagination.rb
@@ -90,7 +95,7 @@ licenses:
90
95
  - Apache-2.0
91
96
  metadata:
92
97
  allowed_push_host: https://rubygems.org
93
- changelog_uri: https://github.com/modelcontextprotocol/ruby-sdk/releases/tag/v0.23.0
98
+ changelog_uri: https://github.com/modelcontextprotocol/ruby-sdk/releases/tag/v0.24.0
94
99
  homepage_uri: https://ruby.sdk.modelcontextprotocol.io
95
100
  source_code_uri: https://github.com/modelcontextprotocol/ruby-sdk
96
101
  bug_tracker_uri: https://github.com/modelcontextprotocol/ruby-sdk/issues