ruby_llm_swarm-mcp 0.8.0 → 0.8.1

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 (89) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -44
  3. data/lib/generators/ruby_llm/mcp/install/templates/initializer.rb +4 -21
  4. data/lib/generators/ruby_llm/mcp/install/templates/mcps.yml +0 -20
  5. data/lib/ruby_llm/mcp/auth/browser/http_server.rb +3 -0
  6. data/lib/ruby_llm/mcp/auth/browser/opener.rb +2 -0
  7. data/lib/ruby_llm/mcp/auth/browser/pages.rb +32 -100
  8. data/lib/ruby_llm/mcp/auth/browser_oauth_provider.rb +6 -32
  9. data/lib/ruby_llm/mcp/auth/http_response_handler.rb +2 -0
  10. data/lib/ruby_llm/mcp/auth/memory_storage.rb +0 -18
  11. data/lib/ruby_llm/mcp/auth/oauth_provider.rb +3 -82
  12. data/lib/ruby_llm/mcp/auth/session_manager.rb +2 -0
  13. data/lib/ruby_llm/mcp/auth/url_builder.rb +2 -0
  14. data/lib/ruby_llm/mcp/client.rb +32 -119
  15. data/lib/ruby_llm/mcp/configuration.rb +6 -74
  16. data/lib/ruby_llm/mcp/coordinator.rb +304 -0
  17. data/lib/ruby_llm/mcp/elicitation.rb +6 -8
  18. data/lib/ruby_llm/mcp/errors.rb +0 -15
  19. data/lib/ruby_llm/mcp/notification_handler.rb +5 -21
  20. data/lib/ruby_llm/mcp/notifications/cancelled.rb +32 -0
  21. data/lib/ruby_llm/mcp/notifications/initialize.rb +24 -0
  22. data/lib/ruby_llm/mcp/notifications/roots_list_change.rb +26 -0
  23. data/lib/ruby_llm/mcp/prompt.rb +7 -7
  24. data/lib/ruby_llm/mcp/protocol.rb +34 -0
  25. data/lib/ruby_llm/mcp/railtie.rb +6 -8
  26. data/lib/ruby_llm/mcp/requests/completion_prompt.rb +50 -0
  27. data/lib/ruby_llm/mcp/requests/completion_resource.rb +50 -0
  28. data/lib/ruby_llm/mcp/requests/initialization.rb +34 -0
  29. data/lib/ruby_llm/mcp/requests/logging_set_level.rb +28 -0
  30. data/lib/ruby_llm/mcp/requests/ping.rb +24 -0
  31. data/lib/ruby_llm/mcp/requests/prompt_call.rb +32 -0
  32. data/lib/ruby_llm/mcp/requests/prompt_list.rb +31 -0
  33. data/lib/ruby_llm/mcp/requests/resource_list.rb +31 -0
  34. data/lib/ruby_llm/mcp/requests/resource_read.rb +30 -0
  35. data/lib/ruby_llm/mcp/requests/resource_template_list.rb +31 -0
  36. data/lib/ruby_llm/mcp/requests/resources_subscribe.rb +30 -0
  37. data/lib/ruby_llm/mcp/requests/shared/meta.rb +32 -0
  38. data/lib/ruby_llm/mcp/requests/shared/pagination.rb +17 -0
  39. data/lib/ruby_llm/mcp/requests/tool_call.rb +35 -0
  40. data/lib/ruby_llm/mcp/requests/tool_list.rb +31 -0
  41. data/lib/ruby_llm/mcp/resource.rb +8 -6
  42. data/lib/ruby_llm/mcp/resource_template.rb +7 -7
  43. data/lib/ruby_llm/mcp/response_handler.rb +67 -0
  44. data/lib/ruby_llm/mcp/responses/elicitation.rb +33 -0
  45. data/lib/ruby_llm/mcp/responses/error.rb +33 -0
  46. data/lib/ruby_llm/mcp/responses/ping.rb +28 -0
  47. data/lib/ruby_llm/mcp/responses/roots_list.rb +31 -0
  48. data/lib/ruby_llm/mcp/responses/sampling_create_message.rb +50 -0
  49. data/lib/ruby_llm/mcp/result.rb +4 -8
  50. data/lib/ruby_llm/mcp/roots.rb +4 -4
  51. data/lib/ruby_llm/mcp/sample.rb +2 -6
  52. data/lib/ruby_llm/mcp/tool.rb +9 -9
  53. data/lib/ruby_llm/mcp/transport.rb +151 -0
  54. data/lib/ruby_llm/mcp/transports/sse.rb +435 -0
  55. data/lib/ruby_llm/mcp/transports/stdio.rb +231 -0
  56. data/lib/ruby_llm/mcp/transports/streamable_http.rb +725 -0
  57. data/lib/ruby_llm/mcp/transports/support/http_client.rb +28 -0
  58. data/lib/ruby_llm/mcp/transports/support/rate_limit.rb +47 -0
  59. data/lib/ruby_llm/mcp/transports/support/timeout.rb +34 -0
  60. data/lib/ruby_llm/mcp/version.rb +1 -1
  61. data/lib/ruby_llm/mcp.rb +7 -30
  62. metadata +38 -33
  63. data/lib/ruby_llm/mcp/adapters/base_adapter.rb +0 -179
  64. data/lib/ruby_llm/mcp/adapters/mcp_sdk_adapter.rb +0 -292
  65. data/lib/ruby_llm/mcp/adapters/mcp_transports/coordinator_stub.rb +0 -33
  66. data/lib/ruby_llm/mcp/adapters/mcp_transports/sse.rb +0 -52
  67. data/lib/ruby_llm/mcp/adapters/mcp_transports/stdio.rb +0 -52
  68. data/lib/ruby_llm/mcp/adapters/mcp_transports/streamable_http.rb +0 -86
  69. data/lib/ruby_llm/mcp/adapters/ruby_llm_adapter.rb +0 -92
  70. data/lib/ruby_llm/mcp/auth/transport_oauth_helper.rb +0 -107
  71. data/lib/ruby_llm/mcp/native/cancellable_operation.rb +0 -57
  72. data/lib/ruby_llm/mcp/native/client.rb +0 -387
  73. data/lib/ruby_llm/mcp/native/json_rpc.rb +0 -170
  74. data/lib/ruby_llm/mcp/native/messages/helpers.rb +0 -39
  75. data/lib/ruby_llm/mcp/native/messages/notifications.rb +0 -42
  76. data/lib/ruby_llm/mcp/native/messages/requests.rb +0 -206
  77. data/lib/ruby_llm/mcp/native/messages/responses.rb +0 -106
  78. data/lib/ruby_llm/mcp/native/messages.rb +0 -36
  79. data/lib/ruby_llm/mcp/native/notification.rb +0 -16
  80. data/lib/ruby_llm/mcp/native/protocol.rb +0 -36
  81. data/lib/ruby_llm/mcp/native/response_handler.rb +0 -110
  82. data/lib/ruby_llm/mcp/native/transport.rb +0 -88
  83. data/lib/ruby_llm/mcp/native/transports/sse.rb +0 -607
  84. data/lib/ruby_llm/mcp/native/transports/stdio.rb +0 -356
  85. data/lib/ruby_llm/mcp/native/transports/streamable_http.rb +0 -926
  86. data/lib/ruby_llm/mcp/native/transports/support/http_client.rb +0 -28
  87. data/lib/ruby_llm/mcp/native/transports/support/rate_limit.rb +0 -49
  88. data/lib/ruby_llm/mcp/native/transports/support/timeout.rb +0 -36
  89. data/lib/ruby_llm/mcp/native.rb +0 -12
