vector_mcp 0.1.0 → 0.3.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.
@@ -4,6 +4,8 @@
4
4
  require "json"
5
5
  require_relative "../errors"
6
6
  require_relative "../util"
7
+ require "securerandom" # For generating unique request IDs
8
+ require "timeout" # For request timeouts
7
9
 
8
10
  module VectorMCP
9
11
  module Transport
@@ -19,6 +21,9 @@ module VectorMCP
19
21
  # @return [Logger] The logger instance, shared with the server.
20
22
  attr_reader :logger
21
23
 
24
+ # Timeout for waiting for a response to a server-initiated request (in seconds)
25
+ DEFAULT_REQUEST_TIMEOUT = 30 # Configurable if needed
26
+
22
27
  # Initializes a new Stdio transport.
23
28
  #
24
29
  # @param server [VectorMCP::Server] The server instance that will handle messages.
@@ -29,6 +34,14 @@ module VectorMCP
29
34
  @output_mutex = Mutex.new
30
35
  @running = false
31
36
  @input_thread = nil
37
+ @shutdown_requested = false
38
+ @outgoing_request_responses = {} # To store responses for server-initiated requests
39
+ @outgoing_request_conditions = {} # ConditionVariables for server-initiated requests
40
+ @mutex = Mutex.new # To synchronize access to shared response data
41
+ @request_id_generator = Enumerator.new do |y|
42
+ i = 0
43
+ loop { y << "vecmcp_stdio_#{i += 1}_#{SecureRandom.hex(4)}" }
44
+ end
32
45
  end
33
46
 
34
47
  # Starts the stdio transport, listening for input and processing messages.
@@ -96,6 +109,30 @@ module VectorMCP
96
109
  write_message(notification)
97
110
  end
98
111
 
112
+ # Sends a server-initiated JSON-RPC request to the client and waits for a response.
113
+ # This is a blocking call.
114
+ #
115
+ # @param method [String] The request method name.
116
+ # @param params [Hash, Array, nil] The request parameters.
117
+ # @param timeout [Numeric] How long to wait for a response, in seconds.
118
+ # @return [Object] The result part of the client's response.
119
+ # @raise [VectorMCP::SamplingError, VectorMCP::SamplingTimeoutError] if the client returns an error or times out.
120
+ # @raise [ArgumentError] if method is blank.
121
+ def send_request(method, params = nil, timeout: DEFAULT_REQUEST_TIMEOUT)
122
+ raise ArgumentError, "Method cannot be blank" if method.to_s.strip.empty?
123
+
124
+ request_id = @request_id_generator.next
125
+ request_payload = { jsonrpc: "2.0", id: request_id, method: method }
126
+ request_payload[:params] = params if params
127
+
128
+ setup_request_tracking(request_id)
129
+ logger.debug "[Stdio Transport] Sending request ID #{request_id}: #{method}"
130
+ write_message(request_payload)
131
+
132
+ response = wait_for_response(request_id, method, timeout)
133
+ process_response(response, request_id, method)
134
+ end
135
+
99
136
  # Initiates an immediate shutdown of the transport.
100
137
  # Sets the running flag to false and attempts to kill the input reading thread.
101
138
  #
@@ -112,9 +149,8 @@ module VectorMCP
112
149
  # @api private
113
150
  # @param session [VectorMCP::Session] The session object for this connection.
114
151
  # @return [void]
152
+ # Constant identifier for stdio sessions
115
153
  def read_input_loop(session)
116
- session_id = "stdio-session" # Constant identifier for stdio sessions
117
-
118
154
  while @running
119
155
  line = read_input_line
120
156
  if line.nil?
@@ -123,7 +159,7 @@ module VectorMCP
123
159
  end
124
160
  next if line.strip.empty?
125
161
 
126
- handle_input_line(line, session, session_id)
162
+ handle_input_line(line, session)
127
163
  end
128
164
  end
129
165
 
@@ -141,18 +177,48 @@ module VectorMCP
141
177
  # @api private
142
178
  # @param line [String] The line of text read from stdin.
143
179
  # @param session [VectorMCP::Session] The current session.
144
- # @param session_id [String] The identifier for this session.
145
180
  # @return [void]
