ruby_llm-mcp 0.3.1 → 0.4.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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +121 -2
  3. data/lib/ruby_llm/mcp/capabilities.rb +22 -2
  4. data/lib/ruby_llm/mcp/client.rb +106 -18
  5. data/lib/ruby_llm/mcp/configuration.rb +66 -0
  6. data/lib/ruby_llm/mcp/coordinator.rb +197 -33
  7. data/lib/ruby_llm/mcp/error.rb +34 -0
  8. data/lib/ruby_llm/mcp/errors.rb +37 -4
  9. data/lib/ruby_llm/mcp/logging.rb +16 -0
  10. data/lib/ruby_llm/mcp/parameter.rb +2 -0
  11. data/lib/ruby_llm/mcp/progress.rb +33 -0
  12. data/lib/ruby_llm/mcp/prompt.rb +12 -5
  13. data/lib/ruby_llm/mcp/providers/anthropic/complex_parameter_support.rb +5 -2
  14. data/lib/ruby_llm/mcp/providers/gemini/complex_parameter_support.rb +6 -3
  15. data/lib/ruby_llm/mcp/providers/openai/complex_parameter_support.rb +6 -3
  16. data/lib/ruby_llm/mcp/requests/base.rb +3 -3
  17. data/lib/ruby_llm/mcp/requests/cancelled_notification.rb +32 -0
  18. data/lib/ruby_llm/mcp/requests/completion_prompt.rb +3 -3
  19. data/lib/ruby_llm/mcp/requests/completion_resource.rb +3 -3
  20. data/lib/ruby_llm/mcp/requests/initialization.rb +24 -18
  21. data/lib/ruby_llm/mcp/requests/initialize_notification.rb +15 -9
  22. data/lib/ruby_llm/mcp/requests/logging_set_level.rb +28 -0
  23. data/lib/ruby_llm/mcp/requests/meta.rb +30 -0
  24. data/lib/ruby_llm/mcp/requests/ping.rb +20 -0
  25. data/lib/ruby_llm/mcp/requests/ping_response.rb +28 -0
  26. data/lib/ruby_llm/mcp/requests/prompt_call.rb +3 -3
  27. data/lib/ruby_llm/mcp/requests/prompt_list.rb +1 -1
  28. data/lib/ruby_llm/mcp/requests/resource_list.rb +1 -1
  29. data/lib/ruby_llm/mcp/requests/resource_read.rb +4 -4
  30. data/lib/ruby_llm/mcp/requests/resource_template_list.rb +1 -1
  31. data/lib/ruby_llm/mcp/requests/resources_subscribe.rb +30 -0
  32. data/lib/ruby_llm/mcp/requests/tool_call.rb +6 -3
  33. data/lib/ruby_llm/mcp/requests/tool_list.rb +17 -11
  34. data/lib/ruby_llm/mcp/resource.rb +26 -5
  35. data/lib/ruby_llm/mcp/resource_template.rb +11 -6
  36. data/lib/ruby_llm/mcp/result.rb +90 -0
  37. data/lib/ruby_llm/mcp/tool.rb +28 -3
  38. data/lib/ruby_llm/mcp/transport/sse.rb +81 -75
  39. data/lib/ruby_llm/mcp/transport/stdio.rb +33 -17
  40. data/lib/ruby_llm/mcp/transport/streamable_http.rb +647 -0
  41. data/lib/ruby_llm/mcp/version.rb +1 -1
  42. data/lib/ruby_llm/mcp.rb +18 -0
  43. data/lib/tasks/release.rake +23 -0
  44. metadata +20 -50
  45. data/lib/ruby_llm/mcp/transport/streamable.rb +0 -299
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "logger"
4
+
3
5
  module RubyLLM
4
6
  module MCP
5
7
  class Coordinator
@@ -23,30 +25,29 @@ module RubyLLM
23
25
 
24
26
  def request(body, **options)
25
27
  @transport.request(body, **options)
28
+ rescue RubyLLM::MCP::Errors::TimeoutError => e
29
+ if @transport.alive?
30
+ cancelled_notification(reason: "Request timed out", request_id: e.request_id)
31
+ end
32
+ raise e
26
33
  end
27
34
 
