mcp 0.7.1 → 0.9.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: 1358d86b880959c1608cba8b747c9a13de95b9811f339c2d5811a3a18c7df410
4
- data.tar.gz: ba8d2d0d5071468b56570830f579cdf5ab1d3f2b683c31722d7ed49b90fcc71b
3
+ metadata.gz: d5cd1f7d23be518ff8bff1b1710ff8e8c4ba86ba3d55417e991f921057c0841d
4
+ data.tar.gz: 8e6bba0111698a39ff5aeaa0b4a34e51822018ac943b13b828f9bd2965062ddb
5
5
  SHA512:
6
- metadata.gz: 44b4b01136379f1136084654534536fd269963ba2a010dda528a3b890a5f5416e54f0500e42154725aa9d5e594bedd7fd1944a20da89d2ff81bc9eb7b86e25fe
7
- data.tar.gz: 8ac611adc761a1ddcbf5a0e5b51dcc8c0ec8f9a5f7f072bf9fa226b0db0eb439ebfca73c7e923f3820088375c40e5d30b319fcd1b7b4ffbcd304e0c23d36ac9c
6
+ metadata.gz: 1f9689d2ecb0a2b4e5ba6888e515d577a12d1f41cd48be8459c2d90ad3b7e4cbe7f557c23aac134a8426bf7bfaba2c3579ab496817ade2ff0fd24056286e52cd
7
+ data.tar.gz: 03601ddc6bf751a75ec6bbadc67458ab9d49367feac7b834d90072028e41a2d1046ed3da6551832482884f435c8779620071f1aa5df66753cf9afade090eb220
data/README.md CHANGED
@@ -108,11 +108,12 @@ The server supports sending notifications to clients when lists of tools, prompt
108
108
 
109
109
  #### Notification Methods
110
110
 
111
- The server provides three notification methods:
111
+ The server provides the following notification methods:
112
112
 
113
113
  - `notify_tools_list_changed` - Send a notification when the tools list changes
114
114
  - `notify_prompts_list_changed` - Send a notification when the prompts list changes
115
115
  - `notify_resources_list_changed` - Send a notification when the resources list changes
116
+ - `notify_progress` - Send a progress notification for long-running operations
116
117
  - `notify_log_message` - Send a structured logging notification message
117
118
 
118
119
  #### Notification Format
@@ -122,8 +123,72 @@ Notifications follow the JSON-RPC 2.0 specification and use these method names:
122
123
  - `notifications/tools/list_changed`
123
124
  - `notifications/prompts/list_changed`
124
125
  - `notifications/resources/list_changed`
126
+ - `notifications/progress`
125
127
  - `notifications/message`
126
128
 