146
- def handle_input_line(line, session, session_id)
181
+ def handle_input_line(line, _session)
147
182
  message = parse_json(line)
148
183
  return if message.is_a?(Array) && message.empty? # Error handled in parse_json, indicated by empty array
149
184
 
150
- response_data = server.handle_message(message, session, session_id)
151
- send_response(message["id"], response_data) if message["id"] && response_data
152
- rescue VectorMCP::ProtocolError => e
153
- handle_protocol_error(e, message)
154
- rescue StandardError => e
155
- handle_unexpected_error(e, message)
185
+ return handle_outgoing_response(message) if outgoing_response?(message)
186
+
187
+ ensure_session_exists
188
+ handle_server_message(message)
189
+ end
190
+
191
+ # Checks if a message is a response to an outgoing request.
192
+ # @api private
193
+ # @param message [Hash] The parsed message.
194
+ # @return [Boolean] True if this is an outgoing response.
195
+ def outgoing_response?(message)
196
+ message["id"] && !message["method"] && (message.key?("result") || message.key?("error"))
197
+ end
198
+
199
+ # Ensures a global session exists for this stdio transport.
200
+ # @api private
201
+ # @return [VectorMCP::Session] The current session.
202
+ def ensure_session_exists
203
+ @ensure_session_exists ||= VectorMCP::Session.new(@server, self, id: "stdio_global_session")
204
+ end
205
+
206
+ # Handles a server message with proper error handling.
207
+ # @api private
208
+ # @param message [Hash] The parsed message.
209
+ # @return [void]
210
+ def handle_server_message(message)
211
+ session = ensure_session_exists
212
+ session_id = session.id
213
+
214
+ begin
215
+ result = @server.handle_message(message, session, session_id)
216
+ send_response(message["id"], result) if message["id"] && result
217
+ rescue VectorMCP::ProtocolError => e
218
+ handle_protocol_error(e, message)
219
+ rescue StandardError => e
220
+ handle_unexpected_error(e, message)
221
+ end
156
222
  end
157
223
 
158
224
  # --- Run helpers (private) ---
@@ -161,11 +227,7 @@ module VectorMCP
161
227
  # @api private
162
228
  # @return [VectorMCP::Session] The newly created session.
163
229
  def create_session
164
- VectorMCP::Session.new(
165
- server_info: server.server_info,
166
- server_capabilities: server.server_capabilities,
167
- protocol_version: server.protocol_version
168
- )
230
+ VectorMCP::Session.new(@server, self)
169
231
  end
170
232
 
171
233
  # Launches the input reading loop in a new thread.
@@ -193,6 +255,30 @@ module VectorMCP
193
255
 
194
256
  # --- Input helpers (private) ---
195
257
 
258
+ # Handles responses to outgoing requests (like sampling requests).
259
+ # @api private
260
+ # @param message [Hash] The parsed response message.
261
+ # @return [void]
262
+ def handle_outgoing_response(message)
263
+ request_id = message["id"]
264
+ logger.debug "[Stdio Transport] Received response for outgoing request ID #{request_id}"
265
+
266
+ @mutex.synchronize do
267
+ # Store the response (convert keys to symbols for consistency)
268
+ response_data = deep_transform_keys(message, &:to_sym)
269
+ @outgoing_request_responses[request_id] = response_data
270
+
271
+ # Signal any thread waiting for this response
272
+ condition = @outgoing_request_conditions[request_id]
273
+ if condition
274
+ condition.signal
275
+ logger.debug "[Stdio Transport] Signaled condition for request ID #{request_id}"
276
+ else
277
+ logger.warn "[Stdio Transport] Received response for request ID #{request_id} but no thread is waiting"
278
+ end
279
+ end
280
+ end
281
+
196
282
  # Parses a line of text as JSON.
197
283
  # If parsing fails, sends a JSON-RPC ParseError and returns an empty array
198
284
  # to signal that the error has been handled.
@@ -234,6 +320,21 @@ module VectorMCP
234
320
  send_error(request_id, -32_603, "Internal error", { details: error.message })
235
321
  end
236
322
 