28
35
  def start_transport
29
- case @transport_type
30
- when :sse
31
- @transport = RubyLLM::MCP::Transport::SSE.new(@config[:url],
32
- request_timeout: @config[:request_timeout],
33
- headers: @headers)
34
- when :stdio
35
- @transport = RubyLLM::MCP::Transport::Stdio.new(@config[:command],
36
- request_timeout: @config[:request_timeout],
37
- args: @config[:args],
38
- env: @config[:env])
39
- when :streamable
40
- @transport = RubyLLM::MCP::Transport::Streamable.new(@config[:url],
41
- request_timeout: @config[:request_timeout],
42
- headers: @headers)
43
- else
44
- message = "Invalid transport type: :#{transport_type}. Supported types are :sse, :stdio, :streamable"
45
- raise Errors::InvalidTransportType.new(message: message)
36
+ build_transport
37
+
38
+ initialize_response = initialize_request
39
+ initialize_response.raise_error! if initialize_response.error?
40
+
41
+ # Extract and store the negotiated protocol version
42
+ negotiated_version = initialize_response.value["protocolVersion"]
43
+ @protocol_version = negotiated_version if negotiated_version
44
+
45
+ # Set the protocol version on the transport for subsequent requests
46
+ if @transport.respond_to?(:set_protocol_version)
47
+ @transport.set_protocol_version(@protocol_version)
46
48
  end
47
49
 
48
- @initialize_response = initialize_request
49
- @capabilities = RubyLLM::MCP::Capabilities.new(@initialize_response["result"]["capabilities"])
50
+ @capabilities = RubyLLM::MCP::Capabilities.new(initialize_response.value["capabilities"])
50
51
  initialize_notification
51
52
  end
52
53
 
@@ -64,48 +65,211 @@ module RubyLLM
64
65
  !!@transport&.alive?
65
66
  end
66
67
 
68
+ def ping
69
+ ping_request = RubyLLM::MCP::Requests::Ping.new(self)
70
+ if alive?
71
+ result = ping_request.call
72
+ else
73
+ build_transport
74
+
75
+ result = ping_request.call
76
+ @transport = nil
77
+ end
78
+
79
+ result.value == {}
80
+ rescue RubyLLM::MCP::Errors::TimeoutError, RubyLLM::MCP::Errors::TransportError
81
+ false
82
+ end
83
+
84
+ def process_notification(result)
85
+ notification = result.notification
86
+
87
+ case notification.type
88
+ when "notifications/tools/list_changed"
89
+ client.reset_tools!
90
+ when "notifications/resources/list_changed"
91
+ client.reset_resources!
92
+ when "notifications/resources/updated"
93
+ uri = notification.params["uri"]
94
+ resource = client.resources.find { |r| r.uri == uri }
95
+ resource&.reset_content!
96
+ when "notifications/prompts/list_changed"
97
+ client.reset_prompts!
98
+ when "notifications/message"
99
+ process_logging_message(notification)
100
+ when "notifications/progress"
101
+ process_progress_message(notification)
102
+ when "notifications/cancelled"
103
+ # TODO: - do nothing at the moment until we support client operations
104
+ else
105
+ message = "Unknown notification type: #{notification.type} params:#{notification.params.to_h}"
106
+ raise Errors::UnknownNotification.new(message: message)
107
+ end
108
+ end
109
+
110
+ def process_request(result)
111
+ if result.ping?
112
+ ping_response(id: result.id)
113
+ return
114
+ end
115
+
116
+ # Handle server-initiated requests
117
+ # Currently, we do not support any client operations but will
118
+ raise RubyLLM::MCP::Errors::UnknownRequest.new(message: "Unknown request type: #{result.inspect}")
119
+ end
120
+
121
+ def initialize_request
122
+ RubyLLM::MCP::Requests::Initialization.new(self).call
123
+ end
124
+
125
+ def tool_list
126
+ result = RubyLLM::MCP::Requests::ToolList.new(self).call
127
+ result.raise_error! if result.error?
128
+
129
+ result.value["tools"]
130
+ end
131
+
67
132
  def execute_tool(**args)
