66
77module MCP
88 class Client
9+ class ServerError < StandardError
10+ attr_reader :code , :data
11+
12+ def initialize ( message , code :, data : nil )
13+ super ( message )
14+ @code = code
15+ @data = data
16+ end
17+ end
18+
19+ class RequestHandlerError < StandardError
20+ attr_reader :error_type , :original_error , :request
21+
22+ def initialize ( message , request , error_type : :internal_error , original_error : nil )
23+ super ( message )
24+ @request = request
25+ @error_type = error_type
26+ @original_error = original_error
27+ end
28+ end
29+
930 # Initializes a new MCP::Client instance.
1031 #
1132 # @param transport [Object] The transport object to use for communication with the server.
@@ -33,11 +54,7 @@ def initialize(transport:)
3354 # puts tool.name
3455 # end
3556 def tools
36- response = transport . send_request ( request : {
37- jsonrpc : JsonRpcHandler ::Version ::V2_0 ,
38- id : request_id ,
39- method : "tools/list" ,
40- } )
57+ response = request ( method : "tools/list" )
4158
4259 response . dig ( "result" , "tools" ) &.map do |tool |
4360 Tool . new (
@@ -53,11 +70,7 @@ def tools
5370 #
5471 # @return [Array<Hash>] An array of available resources.
5572 def resources
56- response = transport . send_request ( request : {
57- jsonrpc : JsonRpcHandler ::Version ::V2_0 ,
58- id : request_id ,
59- method : "resources/list" ,
60- } )
73+ response = request ( method : "resources/list" )
6174
6275 response . dig ( "result" , "resources" ) || [ ]
6376 end
@@ -67,11 +80,7 @@ def resources
6780 #
6881 # @return [Array<Hash>] An array of available resource templates.
6982 def resource_templates
70- response = transport . send_request ( request : {
71- jsonrpc : JsonRpcHandler ::Version ::V2_0 ,
72- id : request_id ,
73- method : "resources/templates/list" ,
74- } )
83+ response = request ( method : "resources/templates/list" )
7584
7685 response . dig ( "result" , "resourceTemplates" ) || [ ]
7786 end
@@ -81,11 +90,7 @@ def resource_templates
8190 #
8291 # @return [Array<Hash>] An array of available prompts.
8392 def prompts
84- response = transport . send_request ( request : {
85- jsonrpc : JsonRpcHandler ::Version ::V2_0 ,
86- id : request_id ,
87- method : "prompts/list" ,
88- } )
93+ response = request ( method : "prompts/list" )
8994
9095 response . dig ( "result" , "prompts" ) || [ ]
9196 end
@@ -119,25 +124,15 @@ def call_tool(name: nil, tool: nil, arguments: nil, progress_token: nil)
119124 params [ :_meta ] = { progressToken : progress_token }
120125 end
121126
122- transport . send_request ( request : {
123- jsonrpc : JsonRpcHandler ::Version ::V2_0 ,
124- id : request_id ,
125- method : "tools/call" ,
126- params : params ,
127- } )
127+ request ( method : "tools/call" , params : params )
128128 end
129129
130130 # Reads a resource from the server by URI and returns the contents.
131131 #
132132 # @param uri [String] The URI of the resource to read.
133133 # @return [Array<Hash>] An array of resource contents (text or blob).
134134 def read_resource ( uri :)
135- response = transport . send_request ( request : {
136- jsonrpc : JsonRpcHandler ::Version ::V2_0 ,
137- id : request_id ,
138- method : "resources/read" ,
139- params : { uri : uri } ,
140- } )
135+ response = request ( method : "resources/read" , params : { uri : uri } )
141136
142137 response . dig ( "result" , "contents" ) || [ ]
143138 end
@@ -147,31 +142,34 @@ def read_resource(uri:)
147142 # @param name [String] The name of the prompt to get.
148143 # @return [Hash] A hash containing the prompt details.
149144 def get_prompt ( name :)
150- response = transport . send_request ( request : {
151- jsonrpc : JsonRpcHandler ::Version ::V2_0 ,
152- id : request_id ,
153- method : "prompts/get" ,
154- params : { name : name } ,
155- } )
145+ response = request ( method : "prompts/get" , params : { name : name } )
156146
157147 response . fetch ( "result" , { } )
158148 end
159149
160150 private
161151
162- def request_id
163- SecureRandom . uuid
164- end
152+ def request ( method :, params : nil )
153+ request_body = {
154+ jsonrpc : JsonRpcHandler ::Version ::V2_0 ,
155+ id : request_id ,
156+ method : method ,
157+ }
158+ request_body [ :params ] = params if params
165159
166- class RequestHandlerError < StandardError
167- attr_reader :error_type , :original_error , :request
160+ response = transport . send_request ( request : request_body )
168161
169- def initialize ( message , request , error_type : :internal_error , original_error : nil )
170- super ( message )
171- @request = request
172- @error_type = error_type
173- @original_error = original_error
162+ # Guard with `is_a?(Hash)` because custom transports may return non-Hash values.
163+ if response . is_a? ( Hash ) && response . key? ( "error" )
164+ error = response [ "error" ]
165+ raise ServerError . new ( error [ "message" ] , code : error [ "code" ] , data : error [ "data" ] )
174166 end
167+
168+ response
169+ end
170+
171+ def request_id
172+ SecureRandom . uuid
175173 end
176174 end
177175end
0 commit comments