323
+ # Recursively transforms hash keys using the given block.
324
+ # @api private
325
+ # @param obj [Object] The object to transform (Hash, Array, or other).
326
+ # @return [Object] The transformed object.
327
+ def deep_transform_keys(obj, &block)
328
+ case obj
329
+ when Hash
330
+ obj.transform_keys(&block).transform_values { |v| deep_transform_keys(v, &block) }
331
+ when Array
332
+ obj.map { |v| deep_transform_keys(v, &block) }
333
+ else
334
+ obj
335
+ end
336
+ end
337
+
237
338
  # Writes a message hash to `$stdout` as a JSON string, followed by a newline.
238
339
  # Ensures the output is flushed. Handles EPIPE errors if stdout closes.
239
340
  # @api private
@@ -253,6 +354,63 @@ module VectorMCP
253
354
  shutdown # Initiate shutdown as we can no longer communicate
254
355
  end
255
356
  end
357
+
358
+ # Sets up tracking for an outgoing request.
359
+ # @api private
360
+ # @param request_id [String] The request ID to track.
361
+ # @return [void]
362
+ def setup_request_tracking(request_id)
363
+ condition = ConditionVariable.new
364
+ @mutex.synchronize do
365
+ @outgoing_request_conditions[request_id] = condition
366
+ end
367
+ end
368
+
369
+ # Waits for a response to an outgoing request.
370
+ # @api private
371
+ # @param request_id [String] The request ID to wait for.
372
+ # @param method [String] The request method name.
373
+ # @param timeout [Numeric] How long to wait.
374
+ # @return [Hash] The response data.
375
+ # @raise [VectorMCP::SamplingTimeoutError] if timeout occurs.
376
+ def wait_for_response(request_id, method, timeout)
377
+ condition = @outgoing_request_conditions[request_id]
378
+
379
+ @mutex.synchronize do
380
+ Timeout.timeout(timeout) do
381
+ condition.wait(@mutex) until @outgoing_request_responses.key?(request_id)
382
+ @outgoing_request_responses.delete(request_id)
383
+ end
384
+ rescue Timeout::Error
385
+ logger.warn "[Stdio Transport] Timeout waiting for response to request ID #{request_id} (#{method}) after #{timeout}s"
386
+ @outgoing_request_responses.delete(request_id)
387
+ @outgoing_request_conditions.delete(request_id)
388
+ raise VectorMCP::SamplingTimeoutError, "Timeout waiting for client response to '#{method}' request (ID: #{request_id})"
389
+ ensure
390
+ @outgoing_request_conditions.delete(request_id)
391
+ end
392
+ end
393
+
394
+ # Processes the response from an outgoing request.
395
+ # @api private
396
+ # @param response [Hash, nil] The response data.
397
+ # @param request_id [String] The request ID.
398
+ # @param method [String] The request method name.
399
+ # @return [Object] The result data.
400
+ # @raise [VectorMCP::SamplingError] if response contains an error or is nil.
401
+ def process_response(response, request_id, method)
402
+ if response.nil?
403
+ raise VectorMCP::SamplingError, "No response received for '#{method}' request (ID: #{request_id}) - this indicates a logic error."
404
+ end
405
+
406
+ if response.key?(:error)
407
+ err = response[:error]
408
+ logger.warn "[Stdio Transport] Client returned error for request ID #{request_id} (#{method}): #{err.inspect}"
409
+ raise VectorMCP::SamplingError, "Client returned an error for '#{method}' request (ID: #{request_id}): [#{err[:code]}] #{err[:message]}"
410
+ end
411
+
412
+ response[:result]
413
+ end
256
414
  end
257
415
  end
258
416
  end
@@ -14,9 +14,10 @@ module VectorMCP
14
14
  # into the wire-format expected by the MCP spec.
15
15
  #
16
16
  # Keys present in each returned hash:
17
- # * **:type** – Currently always `"text"`; future protocol versions may add rich/binary types.
18
- # * **:text** – UTF-8 encoded payload.
19
- # * **:mimeType** IANA media-type describing `:text` (`"text/plain"`, `"application/json"`, ).
17
+ # * **:type** – `"text"` or `"image"`; automatic detection for binary data.
18
+ # * **:text** – UTF-8 encoded payload (for text content).
19
+ # * **:data** Base64 encoded payload (for image content).
20
+ # * **:mimeType** – IANA media-type describing the content.
20
21
  # * **:uri** – _Optional._ Added downstream (e.g., by {Handlers::Core.read_resource}).