133
+ if client.human_in_the_loop?
134
+ name = args[:name]
135
+ params = args[:parameters]
136
+ unless client.on[:human_in_the_loop].call(name, params)
137
+ result = Result.new(
138
+ {
139
+ "result" => {
140
+ "isError" => true,
141
+ "content" => [{ "type" => "text", "text" => "Tool call was cancelled by the client" }]
142
+ }
143
+ }
144
+ )
145
+ return result
146
+ end
147
+ end
148
+
68
149
  RubyLLM::MCP::Requests::ToolCall.new(self, **args).call
69
150
  end
70
151
 
152
+ def resource_list
153
+ result = RubyLLM::MCP::Requests::ResourceList.new(self).call
154
+ result.raise_error! if result.error?
155
+
156
+ result.value["resources"]
157
+ end
158
+
71
159
  def resource_read(**args)
72
160
  RubyLLM::MCP::Requests::ResourceRead.new(self, **args).call
73
161
  end
74
162
 
75
- def completion_resource(**args)
76
- RubyLLM::MCP::Requests::CompletionResource.new(self, **args).call
163
+ def resource_template_list
164
+ result = RubyLLM::MCP::Requests::ResourceTemplateList.new(self).call
165
+ result.raise_error! if result.error?
166
+
167
+ result.value["resourceTemplates"]
77
168
  end
78
169
 
79
- def completion_prompt(**args)
80
- RubyLLM::MCP::Requests::CompletionPrompt.new(self, **args).call
170
+ def resources_subscribe(**args)
171
+ RubyLLM::MCP::Requests::ResourcesSubscribe.new(self, **args).call
172
+ end
173
+
174
+ def prompt_list
175
+ result = RubyLLM::MCP::Requests::PromptList.new(self).call
176
+ result.raise_error! if result.error?
177
+
178
+ result.value["prompts"]
81
179
  end
82
180
 
83
181
  def execute_prompt(**args)
84
182
  RubyLLM::MCP::Requests::PromptCall.new(self, **args).call
85
183
  end
86
184
 
87
- def initialize_request
88
- RubyLLM::MCP::Requests::Initialization.new(self).call
185
+ def completion_resource(**args)
186
+ RubyLLM::MCP::Requests::CompletionResource.new(self, **args).call
187
+ end
188
+
189
+ def completion_prompt(**args)
190
+ RubyLLM::MCP::Requests::CompletionPrompt.new(self, **args).call
89
191
  end
90
192
 
91
193
  def initialize_notification
92
194
  RubyLLM::MCP::Requests::InitializeNotification.new(self).call
93
195
  end
94
196
 
95
- def tool_list
96
- RubyLLM::MCP::Requests::ToolList.new(self).call
197
+ def cancelled_notification(**args)
198
+ RubyLLM::MCP::Requests::CancelledNotification.new(self, **args).call
97
199
  end
98
200
 
99
- def resource_list
100
- RubyLLM::MCP::Requests::ResourceList.new(self).call
201
+ def ping_response(id: nil)
202
+ RubyLLM::MCP::Requests::PingResponse.new(self, id: id).call
101
203
  end
102
204
 
103
- def resource_template_list
104
- RubyLLM::MCP::Requests::ResourceTemplateList.new(self).call
205
+ def set_logging(level:)
206
+ RubyLLM::MCP::Requests::LoggingSetLevel.new(self, level: level).call
105
207
  end
106
208
 
