ruby_llm-mcp 0.7.1 → 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_generator.rb → install/install_generator.rb} +4 -2
- data/lib/generators/ruby_llm/mcp/{templates → install/templates}/initializer.rb +21 -4
- data/lib/generators/ruby_llm/mcp/install/templates/mcps.yml +29 -0
- data/lib/generators/ruby_llm/mcp/oauth/install_generator.rb +354 -0
- data/lib/generators/ruby_llm/mcp/oauth/templates/concerns/mcp_token_storage.rb.tt +114 -0
- data/lib/generators/ruby_llm/mcp/oauth/templates/concerns/user_mcp_oauth_concern.rb.tt +90 -0
- data/lib/generators/ruby_llm/mcp/oauth/templates/controllers/mcp_connections_controller.rb.tt +239 -0
- data/lib/generators/ruby_llm/mcp/oauth/templates/jobs/cleanup_expired_oauth_states_job.rb.tt +27 -0
- data/lib/generators/ruby_llm/mcp/oauth/templates/jobs/example_job.rb.tt +78 -0
- data/lib/generators/ruby_llm/mcp/oauth/templates/lib/mcp_client.rb.tt +68 -0
- data/lib/generators/ruby_llm/mcp/oauth/templates/migrations/create_mcp_oauth_credentials.rb.tt +19 -0
- data/lib/generators/ruby_llm/mcp/oauth/templates/migrations/create_mcp_oauth_states.rb.tt +21 -0
- data/lib/generators/ruby_llm/mcp/oauth/templates/models/mcp_oauth_credential.rb.tt +54 -0
- data/lib/generators/ruby_llm/mcp/oauth/templates/models/mcp_oauth_state.rb.tt +30 -0
- data/lib/generators/ruby_llm/mcp/oauth/templates/views/index.html.erb +646 -0
- data/lib/generators/ruby_llm/mcp/oauth/templates/views/show.html.erb +560 -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_handler.rb +71 -0
- data/lib/ruby_llm/mcp/auth/browser/callback_server.rb +36 -0
- data/lib/ruby_llm/mcp/auth/browser/http_server.rb +112 -0
- data/lib/ruby_llm/mcp/auth/browser/opener.rb +39 -0
- data/lib/ruby_llm/mcp/auth/browser/pages.rb +607 -0
- data/lib/ruby_llm/mcp/auth/browser_oauth_provider.rb +427 -0
- data/lib/ruby_llm/mcp/auth/client_registrar.rb +170 -0
- data/lib/ruby_llm/mcp/auth/discoverer.rb +255 -0
- data/lib/ruby_llm/mcp/auth/flows/authorization_code_flow.rb +122 -0
- data/lib/ruby_llm/mcp/auth/flows/client_credentials_flow.rb +67 -0
- data/lib/ruby_llm/mcp/auth/grant_strategies/authorization_code.rb +31 -0
- data/lib/ruby_llm/mcp/auth/grant_strategies/base.rb +31 -0
- data/lib/ruby_llm/mcp/auth/grant_strategies/client_credentials.rb +31 -0
- data/lib/ruby_llm/mcp/auth/http_response_handler.rb +63 -0
- data/lib/ruby_llm/mcp/auth/memory_storage.rb +91 -0
- data/lib/ruby_llm/mcp/auth/oauth_provider.rb +341 -0
- data/lib/ruby_llm/mcp/auth/security.rb +44 -0
- data/lib/ruby_llm/mcp/auth/session_manager.rb +54 -0
- data/lib/ruby_llm/mcp/auth/token_manager.rb +307 -0
- data/lib/ruby_llm/mcp/auth/transport_oauth_helper.rb +107 -0
- data/lib/ruby_llm/mcp/auth/url_builder.rb +135 -0
- data/lib/ruby_llm/mcp/auth.rb +371 -0
- data/lib/ruby_llm/mcp/client.rb +312 -35
- data/lib/ruby_llm/mcp/configuration.rb +199 -24
- data/lib/ruby_llm/mcp/elicitation.rb +261 -14
- data/lib/ruby_llm/mcp/errors.rb +29 -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 +7 -13
- 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 +37 -7
- data/lib/tasks/smoke.rake +66 -0
- metadata +115 -39
- data/lib/generators/ruby_llm/mcp/templates/mcps.yml +0 -9
- data/lib/ruby_llm/mcp/coordinator.rb +0 -293
- 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 -58
- data/lib/ruby_llm/mcp/transports/sse.rb +0 -341
- data/lib/ruby_llm/mcp/transports/stdio.rb +0 -230
- data/lib/ruby_llm/mcp/transports/streamable_http.rb +0 -723
- 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,30 +0,0 @@
|
|
|
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
|
|
@@ -1,31 +0,0 @@
|
|
|
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
|
|
@@ -1,30 +0,0 @@
|
|
|
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
|
|
@@ -1,32 +0,0 @@
|
|
|
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
|
|
@@ -1,17 +0,0 @@
|
|
|
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
|
|
@@ -1,35 +0,0 @@
|
|
|
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
|
|
@@ -1,31 +0,0 @@
|
|
|
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,67 +0,0 @@
|
|
|
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
|
|
@@ -1,33 +0,0 @@
|
|
|
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
|
|
@@ -1,33 +0,0 @@
|
|
|
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
|
|
@@ -1,28 +0,0 @@
|
|
|
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
|
|
@@ -1,31 +0,0 @@
|
|
|
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
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RubyLLM
|
|
4
|
-
module MCP
|
|
5
|
-
module Responses
|
|
6
|
-
class SamplingCreateMessage
|
|
7
|
-
def initialize(coordinator, id:, message:, model:)
|
|
8
|
-
@coordinator = coordinator
|
|
9
|
-
@id = id
|
|
10
|
-
@message = message
|
|
11
|
-
@model = model
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def call
|
|
15
|
-
@coordinator.request(sampling_create_message_body, add_id: false, wait_for_response: false)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
private
|
|
19
|
-
|
|
20
|
-
def sampling_create_message_body
|
|
21
|
-
{
|
|
22
|
-
jsonrpc: "2.0",
|
|
23
|
-
id: @id,
|
|
24
|
-
result: {
|
|
25
|
-
role: @message.role,
|
|
26
|
-
content: format_content(@message.content),
|
|
27
|
-
model: @model,
|
|
28
|
-
# TODO: We are going to assume it was a endTurn
|
|
29
|
-
# Look into getting RubyLLM to expose stopReason in message response
|
|
30
|
-
stopReason: "endTurn"
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def format_content(content)
|
|
36
|
-
if content.is_a?(RubyLLM::Content)
|
|
37
|
-
if context.text.none? && content.attachments.any?
|
|
38
|
-
attachment = content.attachments.first
|
|
39
|
-
{ type: attachment.type, data: attachment.content, mime_type: attachment.mime_type }
|
|
40
|
-
else
|
|
41
|
-
{ type: "text", text: content.text }
|
|
42
|
-
end
|
|
43
|
-
else
|
|
44
|
-
{ type: "text", text: content }
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RubyLLM
|
|
4
|
-
module MCP
|
|
5
|
-
class Transport
|
|
6
|
-
class << self
|
|
7
|
-
def transports
|
|
8
|
-
@transports ||= {}
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def register_transport(transport_type, transport_class)
|
|
12
|
-
transports[transport_type] = transport_class
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
extend Forwardable
|
|
17
|
-
|
|
18
|
-
register_transport(:sse, RubyLLM::MCP::Transports::SSE)
|
|
19
|
-
register_transport(:stdio, RubyLLM::MCP::Transports::Stdio)
|
|
20
|
-
register_transport(:streamable, RubyLLM::MCP::Transports::StreamableHTTP)
|
|
21
|
-
register_transport(:streamable_http, RubyLLM::MCP::Transports::StreamableHTTP)
|
|
22
|
-
|
|
23
|
-
attr_reader :transport_type, :coordinator, :config, :pid
|
|
24
|
-
|
|
25
|
-
def initialize(transport_type, coordinator, config:)
|
|
26
|
-
@transport_type = transport_type
|
|
27
|
-
@coordinator = coordinator
|
|
28
|
-
@config = config
|
|
29
|
-
@pid = Process.pid
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def_delegators :transport_protocol, :request, :alive?, :close, :start, :set_protocol_version
|
|
33
|
-
|
|
34
|
-
def transport_protocol
|
|
35
|
-
if @pid != Process.pid
|
|
36
|
-
@pid = Process.pid
|
|
37
|
-
@transport = build_transport
|
|
38
|
-
coordinator.restart_transport
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
@transport_protocol ||= build_transport
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
private
|
|
45
|
-
|
|
46
|
-
def build_transport
|
|
47
|
-
unless RubyLLM::MCP::Transport.transports.key?(transport_type)
|
|
48
|
-
supported_types = RubyLLM::MCP::Transport.transports.keys.join(", ")
|
|
49
|
-
message = "Invalid transport type: :#{transport_type}. Supported types are #{supported_types}"
|
|
50
|
-
raise Errors::InvalidTransportType.new(message: message)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
transport_klass = RubyLLM::MCP::Transport.transports[transport_type]
|
|
54
|
-
transport_klass.new(coordinator: coordinator, **config)
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|