21
22
  #
22
23
  # The method **never** returns `nil` and **always** returns at least one element.
@@ -35,6 +36,10 @@ module VectorMCP
35
36
  # @example Complex object
36
37
  # VectorMCP::Util.convert_to_mcp_content({foo: 1})
37
38
  # # => [{type: "text", text: "{\"foo\":1}", mimeType: "application/json"}]
39
+ #
40
+ # @example Image file path
41
+ # VectorMCP::Util.convert_to_mcp_content("image.jpg")
42
+ # # => [{type: "image", data: "base64...", mimeType: "image/jpeg"}]
38
43
  def convert_to_mcp_content(input, mime_type: "text/plain")
39
44
  return string_content(input, mime_type) if input.is_a?(String)
40
45
  return hash_content(input) if input.is_a?(Hash)
@@ -45,11 +50,20 @@ module VectorMCP
45
50
 
46
51
  # --- Conversion helpers (exposed as module functions) ---
47
52
 
48
- # Converts a String into an MCP text content item.
53
+ # Converts a String into an MCP content item.
54
+ # Intelligently detects if the string is binary image data, a file path to an image,
55
+ # or regular text content.
49
56
  # @param str [String] The string to convert.
50
57
  # @param mime_type [String] The MIME type for the content.
51
- # @return [Array<Hash>] MCP content array with one text item.
58
+ # @return [Array<Hash>] MCP content array with one item.
52
59
  def string_content(str, mime_type)
60
+ # Check if this might be a file path to an image
61
+ return file_path_to_image_content(str) if looks_like_image_file_path?(str)
62
+
63
+ # Check if this is binary image data
64
+ return binary_image_to_content(str) if binary_image_data?(str)
65
+
66
+ # Default to text content
53
67
  [{ type: "text", text: str, mimeType: mime_type }]
54
68
  end
55
69
 
@@ -60,7 +74,12 @@ module VectorMCP
60
74
  # @return [Array<Hash>] MCP content array.
61
75
  def hash_content(hash)
62
76
  if hash[:type] || hash["type"] # Already in content format
63
- [hash.transform_keys(&:to_sym)]
77
+ normalized = hash.transform_keys(&:to_sym)
78
+
79
+ # Validate and enhance image content if needed
80
+ return [validate_and_enhance_image_content(normalized)] if normalized[:type] == "image"
81
+
82
+ [normalized]
64
83
  else
65
84
  [{ type: "text", text: hash.to_json, mimeType: "application/json" }]
66
85
  end
@@ -73,14 +92,30 @@ module VectorMCP
73
92
  # @param mime_type [String] The default MIME type for child items if they need conversion.
74
93
  # @return [Array<Hash>] MCP content array.
75
94
  def array_content(arr, mime_type)
76
- if arr.all? { |item| item.is_a?(Hash) && (item[:type] || item["type"]) }
77
- arr.map { |item| item.transform_keys(&:to_sym) }
95
+ if all_content_items?(arr)
96
+ arr.map { |item| process_content_item(item) }
78
97
  else
79
- # Recursively convert each item, preserving the original mime_type intent for non-structured children.
80
98
  arr.flat_map { |item| convert_to_mcp_content(item, mime_type: mime_type) }
81
99
  end
82
100
  end
83
101
 
102
+ # Checks if all array items are pre-formatted MCP content items.
103
+ # @param arr [Array] The array to check.
104
+ # @return [Boolean] True if all items have type fields.
105
+ def all_content_items?(arr)
106
+ arr.all? { |item| item.is_a?(Hash) && (item[:type] || item["type"]) }
107
+ end
108
+
109
+ # Processes a single content item, normalizing and validating as needed.
110
+ # @param item [Hash] The content item to process.
111
+ # @return [Hash] The processed content item.
112
+ def process_content_item(item)
113
+ normalized = item.transform_keys(&:to_sym)
114
+ return validate_and_enhance_image_content(normalized) if normalized[:type] == "image"
115
+
116
+ normalized
117
+ end
118
+
84
119
  # Fallback conversion for any other object type to an MCP text content item.