107
- def prompt_list
108
- RubyLLM::MCP::Requests::PromptList.new(self).call
209
+ def build_transport
210
+ case @transport_type
211
+ when :sse
212
+ @transport = RubyLLM::MCP::Transport::SSE.new(@config[:url],
213
+ request_timeout: @config[:request_timeout],
214
+ headers: @headers,
215
+ coordinator: self)
216
+ when :stdio
217
+ @transport = RubyLLM::MCP::Transport::Stdio.new(@config[:command],
218
+ request_timeout: @config[:request_timeout],
219
+ args: @config[:args],
220
+ env: @config[:env],
221
+ coordinator: self)
222
+ when :streamable
223
+ @transport = RubyLLM::MCP::Transport::StreamableHTTP.new(@config[:url],
224
+ request_timeout: @config[:request_timeout],
225
+ headers: @headers,
226
+ coordinator: self)
227
+ else
228
+ message = "Invalid transport type: :#{transport_type}. Supported types are :sse, :stdio, :streamable"
229
+ raise Errors::InvalidTransportType.new(message: message)
230
+ end
231
+ end
232
+
233
+ def process_logging_message(notification)
234
+ if client.logging_handler_enabled?
235
+ client.on[:logging].call(notification)
236
+ else
237
+ default_process_logging_message(notification)
238
+ end
239
+ end
240
+
241
+ def default_process_logging_message(notification, logger: RubyLLM::MCP.logger)
242
+ level = notification.params["level"]
243
+ logger_message = notification.params["logger"]
244
+ message = notification.params["data"]
245
+
246
+ message = "#{logger_message}: #{message}"
247
+
248
+ case level
249
+ when "debug"
250
+ logger.debug(message["message"])
251
+ when "info", "notice"
252
+ logger.info(message["message"])
253
+ when "warning"
254
+ logger.warn(message["message"])
255
+ when "error", "critical"
256
+ logger.error(message["message"])
257
+ when "alert", "emergency"
258
+ logger.fatal(message["message"])
259
+ end
260
+ end
261
+
262
+ def name
263
+ client.name
264
+ end
265
+
266
+ private
267
+
268
+ def process_progress_message(notification)
269
+ progress_obj = RubyLLM::MCP::Progress.new(self, client.on[:progress], notification.params)
270
+ if client.tracking_progress?
271
+ progress_obj.execute_progress_handler
272
+ end
109
273
  end
110
274
  end
111
275
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module MCP
5
+ class Error
6
+ def initialize(error_data)
7
+ @code = error_data["code"]
8
+ @message = error_data["message"]
9
+ @data = error_data["data"]
10
+ end
11
+
12
+ def type
13
+ case @code
14
+ when -32_700
15
+ :parse_error
16
+ when -32_600
17
+ :invalid_request
18
+ when -32_601
19
+ :method_not_found
20
+ when -32_602
21
+ :invalid_params
22
+ when -32_603
23
+ :internal_error
24
+ else
25
+ :custom_error
26
+ end
27
+ end
28
+
29
+ def to_s
30
+ "Error: code: #{@code} (#{type}), message: #{@message}, data: #{@data}"
31
+ end
32
+ end
33
+ end
34
+ end
@@ -12,17 +12,50 @@ module RubyLLM
12
12
  end
13
13
  end
14
14
 
15
- class CompletionNotAvailable < BaseError; end
15
+ module Capabilities
16
+ class CompletionNotAvailable < BaseError; end
17
+ class ResourceSubscribeNotAvailable < BaseError; end
18
+ end
19
+
20
+ class InvalidProtocolVersionError < BaseError; end
21
+
22
+ class InvalidTransportType < BaseError; end
23
+
24
+ class ProgressHandlerNotAvailable < BaseError; end
16
25
 
17
26
  class PromptArgumentError < BaseError; end
18
27
 
19
- class InvalidProtocolVersionError < BaseError; end
28
+ class ResponseError < BaseError
29
+ attr_reader :error
30
+
31
+ def initialize(message:, error:)
32
+ @error = error
33
+ super(message: message)
34
+ end
35
+ end
20
36
 
21
37
  class SessionExpiredError < BaseError; end
22
38
 
23
- class TimeoutError < BaseError; end
39
+ class TimeoutError < BaseError
40
+ attr_reader :request_id
24
41
 
25
- class InvalidTransportType < BaseError; end
42
+ def initialize(message:, request_id:)
43
+ @request_id = request_id
44
+ super(message: message)
45
+ end
46
+ end
47
+
48
+ class TransportError < BaseError
49
+ attr_reader :code, :error
50
+
51
+ def initialize(message:, code: nil, error: nil)
52
+ @code = code
53
+ @error = error
54
+ super(message: message)
55
+ end
56
+ end
57
+
58
+ class UnknownRequest < BaseError; end
26
59
  end
27
60
  end
28
61
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module MCP
5
+ module Logging
6
+ DEBUG = "debug"
7
+ INFO = "info"
8
+ NOTICE = "notice"
9
+ WARNING = "warning"
10
+ ERROR = "error"
11
+ CRITICAL = "critical"
12
+ ALERT = "alert"
13
+ EMERGENCY = "emergency"
14
+ end
15
+ end
16
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "ruby_llm/tool"
4
+
3
5
  module RubyLLM