129
+ ### Progress
130
+
131
+ The MCP Ruby SDK supports progress tracking for long-running tool operations,
132
+ following the [MCP Progress specification](https://modelcontextprotocol.io/specification/latest/server/utilities/progress).
133
+
134
+ #### How Progress Works
135
+
136
+ 1. **Client Request**: The client sends a `progressToken` in the `_meta` field when calling a tool
137
+ 2. **Server Notification**: The server sends `notifications/progress` messages back to the client during tool execution
138
+ 3. **Tool Integration**: Tools call `server_context.report_progress` to report incremental progress
139
+
140
+ #### Server-Side: Tool with Progress
141
+
142
+ Tools that accept a `server_context:` parameter can call `report_progress` on it.
143
+ The server automatically wraps the context in an `MCP::ServerContext` instance that provides this method:
144
+
145
+ ```ruby
146
+ class LongRunningTool < MCP::Tool
147
+ description "A tool that reports progress during execution"
148
+ input_schema(
149
+ properties: {
150
+ count: { type: "integer" },
151
+ },
152
+ required: ["count"]
153
+ )
154
+
155
+ def self.call(count:, server_context:)
156
+ count.times do |i|
157
+ # Do work here.
158
+ server_context.report_progress(i + 1, total: count, message: "Processing item #{i + 1}")
159
+ end
160
+
161
+ MCP::Tool::Response.new([{ type: "text", text: "Done" }])
162
+ end
163
+ end
164
+ ```
165
+
166
+ The `server_context.report_progress` method accepts:
167
+
168
+ - `progress` (required) — current progress value (numeric)
169
+ - `total:` (optional) — total expected value, so clients can display a percentage
170
+ - `message:` (optional) — human-readable status message
171
+
172
+ #### Server-Side: Direct `notify_progress` Usage
173
+
174
+ You can also call `notify_progress` directly on the server instance:
175
+
176
+ ```ruby
177
+ server.notify_progress(
178
+ progress_token: "token-123",
179
+ progress: 50,
180
+ total: 100, # optional
181
+ message: "halfway" # optional
182
+ )
183
+ ```
184
+
185
+ **Key Features:**
186
+
187
+ - Tools report progress via `server_context.report_progress`
188
+ - `report_progress` is a no-op when no `progressToken` was provided by the client
189
+ - `notify_progress` is a no-op when no transport is configured
190
+ - Supports both numeric and string progress tokens
191
+
127
192
  ### Logging
128
193
 
129
194
  The MCP Ruby SDK supports structured logging through the `notify_log_message` method, following the [MCP Logging specification](https://modelcontextprotocol.io/specification/latest/server/utilities/logging).
@@ -242,11 +307,12 @@ When added to a Rails controller on a route that handles POST requests, your ser
242
307
  [Streamable HTTP](https://modelcontextprotocol.io/specification/latest/basic/transports#streamable-http) transport
243
308
  requests.
244
309
 
245
- You can use the `Server#handle_json` method to handle requests.
310
+ You can use `StreamableHTTPTransport#handle_request` to handle requests with proper HTTP
311
+ status codes (e.g., 202 Accepted for notifications).
246
312
 
247
313
  ```ruby
248
- class ApplicationController < ActionController::Base
249
- def index
314
+ class McpController < ActionController::Base
315
+ def create
250
316
  server = MCP::Server.new(
251
317
  name: "my_server",
252
318
  title: "Example Server Display Name",
@@ -256,7 +322,11 @@ class ApplicationController < ActionController::Base
256
322
  prompts: [MyPrompt],
257
323
  server_context: { user_id: current_user.id },
258
324
  )
259
- render(json: server.handle_json(request.body.read))
325
+ transport = MCP::Server::Transports::StreamableHTTPTransport.new(server)
326
+ server.transport = transport
327
+ status, headers, body = transport.handle_request(request)
328
+
329
+ render(json: body.first, status: status, headers: headers)
260
330
  end
261
331
  end
262
332
  ```
@@ -375,6 +445,50 @@ server = MCP::Server.new(
375
445
 
376
446
  This hash is then passed as the `server_context` argument to tool and prompt calls, and is included in exception and instrumentation callbacks.
377
447
 
448
+ #### Request-specific `_meta` Parameter
449
+
450
+ The MCP protocol supports a special [`_meta` parameter](https://modelcontextprotocol.io/specification/2025-06-18/basic#general-fields) in requests that allows clients to pass request-specific metadata. The server automatically extracts this parameter and makes it available to tools and prompts as a nested field within the `server_context`.
451
+
452
+ **Access Pattern:**
453
+
454
+ When a client includes `_meta` in the request params, it becomes available as `server_context[:_meta]`:
455
+
456
+ ```ruby
457
+ class MyTool < MCP::Tool
458
+ def self.call(message:, server_context:)
459
+ # Access provider-specific metadata
460
+ session_id = server_context.dig(:_meta, :session_id)
461
+ request_id = server_context.dig(:_meta, :request_id)
462
+
463
+ # Access server's original context
464
+ user_id = server_context.dig(:user_id)
465
+
466
+ MCP::Tool::Response.new([{
467
+ type: "text",
468
+ text: "Processing for user #{user_id} in session #{session_id}"
469
+ }])
470
+ end
471
+ end
472
+ ```
473
+
474
+ **Client Request Example:**
475
+
476
+ ```json
477
+ {
478
+ "jsonrpc": "2.0",
479
+ "id": 1,
480
+ "method": "tools/call",
481
+ "params": {
482
+ "name": "my_tool",
483
+ "arguments": { "message": "Hello" },
484
+ "_meta": {
485
+ "session_id": "abc123",
486
+ "request_id": "req_456"
487
+ }
488
+ }
489
+ }
490
+ ```
491
+
378
492
  #### Configuration Block Data
379
493
 
380
494
  ##### Exception Reporter
@@ -968,6 +1082,52 @@ class CustomTransport
968
1082
  end
969
1083
  ```
970
1084
 
1085
+ ### Stdio Transport Layer
1086
+
1087
+ Use the `MCP::Client::Stdio` transport to interact with MCP servers running as subprocesses over standard input/output.
1088
+
1089
+ `MCP::Client::Stdio.new` accepts the following keyword arguments:
1090
+
1091
+ | Parameter | Required | Description |
1092
+ |---|---|---|
1093
+ | `command:` | Yes | The command to spawn the server process (e.g., `"ruby"`, `"bundle"`, `"npx"`). |
1094
+ | `args:` | No | An array of arguments passed to the command. Defaults to `[]`. |
1095
+ | `env:` | No | A hash of environment variables to set for the server process. Defaults to `nil`. |
1096
+ | `read_timeout:` | No | Timeout in seconds for waiting for a server response. Defaults to `nil` (no timeout). |
1097
+
1098
+ Example usage:
1099
+
1100
+ ```ruby
1101
+ stdio_transport = MCP::Client::Stdio.new(
1102
+ command: "bundle",
1103
+ args: ["exec", "ruby", "path/to/server.rb"],
1104
+ env: { "API_KEY" => "my_secret_key" },
1105
+ read_timeout: 30
1106
+ )
1107
+ client = MCP::Client.new(transport: stdio_transport)
1108
+
1109
+ # List available tools.
1110
+ tools = client.tools
1111
+ tools.each do |tool|
1112
+ puts "Tool: #{tool.name} - #{tool.description}"
1113
+ end
1114
+
1115
+ # Call a specific tool.
1116
+ response = client.call_tool(
1117
+ tool: tools.first,
1118
+ arguments: { message: "Hello, world!" }
1119
+ )
1120
+
1121
+ # Close the transport when done.
1122
+ stdio_transport.close
1123
+ ```
1124
+
1125
+ The stdio transport automatically handles:
1126
+
1127
+ - Spawning the server process with `Open3.popen3`
1128
+ - MCP protocol initialization handshake (`initialize` request + `notifications/initialized`)
1129
+ - JSON-RPC 2.0 message framing over newline-delimited JSON
1130
+
971
1131
  ### HTTP Transport Layer
972
1132
 
973
1133
  Use the `MCP::Client::HTTP` transport to interact with MCP servers using simple HTTP requests.
@@ -1000,8 +1160,17 @@ response = client.call_tool(
1000
1160
  tool: tools.first,
1001
1161
  arguments: { message: "Hello, world!" }
1002
1162
  )
1163
+
1164
+ # Call a tool with progress tracking.
1165
+ response = client.call_tool(
1166
+ tool: tools.first,
1167
+ arguments: { count: 10 },
1168
+ progress_token: "my-progress-token"
1169
+ )
1003
1170
  ```
1004
1171
 
1172
+ The server will send `notifications/progress` back to the client during execution.
1173
+
1005
1174
  #### HTTP Authorization
1006
1175
 
1007
1176
  By default, the HTTP transport layer provides no authentication to the server, but you can provide custom headers if you need authentication. For example, to use Bearer token authentication:
@@ -1028,6 +1197,12 @@ The client provides a wrapper class for tools returned by the server:
1028
1197
 
1029
1198
  This class provides easy access to tool properties like name, description, input schema, and output schema.
1030
1199
 
1200
+ ## Conformance Testing
1201
+
1202
+ The `conformance/` directory contains a test server and runner that validate the SDK against the MCP specification using [`@modelcontextprotocol/conformance`](https://github.com/modelcontextprotocol/conformance).
1203
+
1204
+ See [conformance/README.md](conformance/README.md) for usage instructions.
1205
+
1031
1206
  ## Documentation
1032
1207
 
1033
1208
  - [SDK API documentation](https://rubydoc.info/gems/mcp)
@@ -0,0 +1,222 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "open3"
5
+ require "securerandom"
6
+ require "timeout"
7
+ require_relative "../../json_rpc_handler"
8
+ require_relative "../configuration"
9
+ require_relative "../methods"
10
+ require_relative "../version"
11
+
12
+ module MCP
13
+ class Client
14
+ class Stdio
15
+ # Seconds to wait for the server process to exit before sending SIGTERM.
16
+ # Matches the Python and TypeScript SDKs' shutdown timeout:
17
+ # https://github.com/modelcontextprotocol/python-sdk/blob/v1.26.0/src/mcp/client/stdio/__init__.py#L48
18
+ # https://github.com/modelcontextprotocol/typescript-sdk/blob/v1.27.1/src/client/stdio.ts#L221
19
+ CLOSE_TIMEOUT = 2
20
+ STDERR_READ_SIZE = 4096
21
+
22
+ attr_reader :command, :args, :env
23
+
24
+ def initialize(command:, args: [], env: nil, read_timeout: nil)
25
+ @command = command
26
+ @args = args
27
+ @env = env
28
+ @read_timeout = read_timeout
29
+ @stdin = nil
30
+ @stdout = nil
31
+ @stderr = nil
32
+ @wait_thread = nil
33
+ @stderr_thread = nil
34
+ @started = false
35
+ @initialized = false
36
+ end
37
+
38
+ def send_request(request:)
39
+ start unless @started
40
+ initialize_session unless @initialized
41
+
42
+ write_message(request)
43
+ read_response(request)
44
+ end
45
+
46
+ def start
47
+ raise "MCP::Client::Stdio already started" if @started
48
+
49
+ spawn_env = @env || {}
50
+ @stdin, @stdout, @stderr, @wait_thread = Open3.popen3(spawn_env, @command, *@args)
51
+ @stdout.set_encoding("UTF-8")
52
+ @stdin.set_encoding("UTF-8")
53
+
54
+ # Drain stderr in the background to prevent the pipe buffer from filling up,
55
+ # which would cause the server process to block and deadlock.
56
+ @stderr_thread = Thread.new do
57
+ loop do
58
+ @stderr.readpartial(STDERR_READ_SIZE)
59
+ end
60
+ rescue IOError
61
+ nil
62
+ end
63
+
64
+ @started = true
65
+ rescue Errno::ENOENT, Errno::EACCES, Errno::ENOEXEC => e
66
+ raise RequestHandlerError.new(
67
+ "Failed to spawn server process: #{e.message}",
68
+ {},
69
+ error_type: :internal_error,
70
+ original_error: e,
71
+ )
72
+ end
73
+
74
+ def close
75
+ return unless @started
76
+
77
+ @stdin.close
78
+ @stdout.close
79
+ @stderr.close
80
+
81
+ begin
82
+ Timeout.timeout(CLOSE_TIMEOUT) { @wait_thread.value }
83
+ rescue Timeout::Error
84
+ begin
85
+ Process.kill("TERM", @wait_thread.pid)
86
+ Timeout.timeout(CLOSE_TIMEOUT) { @wait_thread.value }
87
+ rescue Timeout::Error
88
+ begin
89
+ Process.kill("KILL", @wait_thread.pid)
90
+ rescue Errno::ESRCH
91
+ nil
92
+ end
93
+ rescue Errno::ESRCH
94
+ nil
95
+ end
96
+ end
97
+
98
+ @stderr_thread.join(CLOSE_TIMEOUT)
99
+ @started = false
100
+ @initialized = false
101
+ end
102
+
103
+ private
104
+
105
+ # The client MUST send a protocol version it supports. This SHOULD be the latest version.
106
+ # https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#version-negotiation
107
+ #
108
+ # Always sends `LATEST_STABLE_PROTOCOL_VERSION`, matching the Python and TypeScript SDKs:
109
+ # https://github.com/modelcontextprotocol/python-sdk/blob/v1.26.0/src/mcp/client/session.py#L175
110
+ # https://github.com/modelcontextprotocol/typescript-sdk/blob/v1.27.1/src/client/index.ts#L495
111
+ def initialize_session
112
+ init_request = {
113
+ jsonrpc: JsonRpcHandler::Version::V2_0,
114
+ id: SecureRandom.uuid,
115
+ method: MCP::Methods::INITIALIZE,
116
+ params: {
117
+ protocolVersion: MCP::Configuration::LATEST_STABLE_PROTOCOL_VERSION,
118
+ capabilities: {},
119
+ clientInfo: { name: "mcp-ruby-client", version: MCP::VERSION },
120
+ },
121
+ }
122
+
123
+ write_message(init_request)
124
+ response = read_response(init_request)
125
+
126
+ if response.key?("error")
127
+ error = response["error"]
128
+ raise RequestHandlerError.new(
129
+ "Server initialization failed: #{error["message"]}",
130
+ { method: MCP::Methods::INITIALIZE },
131
+ error_type: :internal_error,
132
+ )
133
+ end
134
+
135
+ unless response.key?("result")
136
+ raise RequestHandlerError.new(
137
+ "Server initialization failed: missing result in response",
138
+ { method: MCP::Methods::INITIALIZE },
139
+ error_type: :internal_error,
140
+ )
141
+ end
142
+
143
+ notification = {
144
+ jsonrpc: JsonRpcHandler::Version::V2_0,
145
+ method: MCP::Methods::NOTIFICATIONS_INITIALIZED,
146
+ }
147
+ write_message(notification)
148
+
149
+ @initialized = true
150
+ end
151
+
152
+ def write_message(message)
153
+ ensure_running!
154
+ json = JSON.generate(message)
155
+ @stdin.puts(json)
156
+ @stdin.flush
157
+ rescue IOError, Errno::EPIPE => e
158
+ raise RequestHandlerError.new(
159
+ "Failed to write to server process",
160
+ {},
161
+ error_type: :internal_error,
162
+ original_error: e,
163
+ )
164
+ end
165
+
166
+ def read_response(request)
167
+ request_id = request[:id] || request["id"]
168
+ method = request[:method] || request["method"]
169
+ params = request[:params] || request["params"]
170
+
171
+ loop do
172
+ ensure_running!
173
+ wait_for_readable!(method, params) if @read_timeout
174
+ line = @stdout.gets
175
+ raise_connection_error!(method, params) if line.nil?
176
+
177
+ parsed = JSON.parse(line.strip)
178
+
179
+ next unless parsed.key?("id")
180
+
181
+ return parsed if parsed["id"] == request_id
182
+ end
183
+ rescue JSON::ParserError => e
184
+ raise RequestHandlerError.new(
185
+ "Failed to parse server response",
186
+ { method: method, params: params },
187
+ error_type: :internal_error,
188
+ original_error: e,
189
+ )
190
+ end
191
+
192
+ def ensure_running!
193
+ return if @wait_thread.alive?
194
+
195
+ raise RequestHandlerError.new(
196
+ "Server process has exited",
197
+ {},
198
+ error_type: :internal_error,
199
+ )
200
+ end
201
+
202
+ def wait_for_readable!(method, params)
203
+ ready = @stdout.wait_readable(@read_timeout)
204
+ return if ready
205
+
206
+ raise RequestHandlerError.new(
207
+ "Timed out waiting for server response",
208
+ { method: method, params: params },
209
+ error_type: :internal_error,
210
+ )
211
+ end
212
+
213
+ def raise_connection_error!(method, params)
214
+ raise RequestHandlerError.new(
215
+ "Server process closed stdout unexpectedly",
216
+ { method: method, params: params },
217
+ error_type: :internal_error,
218
+ )
219
+ end
220
+ end
221
+ end
222
+ end
data/lib/mcp/client.rb CHANGED
@@ -1,5 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "client/stdio"
4
+ require_relative "client/http"
5
+ require_relative "client/tool"
6
+
3
7
  module MCP
4
8
  class Client
5
9
  # Initializes a new MCP::Client instance.
@@ -90,6 +94,7 @@ module MCP
90
94
  #
91
95
  # @param tool [MCP::Client::Tool] The tool to be called.
92
96
  # @param arguments [Object, nil] The arguments to pass to the tool.
97
+ # @param progress_token [String, Integer, nil] A token to request progress notifications from the server during tool execution.
93
98
  # @return [Hash] The full JSON-RPC response from the transport.
94
99
  #
95
100
  # @example
@@ -100,12 +105,17 @@ module MCP
100
105
  # @note
101
106
  # The exact requirements for `arguments` are determined by the transport layer in use.
102
107
  # Consult the documentation for your transport (e.g., MCP::Client::HTTP) for details.
103
- def call_tool(tool:, arguments: nil)
108
+ def call_tool(tool:, arguments: nil, progress_token: nil)
109
+ params = { name: tool.name, arguments: arguments }
110
+ if progress_token
111
+ params[:_meta] = { progressToken: progress_token }
112
+ end
113
+
104
114
  transport.send_request(request: {
105
115
  jsonrpc: JsonRpcHandler::Version::V2_0,
106
116
  id: request_id,
107
117
  method: "tools/call",
108
- params: { name: tool.name, arguments: arguments },
118
+ params: params,
109
119
  })
110
120
  end
111
121
 
data/lib/mcp/content.rb CHANGED
@@ -25,7 +25,34 @@ module MCP
25
25
  end
26
26
 
27
27
  def to_h
28
- { data: data, mime_type: mime_type, annotations: annotations, type: "image" }.compact
28
+ { data: data, mimeType: mime_type, annotations: annotations, type: "image" }.compact
29
+ end
30
+ end
31
+
32
+ class Audio
33
+ attr_reader :data, :mime_type, :annotations
34
+
35
+ def initialize(data, mime_type, annotations: nil)
36
+ @data = data
37
+ @mime_type = mime_type
38
+ @annotations = annotations
39
+ end
40
+
41
+ def to_h
42
+ { data: data, mimeType: mime_type, annotations: annotations, type: "audio" }.compact
43
+ end
44
+ end
45
+
46
+ class EmbeddedResource
47
+ attr_reader :resource, :annotations
48
+
49
+ def initialize(resource, annotations: nil)
50
+ @resource = resource
51
+ @annotations = annotations
52
+ end
53
+
54
+ def to_h
55
+ { resource: resource.to_h, annotations: annotations, type: "resource" }.compact
29
56
  end
30
57
  end
31
58
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MCP
4
+ class Progress
5
+ def initialize(server:, progress_token:)
6
+ @server = server
7
+ @progress_token = progress_token
8
+ end
9
+
10
+ def report(progress, total: nil, message: nil)
11
+ return unless @progress_token
12
+
13
+ @server.notify_progress(
14
+ progress_token: @progress_token,
15
+ progress: progress,
16
+ total: total,
17
+ message: message,
18
+ )
19
+ end
20
+ end
21
+ end
data/lib/mcp/prompt.rb CHANGED
@@ -1,5 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "prompt/argument"
4
+ require_relative "prompt/message"
5
+ require_relative "prompt/result"
6
+
3
7
  module MCP
4
8
  class Prompt
5
9
  class << self
@@ -21,7 +25,7 @@ module MCP
21
25
  title: title_value,
22
26
  description: description_value,
23
27
  icons: icons_value&.then { |icons| icons.empty? ? nil : icons.map(&:to_h) },
24
- arguments: arguments_value&.map(&:to_h),
28
+ arguments: arguments_value.empty? ? nil : arguments_value.map(&:to_h),
25
29
  _meta: meta_value,
26
30
  }.compact
27
31
  end
@@ -32,7 +36,7 @@ module MCP
32
36
  subclass.instance_variable_set(:@title_value, nil)
33
37
  subclass.instance_variable_set(:@description_value, nil)
34
38
  subclass.instance_variable_set(:@icons_value, nil)
35
- subclass.instance_variable_set(:@arguments_value, nil)
39
+ subclass.instance_variable_set(:@arguments_value, [])
36
40
  subclass.instance_variable_set(:@meta_value, nil)
37
41
  end
38
42
 
@@ -76,7 +80,7 @@ module MCP
76
80
  if value == NOT_SET
77
81
  @arguments_value
78
82
  else
79
- @arguments_value = value
83
+ @arguments_value = Array(value)
80
84
  end
81
85
  end
82
86
 
@@ -103,6 +107,7 @@ module MCP
103
107
  end
104
108
 
105
109
  def validate_arguments!(args)
110
+ args ||= {}
106
111
  missing = required_args - args.keys
107
112
  return if missing.empty?
108
113
 
data/lib/mcp/resource.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "resource/contents"
4
+ require_relative "resource/embedded"
5
+
3
6
  module MCP
4
7
  class Resource
5
8
  attr_reader :uri, :name, :title, :description, :icons, :mime_type
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "../../transport"
4
3
  require "json"
4
+ require_relative "../../transport"
5
5
 
6
6
  module MCP
7
7
  class Server