85
120
  # Converts the object to its string representation.
86
121
  # @param obj [Object] The object to convert.
@@ -90,7 +125,8 @@ module VectorMCP
90
125
  [{ type: "text", text: obj.to_s, mimeType: mime_type }]
91
126
  end
92
127
 
93
- module_function :string_content, :hash_content, :array_content, :fallback_content
128
+ module_function :string_content, :hash_content, :array_content, :fallback_content,
129
+ :all_content_items?, :process_content_item
94
130
 
95
131
  # Extracts an ID from a potentially malformed JSON string using regex.
96
132
  # This is a best-effort attempt, primarily for error reporting when full JSON parsing fails.
@@ -109,5 +145,94 @@ module VectorMCP
109
145
 
110
146
  nil
111
147
  end
148
+
149
+ private
150
+
151
+ # Checks if a string looks like a file path to an image.
152
+ # @param str [String] The string to check.
153
+ # @return [Boolean] True if it looks like an image file path.
154
+ def looks_like_image_file_path?(str)
155
+ return false if str.nil? || str.empty? || str.length > 500
156
+
157
+ # Check for common image extensions
158
+ image_extensions = %w[.jpg .jpeg .png .gif .webp .bmp .tiff .tif .svg]
159
+ has_image_extension = image_extensions.any? { |ext| str.downcase.end_with?(ext) }
160
+
161
+ # Check if it looks like a file path (contains / or \ or ends with image extension)
162
+ looks_like_path = str.include?("/") || str.include?("\\") || has_image_extension
163
+
164
+ has_image_extension && looks_like_path
165
+ end
166
+
167
+ # Checks if a string contains binary image data.
168
+ # @param str [String] The string to check.
169
+ # @return [Boolean] True if it appears to be binary image data.
170
+ def binary_image_data?(str)
171
+ return false if str.nil? || str.empty?
172
+
173
+ # Check encoding first
174
+ encoding = str.encoding
175
+ is_binary = encoding == Encoding::ASCII_8BIT || !str.valid_encoding?
176
+
177
+ return false unless is_binary
178
+
179
+ # Use ImageUtil to detect if it's actually image data
180
+ require_relative "image_util"
181
+ !VectorMCP::ImageUtil.detect_image_format(str).nil?
182
+ rescue StandardError
183
+ false
184
+ end
185
+
186
+ # Converts a file path string to image content.
187
+ # @param file_path [String] Path to the image file.
188
+ # @return [Array<Hash>] MCP content array with image content.
189
+ def file_path_to_image_content(file_path)
190
+ require_relative "image_util"
191
+
192
+ begin
193
+ image_content = VectorMCP::ImageUtil.file_to_mcp_image_content(file_path)
194
+ [image_content]
195
+ rescue ArgumentError => e
196
+ # If image processing fails, fall back to text content with error message
197
+ [{ type: "text", text: "Error loading image '#{file_path}': #{e.message}", mimeType: "text/plain" }]
198
+ end
199
+ end
200
+
201
+ # Converts binary image data to MCP image content.
202
+ # @param binary_data [String] Binary image data.
203
+ # @return [Array<Hash>] MCP content array with image content.
204
+ def binary_image_to_content(binary_data)
205
+ require_relative "image_util"
206
+
207
+ begin
208
+ image_content = VectorMCP::ImageUtil.to_mcp_image_content(binary_data)
209
+ [image_content]
210
+ rescue ArgumentError
211
+ # If image processing fails, fall back to text content
212
+ [{ type: "text", text: binary_data.to_s, mimeType: "application/octet-stream" }]
213
+ end
214
+ end
215
+
216
+ # Validates and enhances existing image content hash.
217
+ # @param content [Hash] Existing image content hash.
218
+ # @return [Hash] Validated and enhanced image content.
219
+ def validate_and_enhance_image_content(content)
220
+ # Ensure required fields are present
221
+ raise ArgumentError, "Image content must have both :data and :mimeType fields" unless content[:data] && content[:mimeType]
222
+
223
+ # Validate the base64 data if possible
224
+ begin
225
+ require_relative "image_util"
226
+ VectorMCP::ImageUtil.decode_base64(content[:data])
227
+ rescue ArgumentError => e
228
+ raise ArgumentError, "Invalid base64 image data: #{e.message}"
229
+ end
230
+
231
+ content
232
+ end
233
+
234
+ module_function :looks_like_image_file_path?, :binary_image_data?,
235
+ :file_path_to_image_content, :binary_image_to_content,
236
+ :validate_and_enhance_image_content
112
237
  end