@@ -0,0 +1,34 @@
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
@@ -0,0 +1,28 @@
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
@@ -0,0 +1,24 @@
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
@@ -0,0 +1,32 @@
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
@@ -0,0 +1,31 @@
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
@@ -0,0 +1,31 @@
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
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module MCP
5
+ module Requests
6
+ class ResourceRead
7
+ attr_reader :coordinator, :uri
8
+
9
+ def initialize(coordinator, uri:)
10
+ @coordinator = coordinator
11
+ @uri = uri
12
+ end
13
+
14
+ def call
15
+ coordinator.request(reading_resource_body(uri))
16
+ end
17
+
18
+ def reading_resource_body(uri)
19
+ {
20
+ jsonrpc: "2.0",
21
+ method: "resources/read",
22
+ params: {
23
+ uri: uri
24
+ }
25
+ }
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module MCP
5
+ module Requests
6
+ class ResourceTemplateList
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_template_list_body)
16
+ @coordinator.request(body)
17
+ end
18
+
19
+ private
20
+
21
+ def resource_template_list_body
22
+ {
23
+ jsonrpc: "2.0",
24
+ method: "resources/templates/list",
25
+ params: {}
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module MCP
5
+ module Requests
6
+ class ResourcesSubscribe
7
+ def initialize(coordinator, uri:)
8
+ @coordinator = coordinator
9
+ @uri = uri
10
+ end
11
+
12
+ def call
13
+ @coordinator.request(resources_subscribe_body, wait_for_response: false)
14
+ end
15
+
16
+ private
17
+
18
+ def resources_subscribe_body
19
+ {
20
+ jsonrpc: "2.0",
21
+ method: "resources/subscribe",
22
+ params: {
23
+ uri: @uri
24
+ }
25
+ }
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "securerandom"
4
+
5
+ module RubyLLM
6
+ module MCP
7
+ module Requests
8
+ module Shared
9
+ module Meta
10
+ def merge_meta(body)
11
+ meta = {}
12
+ meta.merge!(progress_token) if @coordinator.client.tracking_progress?
13
+
14
+ body[:params] ||= {}
15
+ body[:params].merge!({ _meta: meta }) unless meta.empty?
16
+ body
17
+ end
18
+
19
+ private
20
+
21
+ def progress_token
22
+ { progressToken: generate_progress_token }
23
+ end
24
+
25
+ def generate_progress_token
26
+ SecureRandom.uuid
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module MCP
5
+ module Requests
6
+ module Shared
7
+ module Pagination
8
+ def merge_pagination(body)
9
+ body[:params] ||= {}
10
+ body[:params].merge!({ cursor: @cursor }) if @cursor
11
+ body
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module MCP
5
+ module Requests
6
+ class ToolCall
7
+ include Shared::Meta
8
+
9
+ def initialize(coordinator, name:, parameters: {})
10
+ @coordinator = coordinator
11
+ @name = name
12
+ @parameters = parameters
13
+ end
14
+
15
+ def call
16
+ body = merge_meta(request_body)
17
+ @coordinator.request(body)
18
+ end
19
+
20
+ private
21
+
22
+ def request_body
23
+ {
24
+ jsonrpc: "2.0",
25
+ method: "tools/call",
26
+ params: {
27
+ name: @name,
28
+ arguments: @parameters
29
+ }
30
+ }
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module MCP
5
+ module Requests
6
+ class ToolList
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(tool_list_body)
16
+ @coordinator.request(body)
17
+ end
18
+
19
+ private
20
+
21
+ def tool_list_body
22
+ {
23
+ jsonrpc: "2.0",
24
+ method: "tools/list",
25
+ params: {}
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,12 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "httpx"
4
+
3
5
  module RubyLLM
4
6
  module MCP
5
7
  class Resource
6
- attr_reader :uri, :name, :description, :mime_type, :adapter, :subscribed
8
+ attr_reader :uri, :name, :description, :mime_type, :coordinator, :subscribed
7
9
 
8
- def initialize(adapter, resource)
9
- @adapter = adapter
10
+ def initialize(coordinator, resource)
11
+ @coordinator = coordinator
10
12
  @uri = resource["uri"]
11
13
  @name = resource["name"]
12
14
  @description = resource["description"]
@@ -34,8 +36,8 @@ module RubyLLM
34
36
  end
35
37
 
36
38
  def subscribe!
37
- if @adapter.capabilities.resource_subscribe?
38
- @adapter.resources_subscribe(uri: @uri)
39
+ if @coordinator.capabilities.resource_subscribe?
40
+ @coordinator.resources_subscribe(uri: @uri)
39
41
  @subscribed = true
40
42
  else
41
43
  message = "Resource subscribe is not available for this MCP server"
@@ -99,7 +101,7 @@ module RubyLLM
99
101
  when "http", "https"
100
102
  fetch_uri_content(uri)
101
103
  else # file:// or git://
102
- @adapter.resource_read(uri: uri)
104
+ @coordinator.resource_read(uri: uri)
103
105
  end
104
106
  end
105
107
 
@@ -5,10 +5,10 @@ require "httpx"
5
5
  module RubyLLM
6
6
  module MCP
7
7
  class ResourceTemplate
8
- attr_reader :uri, :name, :description, :mime_type, :adapter, :template
8
+ attr_reader :uri, :name, :description, :mime_type, :coordinator, :template
9
9
 
10
- def initialize(adapter, resource)
11
- @adapter = adapter
10
+ def initialize(coordinator, resource)
11
+ @coordinator = coordinator
12
12
  @uri = resource["uriTemplate"]
13
13
  @name = resource["name"]
14
14
  @description = resource["description"]
@@ -20,7 +20,7 @@ module RubyLLM
20
20
  result = read_response(uri)
21
21
  content_response = result.value.dig("contents", 0)
22
22
 
23
- Resource.new(adapter, {
23
+ Resource.new(coordinator, {
24
24
  "uri" => uri,
25
25
  "name" => "#{@name} (#{uri})",
26
26
  "description" => @description,
@@ -34,8 +34,8 @@ module RubyLLM
34
34
  end
35
35
 
36
36
  def complete(argument, value, context: nil)
37
- if @adapter.capabilities.completion?
38
- result = @adapter.completion_resource(uri: @uri, argument: argument, value: value, context: context)
37
+ if @coordinator.capabilities.completion?
38
+ result = @coordinator.completion_resource(uri: @uri, argument: argument, value: value, context: context)
39
39
  result.raise_error! if result.error?
40
40
 
41
41
  response = result.value["completion"]
@@ -64,7 +64,7 @@ module RubyLLM
64
64
  when "http", "https"
65
65
  fetch_uri_content(uri)
66
66
  else # file:// or git://
67
- @adapter.resource_read(uri: uri)
67
+ @coordinator.resource_read(uri: uri)
68
68
  end
69
69
  end
70
70
 
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module MCP
5
+ class ResponseHandler
6
+ attr_reader :coordinator, :client
7
+
8
+ def initialize(coordinator)
9
+ @coordinator = coordinator
10
+ @client = coordinator.client
11
+ end
12
+
13
+ def execute(result) # rubocop:disable Naming/PredicateMethod
14
+ if result.ping?
15
+ coordinator.ping_response(id: result.id)
16
+ true
17
+ elsif result.roots?
18
+ handle_roots_response(result)
19
+ true
20
+ elsif result.sampling?
21
+ handle_sampling_response(result)
22
+ true
23
+ elsif result.elicitation?
24
+ handle_elicitation_response(result)
25
+ true
26
+ else
27
+ handle_unknown_request(result)
28
+ RubyLLM::MCP.logger.error("MCP client was sent unknown method type and could not respond: #{result.inspect}")
29
+ false
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def handle_roots_response(result)
36
+ RubyLLM::MCP.logger.info("Roots request: #{result.inspect}")
37
+ if client.roots.active?
38
+ coordinator.roots_list_response(id: result.id, roots: client.roots)
39
+ else
40
+ coordinator.error_response(id: result.id, message: "Roots are not enabled", code: -32_000)
41
+ end
42
+ end
43
+
44
+ def handle_sampling_response(result)
45
+ unless MCP.config.sampling.enabled?
46
+ RubyLLM::MCP.logger.info("Sampling is disabled, yet server requested sampling")
47
+ coordinator.error_response(id: result.id, message: "Sampling is disabled", code: -32_000)
48
+ return
49
+ end
50
+
51
+ RubyLLM::MCP.logger.info("Sampling request: #{result.inspect}")
52
+ Sample.new(result, coordinator).execute
53
+ end
54
+
55
+ def handle_elicitation_response(result)
56
+ RubyLLM::MCP.logger.info("Elicitation request: #{result.inspect}")
57
+ Elicitation.new(coordinator, result).execute
58
+ end
59
+
60
+ def handle_unknown_request(result)
61
+ coordinator.error_response(id: result.id,
62
+ message: "Unknown method and could not respond: #{result.method}",
63
+ code: -32_000)
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module MCP
5
+ module Responses
6
+ class Elicitation
7
+ def initialize(coordinator, id:, action:, content:)
8
+ @coordinator = coordinator
9
+ @id = id
10
+ @action = action
11
+ @content = content
12
+ end
13
+
14
+ def call
15
+ @coordinator.request(elicitation_response_body, add_id: false, wait_for_response: false)
16
+ end
17
+
18
+ private
19
+
20
+ def elicitation_response_body
21
+ {
22
+ jsonrpc: "2.0",
23
+ id: @id,
24
+ result: {
25
+ action: @action,
26
+ content: @content
27
+ }.compact
28
+ }
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module MCP
5
+ module Responses
6
+ class Error
7
+ def initialize(coordinator, id:, message:, code: -32_000)
8
+ @coordinator = coordinator
9
+ @id = id
10
+ @message = message
11
+ @code = code
12
+ end
13
+
14
+ def call
15
+ @coordinator.request(sampling_error_body, add_id: false, wait_for_response: false)
16
+ end
17
+
18
+ private
19
+
20
+ def sampling_error_body
21
+ {
22
+ jsonrpc: "2.0",
23
+ id: @id,
24
+ error: {
25
+ code: @code,
26
+ message: @message
27
+ }
28
+ }
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module MCP
5
+ module Responses
6
+ class Ping
7
+ def initialize(coordinator, id:)
8
+ @coordinator = coordinator
9
+ @id = id
10
+ end
11
+
12
+ def call
13
+ @coordinator.request(ping_response_body, add_id: false, wait_for_response: false)
14
+ end
15
+
16
+ private
17
+
18
+ def ping_response_body
19
+ {
20
+ jsonrpc: "2.0",
21
+ id: @id,
22
+ result: {}
23
+ }
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module MCP
5
+ module Responses
6
+ class RootsList
7
+ def initialize(coordinator, roots:, id:)
8
+ @coordinator = coordinator
9
+ @roots = roots
10
+ @id = id
11
+ end
12
+
13
+ def call
14
+ @coordinator.request(roots_list_body, add_id: false, wait_for_response: false)
15
+ end
16
+
17
+ private
18
+
19
+ def roots_list_body
20
+ {
21
+ jsonrpc: "2.0",
22
+ id: @id,
23
+ result: {
24
+ roots: @roots.to_request
25
+ }
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end