4
6
  module MCP
5
7
  class Parameter < RubyLLM::Parameter
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module MCP
5
+ class Progress
6
+ attr_reader :progress_token, :progress, :total, :message, :client
7
+
8
+ def initialize(coordinator, progress_handler, progress_data)
9
+ @coordinator = coordinator
10
+ @client = coordinator.client
11
+ @progress_handler = progress_handler
12
+
13
+ @progress_token = progress_data["progressToken"]
14
+ @progress = progress_data["progress"]
15
+ @total = progress_data["total"]
16
+ @message = progress_data["message"]
17
+ end
18
+
19
+ def execute_progress_handler
20
+ @progress_handler&.call(self)
21
+ end
22
+
23
+ def to_h
24
+ {
25
+ progress_token: @progress_token,
26
+ progress: @progress,
27
+ total: @total,
28
+ message: @message
29
+ }
30
+ end
31
+ end
32
+ end
33
+ end
@@ -44,24 +44,31 @@ module RubyLLM
44
44
 
45
45
  def complete(argument, value)
46
46
  if @coordinator.capabilities.completion?
47
- response = @coordinator.completion_prompt(name: @name, argument: argument, value: value)
48
- response = response.dig("result", "completion")
47
+ result = @coordinator.completion_prompt(name: @name, argument: argument, value: value)
48
+ if result.error?
49
+ return result.to_error
50
+ end
51
+
52
+ response = result.value["completion"]
49
53
 
50
54
  Completion.new(values: response["values"], total: response["total"], has_more: response["hasMore"])
51
55
  else
52
- raise Errors::CompletionNotAvailable.new(message: "Completion is not available for this MCP server")
56
+ message = "Completion is not available for this MCP server"
57
+ raise Errors::Capabilities::CompletionNotAvailable.new(message: message)
53
58
  end
54
59
  end
55
60
 
56
61
  private
57
62
 
58
63
  def fetch_prompt_messages(arguments)
59
- response = @coordinator.execute_prompt(
64
+ result = @coordinator.execute_prompt(
60
65
  name: @name,
61
66
  arguments: arguments
62
67
  )
63
68
 
64
- response["result"]["messages"].map do |message|
69
+ result.raise_error! if result.error?
70
+
71
+ result.value["messages"].map do |message|
65
72
  content = create_content_for_message(message["content"])
66
73
 
67
74
  RubyLLM::Message.new(
@@ -23,11 +23,13 @@ module RubyLLM
23
23
  if param.item_type == :object
24
24
  {
25
25
  type: param.type,
26
+ description: param.description,
26
27
  items: { type: param.item_type, properties: clean_parameters(param.properties) }
27
- }
28
+ }.compact
28
29
  else
29
30
  {
30
31
  type: param.type,
32
+ description: param.description,
31
33
  default: param.default,
32
34
  items: { type: param.item_type, enum: param.enum }.compact
33
35
  }.compact
@@ -35,9 +37,10 @@ module RubyLLM
35
37
  when :object
36
38
  {
37
39
  type: param.type,
40
+ description: param.description,
38
41
  properties: clean_parameters(param.properties),
39
42
  required: required_parameters(param.properties)
40
- }
43
+ }.compact
41
44
  when :union
42
45
  {
43
46
  param.union_type => param.properties.map { |property| build_properties(property) }
@@ -16,20 +16,22 @@ module RubyLLM
16
16
  }
17
17
  end
18
18
 
19
- def build_properties(param)
19
+ def build_properties(param) # rubocop:disable Metrics/MethodLength
20
20
  properties = case param.type
21
21
  when :array
22
22
  if param.item_type == :object
23
23
  {
24
24
  type: param_type_for_gemini(param.type),
25
+ description: param.description,
25
26
  items: {
26
27
  type: param_type_for_gemini(param.item_type),
27
28
  properties: param.properties.transform_values { |value| build_properties(value) }
28
29
  }
29
- }
30
+ }.compact
30
31
  else