113
238
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module VectorMCP
4
4
  # The current version of the VectorMCP gem.
5
- VERSION = "0.1.0"
5
+ VERSION = "0.3.0"
6
6
  end
data/lib/vector_mcp.rb CHANGED
@@ -8,9 +8,10 @@ require_relative "vector_mcp/errors"
8
8
  require_relative "vector_mcp/definitions"
9
9
  require_relative "vector_mcp/session"
10
10
  require_relative "vector_mcp/util"
11
+ require_relative "vector_mcp/image_util"
11
12
  require_relative "vector_mcp/handlers/core"
12
13
  require_relative "vector_mcp/transport/stdio"
13
- require_relative "vector_mcp/transport/sse"
14
+ # require_relative "vector_mcp/transport/sse" # Load on demand to avoid async dependencies
14
15
  require_relative "vector_mcp/server"
15
16
 
16
17
  # The VectorMCP module provides a full-featured, opinionated Ruby implementation
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vector_mcp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergio Bayona
@@ -10,75 +10,75 @@ cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
- name: async
13
+ name: base64
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: 2.23.0
18
+ version: '0.2'
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: 2.23.0
25
+ version: '0.2'
26
26
  - !ruby/object:Gem::Dependency
27
- name: async-container
27
+ name: bigdecimal
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '0.16'
32
+ version: '3.1'
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '0.16'
39
+ version: '3.1'
40
40
  - !ruby/object:Gem::Dependency
41
- name: async-http
41
+ name: concurrent-ruby
42
42
  requirement: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: '0.61'
46
+ version: '1.2'
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '0.61'
53
+ version: '1.2'
54
54
  - !ruby/object:Gem::Dependency
55
- name: async-io
55
+ name: json-schema
56
56
  requirement: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: '1.36'
60
+ version: '3.0'
61
61
  type: :runtime
62
62
  prerelease: false
63
63
  version_requirements: !ruby/object:Gem::Requirement
64
64
  requirements:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: '1.36'
67
+ version: '3.0'
68
68
  - !ruby/object:Gem::Dependency
69
- name: falcon
69
+ name: puma
70
70
  requirement: !ruby/object:Gem::Requirement
71
71
  requirements:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
- version: '0.42'
74
+ version: '6.4'
75
75
  type: :runtime
76
76
  prerelease: false
77
77
  version_requirements: !ruby/object:Gem::Requirement
78
78
  requirements:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
- version: '0.42'
81
+ version: '6.4'
82
82
  description: Server-side tools for implementing the Model Context Protocol in Ruby
83
83
  applications
84
84
  email:
@@ -97,9 +97,19 @@ files:
97
97
  - lib/vector_mcp/definitions.rb
98
98
  - lib/vector_mcp/errors.rb
99
99
  - lib/vector_mcp/handlers/core.rb
100
+ - lib/vector_mcp/image_util.rb
101
+ - lib/vector_mcp/sampling/request.rb
102
+ - lib/vector_mcp/sampling/result.rb
100
103
  - lib/vector_mcp/server.rb
104
+ - lib/vector_mcp/server/capabilities.rb
105
+ - lib/vector_mcp/server/message_handling.rb
106
+ - lib/vector_mcp/server/registry.rb
101
107
  - lib/vector_mcp/session.rb
102
108
  - lib/vector_mcp/transport/sse.rb
109
+ - lib/vector_mcp/transport/sse/client_connection.rb
110
+ - lib/vector_mcp/transport/sse/message_handler.rb
111
+ - lib/vector_mcp/transport/sse/puma_config.rb
112
+ - lib/vector_mcp/transport/sse/stream_manager.rb
103
113
  - lib/vector_mcp/transport/stdio.rb
104
114
  - lib/vector_mcp/util.rb
105
115
  - lib/vector_mcp/version.rb