ruby_llm-mcp 0.8.0 → 1.0.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 +144 -162
- data/lib/generators/ruby_llm/mcp/install/templates/initializer.rb +21 -4
- data/lib/generators/ruby_llm/mcp/install/templates/mcps.yml +20 -0
- data/lib/ruby_llm/mcp/adapters/base_adapter.rb +215 -0
- data/lib/ruby_llm/mcp/adapters/mcp_sdk_adapter.rb +413 -0
- data/lib/ruby_llm/mcp/adapters/mcp_transports/coordinator_stub.rb +41 -0
- data/lib/ruby_llm/mcp/adapters/mcp_transports/sse.rb +56 -0
- data/lib/ruby_llm/mcp/adapters/mcp_transports/stdio.rb +56 -0
- data/lib/ruby_llm/mcp/adapters/mcp_transports/streamable_http.rb +90 -0
- data/lib/ruby_llm/mcp/adapters/ruby_llm_adapter.rb +216 -0
- data/lib/ruby_llm/mcp/auth/browser/callback_server.rb +7 -1
- data/lib/ruby_llm/mcp/auth/browser/http_server.rb +0 -3
- data/lib/ruby_llm/mcp/auth/browser/opener.rb +0 -2
- data/lib/ruby_llm/mcp/auth/browser/pages.rb +100 -32
- data/lib/ruby_llm/mcp/auth/browser_oauth_provider.rb +230 -57
- data/lib/ruby_llm/mcp/auth/discoverer.rb +157 -26
- data/lib/ruby_llm/mcp/auth/flows/authorization_code_flow.rb +19 -2
- data/lib/ruby_llm/mcp/auth/flows/client_credentials_flow.rb +3 -2
- data/lib/ruby_llm/mcp/auth/http_response_handler.rb +0 -2
- data/lib/ruby_llm/mcp/auth/memory_storage.rb +31 -12
- data/lib/ruby_llm/mcp/auth/oauth_provider.rb +124 -9
- data/lib/ruby_llm/mcp/auth/session_manager.rb +0 -2
- data/lib/ruby_llm/mcp/auth/token_manager.rb +74 -3
- data/lib/ruby_llm/mcp/auth/transport_oauth_helper.rb +107 -0
- data/lib/ruby_llm/mcp/auth/url_builder.rb +72 -15
- data/lib/ruby_llm/mcp/auth.rb +19 -7
- data/lib/ruby_llm/mcp/client.rb +267 -39
- data/lib/ruby_llm/mcp/configuration.rb +161 -12
- data/lib/ruby_llm/mcp/elicitation.rb +261 -14
- data/lib/ruby_llm/mcp/errors.rb +18 -0
- data/lib/ruby_llm/mcp/extensions/apps/constants.rb +28 -0
- data/lib/ruby_llm/mcp/extensions/apps/resource_metadata.rb +24 -0
- data/lib/ruby_llm/mcp/extensions/apps/tool_metadata.rb +45 -0
- data/lib/ruby_llm/mcp/extensions/configuration.rb +72 -0
- data/lib/ruby_llm/mcp/extensions/constants.rb +16 -0
- data/lib/ruby_llm/mcp/extensions/registry.rb +85 -0
- data/lib/ruby_llm/mcp/handlers/approval_decision.rb +90 -0
- data/lib/ruby_llm/mcp/handlers/async_response.rb +181 -0
- data/lib/ruby_llm/mcp/handlers/concerns/approval_actions.rb +42 -0
- data/lib/ruby_llm/mcp/handlers/concerns/async_execution.rb +80 -0
- data/lib/ruby_llm/mcp/handlers/concerns/elicitation_actions.rb +42 -0
- data/lib/ruby_llm/mcp/handlers/concerns/error_handling.rb +29 -0
- data/lib/ruby_llm/mcp/handlers/concerns/guard_checks.rb +72 -0
- data/lib/ruby_llm/mcp/handlers/concerns/lifecycle.rb +84 -0
- data/lib/ruby_llm/mcp/handlers/concerns/logging.rb +19 -0
- data/lib/ruby_llm/mcp/handlers/concerns/model_filtering.rb +36 -0
- data/lib/ruby_llm/mcp/handlers/concerns/options.rb +83 -0
- data/lib/ruby_llm/mcp/handlers/concerns/registry_integration.rb +54 -0
- data/lib/ruby_llm/mcp/handlers/concerns/sampling_actions.rb +84 -0
- data/lib/ruby_llm/mcp/handlers/concerns/timeouts.rb +52 -0
- data/lib/ruby_llm/mcp/handlers/concerns/tool_filtering.rb +50 -0
- data/lib/ruby_llm/mcp/handlers/elicitation_handler.rb +58 -0
- data/lib/ruby_llm/mcp/handlers/elicitation_registry.rb +203 -0
- data/lib/ruby_llm/mcp/handlers/human_in_the_loop_handler.rb +93 -0
- data/lib/ruby_llm/mcp/handlers/human_in_the_loop_registry.rb +271 -0
- data/lib/ruby_llm/mcp/handlers/promise.rb +192 -0
- data/lib/ruby_llm/mcp/handlers/sampling_handler.rb +64 -0
- data/lib/ruby_llm/mcp/handlers.rb +14 -0
- data/lib/ruby_llm/mcp/native/cancellable_operation.rb +94 -0
- data/lib/ruby_llm/mcp/native/client.rb +551 -0
- data/lib/ruby_llm/mcp/native/json_rpc.rb +170 -0
- data/lib/ruby_llm/mcp/native/messages/helpers.rb +39 -0
- data/lib/ruby_llm/mcp/native/messages/notifications.rb +60 -0
- data/lib/ruby_llm/mcp/native/messages/requests.rb +267 -0
- data/lib/ruby_llm/mcp/native/messages/responses.rb +114 -0
- data/lib/ruby_llm/mcp/native/messages.rb +43 -0
- data/lib/ruby_llm/mcp/native/notification.rb +16 -0
- data/lib/ruby_llm/mcp/native/protocol.rb +79 -0
- data/lib/ruby_llm/mcp/native/response_handler.rb +220 -0
- data/lib/ruby_llm/mcp/native/task_registry.rb +62 -0
- data/lib/ruby_llm/mcp/native/transport.rb +88 -0
- data/lib/ruby_llm/mcp/native/transports/sse.rb +655 -0
- data/lib/ruby_llm/mcp/native/transports/stdio.rb +367 -0
- data/lib/ruby_llm/mcp/native/transports/streamable_http.rb +1024 -0
- data/lib/ruby_llm/mcp/native/transports/support/http_client.rb +28 -0
- data/lib/ruby_llm/mcp/native/transports/support/rate_limiter.rb +49 -0
- data/lib/ruby_llm/mcp/native/transports/support/timeout.rb +36 -0
- data/lib/ruby_llm/mcp/native.rb +12 -0
- data/lib/ruby_llm/mcp/notification_handler.rb +43 -5
- data/lib/ruby_llm/mcp/prompt.rb +7 -7
- data/lib/ruby_llm/mcp/railtie.rb +8 -6
- data/lib/ruby_llm/mcp/resource.rb +17 -8
- data/lib/ruby_llm/mcp/resource_template.rb +8 -7
- data/lib/ruby_llm/mcp/result.rb +8 -4
- data/lib/ruby_llm/mcp/roots.rb +4 -4
- data/lib/ruby_llm/mcp/sample.rb +83 -13
- data/lib/ruby_llm/mcp/schema_validator.rb +33 -0
- data/lib/ruby_llm/mcp/server_capabilities.rb +41 -0
- data/lib/ruby_llm/mcp/task.rb +65 -0
- data/lib/ruby_llm/mcp/tool.rb +33 -27
- data/lib/ruby_llm/mcp/version.rb +1 -1
- data/lib/ruby_llm/mcp.rb +31 -7
- data/lib/tasks/smoke.rake +66 -0
- metadata +77 -36
- data/lib/ruby_llm/mcp/coordinator.rb +0 -304
- data/lib/ruby_llm/mcp/notifications/cancelled.rb +0 -32
- data/lib/ruby_llm/mcp/notifications/initialize.rb +0 -24
- data/lib/ruby_llm/mcp/notifications/roots_list_change.rb +0 -26
- data/lib/ruby_llm/mcp/protocol.rb +0 -34
- data/lib/ruby_llm/mcp/requests/completion_prompt.rb +0 -50
- data/lib/ruby_llm/mcp/requests/completion_resource.rb +0 -50
- data/lib/ruby_llm/mcp/requests/initialization.rb +0 -34
- data/lib/ruby_llm/mcp/requests/logging_set_level.rb +0 -28
- data/lib/ruby_llm/mcp/requests/ping.rb +0 -24
- data/lib/ruby_llm/mcp/requests/prompt_call.rb +0 -32
- data/lib/ruby_llm/mcp/requests/prompt_list.rb +0 -31
- data/lib/ruby_llm/mcp/requests/resource_list.rb +0 -31
- data/lib/ruby_llm/mcp/requests/resource_read.rb +0 -30
- data/lib/ruby_llm/mcp/requests/resource_template_list.rb +0 -31
- data/lib/ruby_llm/mcp/requests/resources_subscribe.rb +0 -30
- data/lib/ruby_llm/mcp/requests/shared/meta.rb +0 -32
- data/lib/ruby_llm/mcp/requests/shared/pagination.rb +0 -17
- data/lib/ruby_llm/mcp/requests/tool_call.rb +0 -35
- data/lib/ruby_llm/mcp/requests/tool_list.rb +0 -31
- data/lib/ruby_llm/mcp/response_handler.rb +0 -67
- data/lib/ruby_llm/mcp/responses/elicitation.rb +0 -33
- data/lib/ruby_llm/mcp/responses/error.rb +0 -33
- data/lib/ruby_llm/mcp/responses/ping.rb +0 -28
- data/lib/ruby_llm/mcp/responses/roots_list.rb +0 -31
- data/lib/ruby_llm/mcp/responses/sampling_create_message.rb +0 -50
- data/lib/ruby_llm/mcp/transport.rb +0 -151
- data/lib/ruby_llm/mcp/transports/sse.rb +0 -435
- data/lib/ruby_llm/mcp/transports/stdio.rb +0 -231
- data/lib/ruby_llm/mcp/transports/streamable_http.rb +0 -725
- data/lib/ruby_llm/mcp/transports/support/http_client.rb +0 -28
- data/lib/ruby_llm/mcp/transports/support/rate_limit.rb +0 -47
- data/lib/ruby_llm/mcp/transports/support/timeout.rb +0 -34
|
@@ -1,304 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "logger"
|
|
4
|
-
|
|
5
|
-
module RubyLLM
|
|
6
|
-
module MCP
|
|
7
|
-
class Coordinator
|
|
8
|
-
attr_reader :client, :transport_type, :config, :capabilities, :protocol_version
|
|
9
|
-
|
|
10
|
-
def initialize(client, transport_type:, config: {})
|
|
11
|
-
@client = client
|
|
12
|
-
@transport_type = transport_type
|
|
13
|
-
@config = config
|
|
14
|
-
|
|
15
|
-
@protocol_version = MCP.config.protocol_version || MCP::Protocol.default_negotiated_version
|
|
16
|
-
|
|
17
|
-
@transport = nil
|
|
18
|
-
@capabilities = nil
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def name
|
|
22
|
-
client.name
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def request(body, **options)
|
|
26
|
-
transport.request(body, **options)
|
|
27
|
-
rescue RubyLLM::MCP::Errors::TimeoutError => e
|
|
28
|
-
if transport&.alive? && !e.request_id.nil?
|
|
29
|
-
cancelled_notification(reason: "Request timed out", request_id: e.request_id)
|
|
30
|
-
end
|
|
31
|
-
raise e
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def process_result(result)
|
|
35
|
-
if result.notification?
|
|
36
|
-
process_notification(result)
|
|
37
|
-
return nil
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
if result.request?
|
|
41
|
-
process_request(result) if alive?
|
|
42
|
-
return nil
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
if result.response?
|
|
46
|
-
return result
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
nil
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def start_transport
|
|
53
|
-
return unless capabilities.nil?
|
|
54
|
-
|
|
55
|
-
transport.start
|
|
56
|
-
|
|
57
|
-
initialize_response = initialize_request
|
|
58
|
-
initialize_response.raise_error! if initialize_response.error?
|
|
59
|
-
|
|
60
|
-
# Extract and store the negotiated protocol version
|
|
61
|
-
negotiated_version = initialize_response.value["protocolVersion"]
|
|
62
|
-
|
|
63
|
-
if negotiated_version && !MCP::Protocol.supported_version?(negotiated_version)
|
|
64
|
-
raise Errors::UnsupportedProtocolVersion.new(
|
|
65
|
-
message: <<~MESSAGE
|
|
66
|
-
Unsupported protocol version, and could not negotiate a supported version: #{negotiated_version}.
|
|
67
|
-
Supported versions: #{MCP::Protocol.supported_versions.join(', ')}
|
|
68
|
-
MESSAGE
|
|
69
|
-
)
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
@protocol_version = negotiated_version if negotiated_version
|
|
73
|
-
|
|
74
|
-
# Set the protocol version on the transport for subsequent requests
|
|
75
|
-
if @transport.respond_to?(:set_protocol_version)
|
|
76
|
-
@transport.set_protocol_version(@protocol_version)
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
@capabilities = RubyLLM::MCP::ServerCapabilities.new(initialize_response.value["capabilities"])
|
|
80
|
-
initialize_notification
|
|
81
|
-
|
|
82
|
-
if client.logging_handler_enabled?
|
|
83
|
-
set_logging(level: client.on_logging_level)
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def stop_transport
|
|
88
|
-
@transport&.close
|
|
89
|
-
@capabilities = nil
|
|
90
|
-
@transport = nil
|
|
91
|
-
@protocol_version = MCP::Protocol.default_negotiated_version
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def restart_transport
|
|
95
|
-
@initialize_response = nil
|
|
96
|
-
stop_transport
|
|
97
|
-
start_transport
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def alive?
|
|
101
|
-
!!@transport&.alive?
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def ping
|
|
105
|
-
ping_request = RubyLLM::MCP::Requests::Ping.new(self)
|
|
106
|
-
if alive?
|
|
107
|
-
result = ping_request.call
|
|
108
|
-
else
|
|
109
|
-
transport.start
|
|
110
|
-
|
|
111
|
-
result = ping_request.call
|
|
112
|
-
@transport = nil
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
result.value == {}
|
|
116
|
-
rescue RubyLLM::MCP::Errors::TimeoutError, RubyLLM::MCP::Errors::TransportError
|
|
117
|
-
false
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
def process_notification(result)
|
|
121
|
-
notification = result.notification
|
|
122
|
-
NotificationHandler.new(self).execute(notification)
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def process_request(result)
|
|
126
|
-
ResponseHandler.new(self).execute(result)
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
def initialize_request
|
|
130
|
-
RubyLLM::MCP::Requests::Initialization.new(self).call
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
def tool_list(cursor: nil)
|
|
134
|
-
result = RubyLLM::MCP::Requests::ToolList.new(self, cursor: cursor).call
|
|
135
|
-
result.raise_error! if result.error?
|
|
136
|
-
|
|
137
|
-
if result.next_cursor?
|
|
138
|
-
result.value["tools"] + tool_list(cursor: result.next_cursor)
|
|
139
|
-
else
|
|
140
|
-
result.value["tools"]
|
|
141
|
-
end
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def execute_tool(**args)
|
|
145
|
-
if client.human_in_the_loop?
|
|
146
|
-
name = args[:name]
|
|
147
|
-
params = args[:parameters]
|
|
148
|
-
unless client.on[:human_in_the_loop].call(name, params)
|
|
149
|
-
result = Result.new(
|
|
150
|
-
{
|
|
151
|
-
"result" => {
|
|
152
|
-
"isError" => true,
|
|
153
|
-
"content" => [{ "type" => "text", "text" => "Tool call was cancelled by the client" }]
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
)
|
|
157
|
-
return result
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
RubyLLM::MCP::Requests::ToolCall.new(self, **args).call
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
def register_resource(resource)
|
|
165
|
-
@client.linked_resources << resource
|
|
166
|
-
@client.resources[resource.name] = resource
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
def resource_list(cursor: nil)
|
|
170
|
-
result = RubyLLM::MCP::Requests::ResourceList.new(self, cursor: cursor).call
|
|
171
|
-
result.raise_error! if result.error?
|
|
172
|
-
|
|
173
|
-
if result.next_cursor?
|
|
174
|
-
result.value["resources"] + resource_list(cursor: result.next_cursor)
|
|
175
|
-
else
|
|
176
|
-
result.value["resources"]
|
|
177
|
-
end
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
def resource_read(**args)
|
|
181
|
-
RubyLLM::MCP::Requests::ResourceRead.new(self, **args).call
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
def resource_template_list(cursor: nil)
|
|
185
|
-
result = RubyLLM::MCP::Requests::ResourceTemplateList.new(self, cursor: cursor).call
|
|
186
|
-
result.raise_error! if result.error?
|
|
187
|
-
|
|
188
|
-
if result.next_cursor?
|
|
189
|
-
result.value["resourceTemplates"] + resource_template_list(cursor: result.next_cursor)
|
|
190
|
-
else
|
|
191
|
-
result.value["resourceTemplates"]
|
|
192
|
-
end
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
def resources_subscribe(**args)
|
|
196
|
-
RubyLLM::MCP::Requests::ResourcesSubscribe.new(self, **args).call
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
def prompt_list(cursor: nil)
|
|
200
|
-
result = RubyLLM::MCP::Requests::PromptList.new(self, cursor: cursor).call
|
|
201
|
-
result.raise_error! if result.error?
|
|
202
|
-
|
|
203
|
-
if result.next_cursor?
|
|
204
|
-
result.value["prompts"] + prompt_list(cursor: result.next_cursor)
|
|
205
|
-
else
|
|
206
|
-
result.value["prompts"]
|
|
207
|
-
end
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
def execute_prompt(**args)
|
|
211
|
-
RubyLLM::MCP::Requests::PromptCall.new(self, **args).call
|
|
212
|
-
end
|
|
213
|
-
|
|
214
|
-
def completion_resource(**args)
|
|
215
|
-
RubyLLM::MCP::Requests::CompletionResource.new(self, **args).call
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
def completion_prompt(**args)
|
|
219
|
-
RubyLLM::MCP::Requests::CompletionPrompt.new(self, **args).call
|
|
220
|
-
end
|
|
221
|
-
|
|
222
|
-
def set_logging(**args)
|
|
223
|
-
RubyLLM::MCP::Requests::LoggingSetLevel.new(self, **args).call
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
## Notifications
|
|
227
|
-
#
|
|
228
|
-
def initialize_notification
|
|
229
|
-
RubyLLM::MCP::Notifications::Initialize.new(self).call
|
|
230
|
-
end
|
|
231
|
-
|
|
232
|
-
def cancelled_notification(**args)
|
|
233
|
-
RubyLLM::MCP::Notifications::Cancelled.new(self, **args).call
|
|
234
|
-
end
|
|
235
|
-
|
|
236
|
-
def roots_list_change_notification
|
|
237
|
-
RubyLLM::MCP::Notifications::RootsListChange.new(self).call
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
## Responses
|
|
241
|
-
#
|
|
242
|
-
def ping_response(**args)
|
|
243
|
-
RubyLLM::MCP::Responses::Ping.new(self, **args).call
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
def roots_list_response(**args)
|
|
247
|
-
RubyLLM::MCP::Responses::RootsList.new(self, **args).call
|
|
248
|
-
end
|
|
249
|
-
|
|
250
|
-
def sampling_create_message_response(**args)
|
|
251
|
-
RubyLLM::MCP::Responses::SamplingCreateMessage.new(self, **args).call
|
|
252
|
-
end
|
|
253
|
-
|
|
254
|
-
def error_response(**args)
|
|
255
|
-
RubyLLM::MCP::Responses::Error.new(self, **args).call
|
|
256
|
-
end
|
|
257
|
-
|
|
258
|
-
def elicitation_response(**args)
|
|
259
|
-
RubyLLM::MCP::Responses::Elicitation.new(self, **args).call
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
def client_capabilities
|
|
263
|
-
capabilities = {}
|
|
264
|
-
|
|
265
|
-
if client.roots.active?
|
|
266
|
-
capabilities[:roots] = {
|
|
267
|
-
listChanged: true
|
|
268
|
-
}
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
if sampling_enabled?
|
|
272
|
-
capabilities[:sampling] = {}
|
|
273
|
-
end
|
|
274
|
-
|
|
275
|
-
if client.elicitation_enabled?
|
|
276
|
-
capabilities[:elicitation] = {}
|
|
277
|
-
end
|
|
278
|
-
|
|
279
|
-
capabilities
|
|
280
|
-
end
|
|
281
|
-
|
|
282
|
-
def transport
|
|
283
|
-
@transport ||= RubyLLM::MCP::Transport.new(@transport_type, self, config: @config)
|
|
284
|
-
end
|
|
285
|
-
|
|
286
|
-
# Get OAuth provider from transport if available
|
|
287
|
-
# @return [OAuthProvider, BrowserOAuthProvider, nil] OAuth provider or nil
|
|
288
|
-
def transport_oauth_provider
|
|
289
|
-
return nil unless @transport
|
|
290
|
-
|
|
291
|
-
transport_protocol = @transport.transport_protocol
|
|
292
|
-
return nil unless transport_protocol.respond_to?(:oauth_provider)
|
|
293
|
-
|
|
294
|
-
transport_protocol.oauth_provider
|
|
295
|
-
end
|
|
296
|
-
|
|
297
|
-
private
|
|
298
|
-
|
|
299
|
-
def sampling_enabled?
|
|
300
|
-
MCP.config.sampling.enabled?
|
|
301
|
-
end
|
|
302
|
-
end
|
|
303
|
-
end
|
|
304
|
-
end
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RubyLLM
|
|
4
|
-
module MCP
|
|
5
|
-
module Notifications
|
|
6
|
-
class Cancelled
|
|
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
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RubyLLM
|
|
4
|
-
module MCP
|
|
5
|
-
module Notifications
|
|
6
|
-
class Initialize
|
|
7
|
-
def initialize(coordinator)
|
|
8
|
-
@coordinator = coordinator
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def call
|
|
12
|
-
@coordinator.request(notification_body, add_id: true, wait_for_response: false)
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def notification_body
|
|
16
|
-
{
|
|
17
|
-
jsonrpc: "2.0",
|
|
18
|
-
method: "notifications/initialized"
|
|
19
|
-
}
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RubyLLM
|
|
4
|
-
module MCP
|
|
5
|
-
module Notifications
|
|
6
|
-
class RootsListChange
|
|
7
|
-
def initialize(coordinator)
|
|
8
|
-
@coordinator = coordinator
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def call
|
|
12
|
-
@coordinator.request(roots_list_change_notification_body, add_id: false, wait_for_response: false)
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
private
|
|
16
|
-
|
|
17
|
-
def roots_list_change_notification_body
|
|
18
|
-
{
|
|
19
|
-
jsonrpc: "2.0",
|
|
20
|
-
method: "notifications/roots/list_changed"
|
|
21
|
-
}
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RubyLLM
|
|
4
|
-
module MCP
|
|
5
|
-
module Protocol
|
|
6
|
-
module_function
|
|
7
|
-
|
|
8
|
-
LATEST_PROTOCOL_VERSION = "2025-06-18"
|
|
9
|
-
DEFAULT_NEGOTIATED_PROTOCOL_VERSION = "2025-03-26"
|
|
10
|
-
SUPPORTED_PROTOCOL_VERSIONS = [
|
|
11
|
-
LATEST_PROTOCOL_VERSION,
|
|
12
|
-
"2025-03-26",
|
|
13
|
-
"2024-11-05",
|
|
14
|
-
"2024-10-07"
|
|
15
|
-
].freeze
|
|
16
|
-
|
|
17
|
-
def supported_version?(version)
|
|
18
|
-
SUPPORTED_PROTOCOL_VERSIONS.include?(version)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def supported_versions
|
|
22
|
-
SUPPORTED_PROTOCOL_VERSIONS
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def latest_version
|
|
26
|
-
LATEST_PROTOCOL_VERSION
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def default_negotiated_version
|
|
30
|
-
DEFAULT_NEGOTIATED_PROTOCOL_VERSION
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RubyLLM
|
|
4
|
-
module MCP
|
|
5
|
-
module Requests
|
|
6
|
-
class CompletionPrompt
|
|
7
|
-
def initialize(coordinator, name:, argument:, value:, context: nil)
|
|
8
|
-
@coordinator = coordinator
|
|
9
|
-
@name = name
|
|
10
|
-
@argument = argument
|
|
11
|
-
@value = value
|
|
12
|
-
@context = context
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def call
|
|
16
|
-
@coordinator.request(request_body)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
private
|
|
20
|
-
|
|
21
|
-
def request_body
|
|
22
|
-
{
|
|
23
|
-
jsonrpc: "2.0",
|
|
24
|
-
id: 1,
|
|
25
|
-
method: "completion/complete",
|
|
26
|
-
params: {
|
|
27
|
-
ref: {
|
|
28
|
-
type: "ref/prompt",
|
|
29
|
-
name: @name
|
|
30
|
-
},
|
|
31
|
-
argument: {
|
|
32
|
-
name: @argument,
|
|
33
|
-
value: @value
|
|
34
|
-
},
|
|
35
|
-
context: format_context
|
|
36
|
-
}.compact
|
|
37
|
-
}
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def format_context
|
|
41
|
-
return nil if @context.nil?
|
|
42
|
-
|
|
43
|
-
{
|
|
44
|
-
arguments: @context
|
|
45
|
-
}
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RubyLLM
|
|
4
|
-
module MCP
|
|
5
|
-
module Requests
|
|
6
|
-
class CompletionResource
|
|
7
|
-
def initialize(coordinator, uri:, argument:, value:, context: nil)
|
|
8
|
-
@coordinator = coordinator
|
|
9
|
-
@uri = uri
|
|
10
|
-
@argument = argument
|
|
11
|
-
@value = value
|
|
12
|
-
@context = context
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def call
|
|
16
|
-
@coordinator.request(request_body)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
private
|
|
20
|
-
|
|
21
|
-
def request_body
|
|
22
|
-
{
|
|
23
|
-
jsonrpc: "2.0",
|
|
24
|
-
id: 1,
|
|
25
|
-
method: "completion/complete",
|
|
26
|
-
params: {
|
|
27
|
-
ref: {
|
|
28
|
-
type: "ref/resource",
|
|
29
|
-
uri: @uri
|
|
30
|
-
},
|
|
31
|
-
argument: {
|
|
32
|
-
name: @argument,
|
|
33
|
-
value: @value
|
|
34
|
-
},
|
|
35
|
-
context: format_context
|
|
36
|
-
}.compact
|
|
37
|
-
}
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def format_context
|
|
41
|
-
return nil if @context.nil?
|
|
42
|
-
|
|
43
|
-
{
|
|
44
|
-
arguments: @context
|
|
45
|
-
}
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RubyLLM
|
|
4
|
-
module MCP
|
|
5
|
-
module Requests
|
|
6
|
-
class Initialization
|
|
7
|
-
def initialize(coordinator)
|
|
8
|
-
@coordinator = coordinator
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def call
|
|
12
|
-
@coordinator.request(initialize_body)
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
private
|
|
16
|
-
|
|
17
|
-
def initialize_body
|
|
18
|
-
{
|
|
19
|
-
jsonrpc: "2.0",
|
|
20
|
-
method: "initialize",
|
|
21
|
-
params: {
|
|
22
|
-
protocolVersion: @coordinator.protocol_version,
|
|
23
|
-
capabilities: @coordinator.client_capabilities,
|
|
24
|
-
clientInfo: {
|
|
25
|
-
name: "RubyLLM-MCP Client",
|
|
26
|
-
version: RubyLLM::MCP::VERSION
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RubyLLM
|
|
4
|
-
module MCP
|
|
5
|
-
module Requests
|
|
6
|
-
class LoggingSetLevel
|
|
7
|
-
def initialize(coordinator, level:)
|
|
8
|
-
@coordinator = coordinator
|
|
9
|
-
@level = level
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def call
|
|
13
|
-
@coordinator.request(logging_set_body)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def logging_set_body
|
|
17
|
-
{
|
|
18
|
-
jsonrpc: "2.0",
|
|
19
|
-
method: "logging/setLevel",
|
|
20
|
-
params: {
|
|
21
|
-
level: @level
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RubyLLM
|
|
4
|
-
module MCP
|
|
5
|
-
module Requests
|
|
6
|
-
class Ping
|
|
7
|
-
def initialize(coordinator)
|
|
8
|
-
@coordinator = coordinator
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def call
|
|
12
|
-
@coordinator.request(ping_body)
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def ping_body
|
|
16
|
-
{
|
|
17
|
-
jsonrpc: "2.0",
|
|
18
|
-
method: "ping"
|
|
19
|
-
}
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RubyLLM
|
|
4
|
-
module MCP
|
|
5
|
-
module Requests
|
|
6
|
-
class PromptCall
|
|
7
|
-
def initialize(coordinator, name:, arguments: {})
|
|
8
|
-
@coordinator = coordinator
|
|
9
|
-
@name = name
|
|
10
|
-
@arguments = arguments
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def call
|
|
14
|
-
@coordinator.request(request_body)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
private
|
|
18
|
-
|
|
19
|
-
def request_body
|
|
20
|
-
{
|
|
21
|
-
jsonrpc: "2.0",
|
|
22
|
-
method: "prompts/get",
|
|
23
|
-
params: {
|
|
24
|
-
name: @name,
|
|
25
|
-
arguments: @arguments
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RubyLLM
|
|
4
|
-
module MCP
|
|
5
|
-
module Requests
|
|
6
|
-
class PromptList
|
|
7
|
-
include Shared::Pagination
|
|
8
|
-
|
|
9
|
-
def initialize(coordinator, cursor: nil)
|
|
10
|
-
@coordinator = coordinator
|
|
11
|
-
@cursor = cursor
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def call
|
|
15
|
-
body = merge_pagination(request_body)
|
|
16
|
-
@coordinator.request(body)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
private
|
|
20
|
-
|
|
21
|
-
def request_body
|
|
22
|
-
{
|
|
23
|
-
jsonrpc: "2.0",
|
|
24
|
-
method: "prompts/list",
|
|
25
|
-
params: {}
|
|
26
|
-
}
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RubyLLM
|
|
4
|
-
module MCP
|
|
5
|
-
module Requests
|
|
6
|
-
class ResourceList
|
|
7
|
-
include Shared::Pagination
|
|
8
|
-
|
|
9
|
-
def initialize(coordinator, cursor: nil)
|
|
10
|
-
@coordinator = coordinator
|
|
11
|
-
@cursor = cursor
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def call
|
|
15
|
-
body = merge_pagination(resource_list_body)
|
|
16
|
-
@coordinator.request(body)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
private
|
|
20
|
-
|
|
21
|
-
def resource_list_body
|
|
22
|
-
{
|
|
23
|
-
jsonrpc: "2.0",
|
|
24
|
-
method: "resources/list",
|
|
25
|
-
params: {}
|
|
26
|
-
}
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|