31
32
  {
32
33
  type: param_type_for_gemini(param.type),
34
+ description: param.description,
33
35
  default: param.default,
34
36
  items: { type: param_type_for_gemini(param.item_type), enum: param.enum }.compact
35
37
  }.compact
@@ -37,9 +39,10 @@ module RubyLLM
37
39
  when :object
38
40
  {
39
41
  type: param_type_for_gemini(param.type),
42
+ description: param.description,
40
43
  properties: param.properties.transform_values { |value| build_properties(value) },
41
44
  required: param.properties.select { |_, p| p.required }.keys
42
- }
45
+ }.compact
43
46
  when :union
44
47
  {
45
48
  param.union_type => param.properties.map { |properties| build_properties(properties) }
@@ -7,20 +7,22 @@ module RubyLLM
7
7
  module ComplexParameterSupport
8
8
  module_function
9
9
 
10
- def param_schema(param)
10
+ def param_schema(param) # rubocop:disable Metrics/MethodLength
11
11
  properties = case param.type
12
12
  when :array
13
13
  if param.item_type == :object
14
14
  {
15
15
  type: param.type,
16
+ description: param.description,
16
17
  items: {
17
18
  type: param.item_type,
18
19
  properties: param.properties.transform_values { |value| param_schema(value) }
19
20
  }
20
- }
21
+ }.compact
21
22
  else
22
23
  {
23
24
  type: param.type,
25
+ description: param.description,
24
26
  default: param.default,
25
27
  items: { type: param.item_type, enum: param.enum }.compact
26
28
  }.compact
@@ -28,9 +30,10 @@ module RubyLLM
28
30
  when :object
29
31
  {
30
32
  type: param.type,
33
+ description: param.description,
31
34
  properties: param.properties.transform_values { |value| param_schema(value) },
32
35
  required: param.properties.select { |_, p| p.required }.keys
33
- }
36
+ }.compact
34
37
  when :union
35
38
  {
36
39
  param.union_type => param.properties.map { |property| param_schema(property) }
@@ -6,10 +6,10 @@ module RubyLLM
6
6
  module MCP
7
7
  module Requests
8
8
  class Base
9
- attr_reader :client
9
+ attr_reader :coordinator
10
10
 
11
- def initialize(client)
12
- @client = client
11
+ def initialize(coordinator)
12
+ @coordinator = coordinator
13
13
  end
14
14
 
15
15
  def call
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module MCP
5
+ module Requests
6
+ class CancelledNotification
7
+ def initialize(coordinator, request_id:, reason:)
8
+ @coordinator = coordinator
9
+ @request_id = request_id
10
+ @reason = reason
11
+ end
12
+
13
+ def call
14
+ @coordinator.request(cancelled_notification_body, add_id: false, wait_for_response: false)
15
+ end
16
+
17
+ private
18
+
19
+ def cancelled_notification_body
20
+ {
21
+ jsonrpc: "2.0",
22
+ method: "notifications/cancelled",
23
+ params: {
24
+ requestId: @request_id,
25
+ reason: @reason
26
+ }
27
+ }
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -4,15 +4,15 @@ module RubyLLM
4
4
  module MCP
5
5
  module Requests
6
6
  class CompletionPrompt
7
- def initialize(client, name:, argument:, value:)
8
- @client = client
7
+ def initialize(coordinator, name:, argument:, value:)
8
+ @coordinator = coordinator
9
9
  @name = name
10
10
  @argument = argument
11
11
  @value = value
12
12
  end
13
13
 
14
14
  def call
15
- @client.request(request_body)
15
+ @coordinator.request(request_body)
16
16
  end
17
17
 
18
18
  private
@@ -4,15 +4,15 @@ module RubyLLM
4
4
  module MCP
5
5
  module Requests
6
6
  class CompletionResource
7
- def initialize(client, uri:, argument:, value:)
8
- @client = client
7
+ def initialize(coordinator, uri:, argument:, value:)
8
+ @coordinator = coordinator
9
9
  @uri = uri
10
10
  @argument = argument
11
11
  @value = value
12
12
  end
13
13
 
14
14
  def call
15
- @client.request(request_body)
15
+ @coordinator.request(request_body)
16
16
  end
17
17
 
18
18
  private