ruby-mcp-client 0.8.0 → 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 +4 -4
- data/README.md +495 -9
- data/lib/mcp_client/auth/browser_oauth.rb +424 -0
- data/lib/mcp_client/auth/oauth_provider.rb +131 -19
- data/lib/mcp_client/auth.rb +1 -1
- data/lib/mcp_client/client.rb +159 -45
- data/lib/mcp_client/json_rpc_common.rb +3 -1
- data/lib/mcp_client/resource_content.rb +80 -0
- data/lib/mcp_client/resource_template.rb +57 -0
- data/lib/mcp_client/server_base.rb +31 -3
- data/lib/mcp_client/server_factory.rb +4 -2
- data/lib/mcp_client/server_http.rb +150 -0
- data/lib/mcp_client/server_sse/sse_parser.rb +11 -0
- data/lib/mcp_client/server_sse.rb +198 -12
- data/lib/mcp_client/server_stdio/json_rpc_transport.rb +5 -0
- data/lib/mcp_client/server_stdio.rb +197 -7
- data/lib/mcp_client/server_streamable_http/json_rpc_transport.rb +8 -1
- data/lib/mcp_client/server_streamable_http.rb +198 -16
- data/lib/mcp_client/tool.rb +40 -4
- data/lib/mcp_client/version.rb +2 -2
- data/lib/mcp_client.rb +2 -0
- metadata +5 -2
|
@@ -9,9 +9,9 @@ require 'faraday/retry'
|
|
|
9
9
|
require 'faraday/follow_redirects'
|
|
10
10
|
|
|
11
11
|
module MCPClient
|
|
12
|
-
# Implementation of MCP server that communicates via Streamable HTTP transport (MCP 2025-
|
|
12
|
+
# Implementation of MCP server that communicates via Streamable HTTP transport (MCP 2025-06-18)
|
|
13
13
|
# This transport uses HTTP POST for RPC calls with optional SSE responses, and GET for event streams
|
|
14
|
-
# Compliant with MCP specification version 2025-
|
|
14
|
+
# Compliant with MCP specification version 2025-06-18
|
|
15
15
|
#
|
|
16
16
|
# Key features:
|
|
17
17
|
# - Supports server-sent events (SSE) for real-time notifications
|
|
@@ -91,7 +91,7 @@ module MCPClient
|
|
|
91
91
|
@headers = opts[:headers].merge({
|
|
92
92
|
'Content-Type' => 'application/json',
|
|
93
93
|
'Accept' => 'text/event-stream, application/json',
|
|
94
|
-
'Accept-Encoding' => 'gzip
|
|
94
|
+
'Accept-Encoding' => 'gzip',
|
|
95
95
|
'User-Agent' => "ruby-mcp-client/#{MCPClient::VERSION}",
|
|
96
96
|
'Cache-Control' => 'no-cache'
|
|
97
97
|
})
|
|
@@ -116,6 +116,7 @@ module MCPClient
|
|
|
116
116
|
@events_connection = nil
|
|
117
117
|
@events_thread = nil
|
|
118
118
|
@buffer = '' # Buffer for partial SSE event data
|
|
119
|
+
@elicitation_request_callback = nil # MCP 2025-06-18
|
|
119
120
|
end
|
|
120
121
|
|
|
121
122
|
# Connect to the MCP server over Streamable HTTP
|
|
@@ -262,24 +263,32 @@ module MCPClient
|
|
|
262
263
|
end
|
|
263
264
|
|
|
264
265
|
# List all resources available from the MCP server
|
|
265
|
-
# @
|
|
266
|
+
# @param cursor [String, nil] optional cursor for pagination
|
|
267
|
+
# @return [Hash] result containing resources array and optional nextCursor
|
|
266
268
|
# @raise [MCPClient::Errors::ResourceReadError] if resources list retrieval fails
|
|
267
|
-
def list_resources
|
|
269
|
+
def list_resources(cursor: nil)
|
|
268
270
|
@mutex.synchronize do
|
|
269
|
-
return @
|
|
271
|
+
return @resources_result if @resources_result && !cursor
|
|
270
272
|
end
|
|
271
273
|
|
|
272
274
|
begin
|
|
273
275
|
ensure_connected
|
|
274
276
|
|
|
275
|
-
|
|
277
|
+
params = {}
|
|
278
|
+
params['cursor'] = cursor if cursor
|
|
279
|
+
result = rpc_request('resources/list', params)
|
|
280
|
+
|
|
281
|
+
resources = (result['resources'] || []).map do |resource_data|
|
|
282
|
+
MCPClient::Resource.from_json(resource_data, server: self)
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
resources_result = { 'resources' => resources, 'nextCursor' => result['nextCursor'] }
|
|
286
|
+
|
|
276
287
|
@mutex.synchronize do
|
|
277
|
-
@
|
|
278
|
-
MCPClient::Resource.from_json(resource_data, server: self)
|
|
279
|
-
end
|
|
288
|
+
@resources_result = resources_result unless cursor
|
|
280
289
|
end
|
|
281
290
|
|
|
282
|
-
|
|
291
|
+
resources_result
|
|
283
292
|
rescue MCPClient::Errors::ConnectionError, MCPClient::Errors::TransportError, MCPClient::Errors::ServerError
|
|
284
293
|
# Re-raise these errors directly
|
|
285
294
|
raise
|
|
@@ -290,10 +299,12 @@ module MCPClient
|
|
|
290
299
|
|
|
291
300
|
# Read a resource by its URI
|
|
292
301
|
# @param uri [String] the URI of the resource to read
|
|
293
|
-
# @return [
|
|
302
|
+
# @return [Array<MCPClient::ResourceContent>] array of resource contents
|
|
294
303
|
# @raise [MCPClient::Errors::ResourceReadError] if resource reading fails
|
|
295
304
|
def read_resource(uri)
|
|
296
|
-
rpc_request('resources/read', { uri: uri })
|
|
305
|
+
result = rpc_request('resources/read', { uri: uri })
|
|
306
|
+
contents = result['contents'] || []
|
|
307
|
+
contents.map { |content| MCPClient::ResourceContent.from_json(content) }
|
|
297
308
|
rescue MCPClient::Errors::ConnectionError, MCPClient::Errors::TransportError
|
|
298
309
|
# Re-raise connection/transport errors directly
|
|
299
310
|
raise
|
|
@@ -302,6 +313,52 @@ module MCPClient
|
|
|
302
313
|
raise MCPClient::Errors::ResourceReadError, "Error reading resource '#{uri}': #{e.message}"
|
|
303
314
|
end
|
|
304
315
|
|
|
316
|
+
# List all resource templates available from the MCP server
|
|
317
|
+
# @param cursor [String, nil] optional cursor for pagination
|
|
318
|
+
# @return [Hash] result containing resourceTemplates array and optional nextCursor
|
|
319
|
+
# @raise [MCPClient::Errors::ResourceReadError] for other errors during resource template listing
|
|
320
|
+
def list_resource_templates(cursor: nil)
|
|
321
|
+
params = {}
|
|
322
|
+
params['cursor'] = cursor if cursor
|
|
323
|
+
result = rpc_request('resources/templates/list', params)
|
|
324
|
+
|
|
325
|
+
templates = (result['resourceTemplates'] || []).map do |template_data|
|
|
326
|
+
MCPClient::ResourceTemplate.from_json(template_data, server: self)
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
{ 'resourceTemplates' => templates, 'nextCursor' => result['nextCursor'] }
|
|
330
|
+
rescue MCPClient::Errors::ConnectionError, MCPClient::Errors::TransportError, MCPClient::Errors::ServerError
|
|
331
|
+
raise
|
|
332
|
+
rescue StandardError => e
|
|
333
|
+
raise MCPClient::Errors::ResourceReadError, "Error listing resource templates: #{e.message}"
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
# Subscribe to resource updates
|
|
337
|
+
# @param uri [String] the URI of the resource to subscribe to
|
|
338
|
+
# @return [Boolean] true if subscription successful
|
|
339
|
+
# @raise [MCPClient::Errors::ResourceReadError] for other errors during subscription
|
|
340
|
+
def subscribe_resource(uri)
|
|
341
|
+
rpc_request('resources/subscribe', { uri: uri })
|
|
342
|
+
true
|
|
343
|
+
rescue MCPClient::Errors::ConnectionError, MCPClient::Errors::TransportError, MCPClient::Errors::ServerError
|
|
344
|
+
raise
|
|
345
|
+
rescue StandardError => e
|
|
346
|
+
raise MCPClient::Errors::ResourceReadError, "Error subscribing to resource '#{uri}': #{e.message}"
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
# Unsubscribe from resource updates
|
|
350
|
+
# @param uri [String] the URI of the resource to unsubscribe from
|
|
351
|
+
# @return [Boolean] true if unsubscription successful
|
|
352
|
+
# @raise [MCPClient::Errors::ResourceReadError] for other errors during unsubscription
|
|
353
|
+
def unsubscribe_resource(uri)
|
|
354
|
+
rpc_request('resources/unsubscribe', { uri: uri })
|
|
355
|
+
true
|
|
356
|
+
rescue MCPClient::Errors::ConnectionError, MCPClient::Errors::TransportError, MCPClient::Errors::ServerError
|
|
357
|
+
raise
|
|
358
|
+
rescue StandardError => e
|
|
359
|
+
raise MCPClient::Errors::ResourceReadError, "Error unsubscribing from resource '#{uri}': #{e.message}"
|
|
360
|
+
end
|
|
361
|
+
|
|
305
362
|
# Override apply_request_headers to add session and SSE headers for MCP protocol
|
|
306
363
|
def apply_request_headers(req, request)
|
|
307
364
|
super
|
|
@@ -395,6 +452,13 @@ module MCPClient
|
|
|
395
452
|
end
|
|
396
453
|
end
|
|
397
454
|
|
|
455
|
+
# Register a callback for elicitation requests (MCP 2025-06-18)
|
|
456
|
+
# @param block [Proc] callback that receives (request_id, params) and returns response hash
|
|
457
|
+
# @return [void]
|
|
458
|
+
def on_elicitation_request(&block)
|
|
459
|
+
@elicitation_request_callback = block
|
|
460
|
+
end
|
|
461
|
+
|
|
398
462
|
private
|
|
399
463
|
|
|
400
464
|
def perform_initialize
|
|
@@ -699,12 +763,12 @@ module MCPClient
|
|
|
699
763
|
# Handle ping requests from server (keepalive mechanism)
|
|
700
764
|
if message['method'] == 'ping' && message.key?('id')
|
|
701
765
|
handle_ping_request(message['id'])
|
|
766
|
+
elsif message['method'] && message.key?('id')
|
|
767
|
+
# Handle server-to-client requests (MCP 2025-06-18)
|
|
768
|
+
handle_server_request(message)
|
|
702
769
|
elsif message['method'] && !message.key?('id')
|
|
703
770
|
# Handle server notifications (messages without id)
|
|
704
771
|
@notification_callback&.call(message['method'], message['params'])
|
|
705
|
-
elsif message.key?('id')
|
|
706
|
-
# This might be a server-to-client request (future MCP versions)
|
|
707
|
-
@logger.warn("Received unhandled server request: #{message['method']}")
|
|
708
772
|
end
|
|
709
773
|
rescue JSON::ParserError => e
|
|
710
774
|
@logger.error("Invalid JSON in server message: #{e.message}")
|
|
@@ -740,5 +804,123 @@ module MCPClient
|
|
|
740
804
|
@logger.error("Failed to send pong response: #{e.message}")
|
|
741
805
|
end
|
|
742
806
|
end
|
|
807
|
+
|
|
808
|
+
# Handle incoming JSON-RPC request from server (MCP 2025-06-18)
|
|
809
|
+
# @param msg [Hash] the JSON-RPC request message
|
|
810
|
+
# @return [void]
|
|
811
|
+
def handle_server_request(msg)
|
|
812
|
+
request_id = msg['id']
|
|
813
|
+
method = msg['method']
|
|
814
|
+
params = msg['params'] || {}
|
|
815
|
+
|
|
816
|
+
@logger.debug("Received server request: #{method} (id: #{request_id})")
|
|
817
|
+
|
|
818
|
+
case method
|
|
819
|
+
when 'elicitation/create'
|
|
820
|
+
handle_elicitation_create(request_id, params)
|
|
821
|
+
else
|
|
822
|
+
# Unknown request method, send error response
|
|
823
|
+
send_error_response(request_id, -32_601, "Method not found: #{method}")
|
|
824
|
+
end
|
|
825
|
+
rescue StandardError => e
|
|
826
|
+
@logger.error("Error handling server request: #{e.message}")
|
|
827
|
+
send_error_response(request_id, -32_603, "Internal error: #{e.message}")
|
|
828
|
+
end
|
|
829
|
+
|
|
830
|
+
# Handle elicitation/create request from server (MCP 2025-06-18)
|
|
831
|
+
# @param request_id [String, Integer] the JSON-RPC request ID (used as elicitationId)
|
|
832
|
+
# @param params [Hash] the elicitation parameters
|
|
833
|
+
# @return [void]
|
|
834
|
+
def handle_elicitation_create(request_id, params)
|
|
835
|
+
# The request_id is the elicitationId per MCP spec
|
|
836
|
+
elicitation_id = request_id
|
|
837
|
+
|
|
838
|
+
# If no callback is registered, decline the request
|
|
839
|
+
unless @elicitation_request_callback
|
|
840
|
+
@logger.warn('Received elicitation request but no callback registered, declining')
|
|
841
|
+
send_elicitation_response(elicitation_id, { 'action' => 'decline' })
|
|
842
|
+
return
|
|
843
|
+
end
|
|
844
|
+
|
|
845
|
+
# Call the registered callback
|
|
846
|
+
result = @elicitation_request_callback.call(request_id, params)
|
|
847
|
+
|
|
848
|
+
# Send the response back to the server
|
|
849
|
+
send_elicitation_response(elicitation_id, result)
|
|
850
|
+
end
|
|
851
|
+
|
|
852
|
+
# Send elicitation response back to server via HTTP POST (MCP 2025-06-18)
|
|
853
|
+
# For streamable HTTP, this is sent as a JSON-RPC request (not response)
|
|
854
|
+
# because HTTP is unidirectional.
|
|
855
|
+
# @param elicitation_id [String] the elicitation ID from the server
|
|
856
|
+
# @param result [Hash] the elicitation result (action and optional content)
|
|
857
|
+
# @return [void]
|
|
858
|
+
def send_elicitation_response(elicitation_id, result)
|
|
859
|
+
params = {
|
|
860
|
+
'elicitationId' => elicitation_id,
|
|
861
|
+
'action' => result['action']
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
# Only include content if present (typically for 'accept' action)
|
|
865
|
+
params['content'] = result['content'] if result['content']
|
|
866
|
+
|
|
867
|
+
request = {
|
|
868
|
+
'jsonrpc' => '2.0',
|
|
869
|
+
'method' => 'elicitation/response',
|
|
870
|
+
'params' => params
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
# Send as a JSON-RPC request via HTTP POST
|
|
874
|
+
post_jsonrpc_response(request)
|
|
875
|
+
rescue StandardError => e
|
|
876
|
+
@logger.error("Error sending elicitation response: #{e.message}")
|
|
877
|
+
end
|
|
878
|
+
|
|
879
|
+
# Send error response back to server via HTTP POST (MCP 2025-06-18)
|
|
880
|
+
# @param request_id [String, Integer] the JSON-RPC request ID
|
|
881
|
+
# @param code [Integer] the error code
|
|
882
|
+
# @param message [String] the error message
|
|
883
|
+
# @return [void]
|
|
884
|
+
def send_error_response(request_id, code, message)
|
|
885
|
+
response = {
|
|
886
|
+
'jsonrpc' => '2.0',
|
|
887
|
+
'id' => request_id,
|
|
888
|
+
'error' => {
|
|
889
|
+
'code' => code,
|
|
890
|
+
'message' => message
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
# Send response via HTTP POST to the endpoint
|
|
895
|
+
post_jsonrpc_response(response)
|
|
896
|
+
rescue StandardError => e
|
|
897
|
+
@logger.error("Error sending error response: #{e.message}")
|
|
898
|
+
end
|
|
899
|
+
|
|
900
|
+
# Post a JSON-RPC response message to the server via HTTP
|
|
901
|
+
# @param response [Hash] the JSON-RPC response
|
|
902
|
+
# @return [void]
|
|
903
|
+
# @private
|
|
904
|
+
def post_jsonrpc_response(response)
|
|
905
|
+
# Send response in a separate thread to avoid blocking event processing
|
|
906
|
+
Thread.new do
|
|
907
|
+
conn = http_connection
|
|
908
|
+
json_body = JSON.generate(response)
|
|
909
|
+
|
|
910
|
+
resp = conn.post(@endpoint) do |req|
|
|
911
|
+
@headers.each { |k, v| req.headers[k] = v }
|
|
912
|
+
req.headers['Mcp-Session-Id'] = @session_id if @session_id
|
|
913
|
+
req.body = json_body
|
|
914
|
+
end
|
|
915
|
+
|
|
916
|
+
if resp.success?
|
|
917
|
+
@logger.debug("Sent JSON-RPC response: #{json_body}")
|
|
918
|
+
else
|
|
919
|
+
@logger.warn("Failed to send JSON-RPC response: HTTP #{resp.status}")
|
|
920
|
+
end
|
|
921
|
+
rescue StandardError => e
|
|
922
|
+
@logger.error("Failed to send JSON-RPC response: #{e.message}")
|
|
923
|
+
end
|
|
924
|
+
end
|
|
743
925
|
end
|
|
744
926
|
end
|
data/lib/mcp_client/tool.rb
CHANGED
|
@@ -8,20 +8,28 @@ module MCPClient
|
|
|
8
8
|
# @!attribute [r] description
|
|
9
9
|
# @return [String] the description of the tool
|
|
10
10
|
# @!attribute [r] schema
|
|
11
|
-
# @return [Hash] the JSON schema for the tool
|
|
11
|
+
# @return [Hash] the JSON schema for the tool inputs
|
|
12
|
+
# @!attribute [r] output_schema
|
|
13
|
+
# @return [Hash, nil] optional JSON schema for structured tool outputs (MCP 2025-06-18)
|
|
14
|
+
# @!attribute [r] annotations
|
|
15
|
+
# @return [Hash, nil] optional annotations describing tool behavior (e.g., readOnly, destructive)
|
|
12
16
|
# @!attribute [r] server
|
|
13
17
|
# @return [MCPClient::ServerBase, nil] the server this tool belongs to
|
|
14
|
-
attr_reader :name, :description, :schema, :server
|
|
18
|
+
attr_reader :name, :description, :schema, :output_schema, :annotations, :server
|
|
15
19
|
|
|
16
20
|
# Initialize a new Tool
|
|
17
21
|
# @param name [String] the name of the tool
|
|
18
22
|
# @param description [String] the description of the tool
|
|
19
|
-
# @param schema [Hash] the JSON schema for the tool
|
|
23
|
+
# @param schema [Hash] the JSON schema for the tool inputs
|
|
24
|
+
# @param output_schema [Hash, nil] optional JSON schema for structured tool outputs (MCP 2025-06-18)
|
|
25
|
+
# @param annotations [Hash, nil] optional annotations describing tool behavior
|
|
20
26
|
# @param server [MCPClient::ServerBase, nil] the server this tool belongs to
|
|
21
|
-
def initialize(name:, description:, schema:, server: nil)
|
|
27
|
+
def initialize(name:, description:, schema:, output_schema: nil, annotations: nil, server: nil)
|
|
22
28
|
@name = name
|
|
23
29
|
@description = description
|
|
24
30
|
@schema = schema
|
|
31
|
+
@output_schema = output_schema
|
|
32
|
+
@annotations = annotations
|
|
25
33
|
@server = server
|
|
26
34
|
end
|
|
27
35
|
|
|
@@ -33,10 +41,14 @@ module MCPClient
|
|
|
33
41
|
# Some servers (Playwright MCP CLI) use 'inputSchema' instead of 'schema'
|
|
34
42
|
# Handle both string and symbol keys
|
|
35
43
|
schema = data['inputSchema'] || data[:inputSchema] || data['schema'] || data[:schema]
|
|
44
|
+
output_schema = data['outputSchema'] || data[:outputSchema]
|
|
45
|
+
annotations = data['annotations'] || data[:annotations]
|
|
36
46
|
new(
|
|
37
47
|
name: data['name'] || data[:name],
|
|
38
48
|
description: data['description'] || data[:description],
|
|
39
49
|
schema: schema,
|
|
50
|
+
output_schema: output_schema,
|
|
51
|
+
annotations: annotations,
|
|
40
52
|
server: server
|
|
41
53
|
)
|
|
42
54
|
end
|
|
@@ -74,6 +86,30 @@ module MCPClient
|
|
|
74
86
|
}
|
|
75
87
|
end
|
|
76
88
|
|
|
89
|
+
# Check if the tool is marked as read-only
|
|
90
|
+
# @return [Boolean] true if the tool is read-only
|
|
91
|
+
def read_only?
|
|
92
|
+
@annotations && @annotations['readOnly'] == true
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Check if the tool is marked as destructive
|
|
96
|
+
# @return [Boolean] true if the tool is destructive
|
|
97
|
+
def destructive?
|
|
98
|
+
@annotations && @annotations['destructive'] == true
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Check if the tool requires confirmation before execution
|
|
102
|
+
# @return [Boolean] true if the tool requires confirmation
|
|
103
|
+
def requires_confirmation?
|
|
104
|
+
@annotations && @annotations['requiresConfirmation'] == true
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Check if the tool supports structured outputs (MCP 2025-06-18)
|
|
108
|
+
# @return [Boolean] true if the tool has an output schema defined
|
|
109
|
+
def structured_output?
|
|
110
|
+
!@output_schema.nil? && !@output_schema.empty?
|
|
111
|
+
end
|
|
112
|
+
|
|
77
113
|
private
|
|
78
114
|
|
|
79
115
|
# Recursively remove "$schema" keys that are not accepted by Vertex AI
|
data/lib/mcp_client/version.rb
CHANGED
data/lib/mcp_client.rb
CHANGED
|
@@ -5,6 +5,8 @@ require_relative 'mcp_client/errors'
|
|
|
5
5
|
require_relative 'mcp_client/tool'
|
|
6
6
|
require_relative 'mcp_client/prompt'
|
|
7
7
|
require_relative 'mcp_client/resource'
|
|
8
|
+
require_relative 'mcp_client/resource_template'
|
|
9
|
+
require_relative 'mcp_client/resource_content'
|
|
8
10
|
require_relative 'mcp_client/server_base'
|
|
9
11
|
require_relative 'mcp_client/server_stdio'
|
|
10
12
|
require_relative 'mcp_client/server_sse'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby-mcp-client
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Szymon Kurcab
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-
|
|
11
|
+
date: 2025-11-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|
|
@@ -120,6 +120,7 @@ files:
|
|
|
120
120
|
- README.md
|
|
121
121
|
- lib/mcp_client.rb
|
|
122
122
|
- lib/mcp_client/auth.rb
|
|
123
|
+
- lib/mcp_client/auth/browser_oauth.rb
|
|
123
124
|
- lib/mcp_client/auth/oauth_provider.rb
|
|
124
125
|
- lib/mcp_client/client.rb
|
|
125
126
|
- lib/mcp_client/config_parser.rb
|
|
@@ -129,6 +130,8 @@ files:
|
|
|
129
130
|
- lib/mcp_client/oauth_client.rb
|
|
130
131
|
- lib/mcp_client/prompt.rb
|
|
131
132
|
- lib/mcp_client/resource.rb
|
|
133
|
+
- lib/mcp_client/resource_content.rb
|
|
134
|
+
- lib/mcp_client/resource_template.rb
|
|
132
135
|
- lib/mcp_client/server_base.rb
|
|
133
136
|
- lib/mcp_client/server_factory.rb
|
|
134
137
|
- lib/mcp_client/server_http.rb
|