Skip to content

Commit 1221aed

Browse files
committed
support complations for resources
1 parent 13286e2 commit 1221aed

File tree

7 files changed

+127
-22
lines changed

7 files changed

+127
-22
lines changed

Gemfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ group :development do
1313
gem "rdoc"
1414
gem "reline"
1515
gem "rspec", "~> 3.12"
16-
gem "rubocop", ">= 1.0"
17-
gem "rubocop-rake", ">= 0.6"
18-
gem "rubocop-rspec"
16+
gem "rubocop", ">= 1.76"
17+
gem "rubocop-rake", ">= 0.7"
18+
gem "rubocop-rspec", ">= 3.6"
1919
end

Gemfile.lock

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ GEM
3636
pp (>= 0.6.0)
3737
rdoc (>= 4.0.0)
3838
reline (>= 0.4.2)
39-
json (2.12.0)
39+
json (2.12.2)
4040
language_server-protocol (3.17.0.5)
4141
lint_roller (1.1.0)
4242
logger (1.7.0)
@@ -76,18 +76,18 @@ GEM
7676
diff-lcs (>= 1.2.0, < 2.0)
7777
rspec-support (~> 3.13.0)
7878
rspec-support (3.13.3)
79-
rubocop (1.75.6)
79+
rubocop (1.76.0)
8080
json (~> 2.3)
8181
language_server-protocol (~> 3.17.0.2)
8282
lint_roller (~> 1.1.0)
8383
parallel (~> 1.10)
8484
parser (>= 3.3.0.2)
8585
rainbow (>= 2.2.2, < 4.0)
8686
regexp_parser (>= 2.9.3, < 3.0)
87-
rubocop-ast (>= 1.44.0, < 2.0)
87+
rubocop-ast (>= 1.45.0, < 2.0)
8888
ruby-progressbar (~> 1.7)
8989
unicode-display_width (>= 2.4.0, < 4.0)
90-
rubocop-ast (1.44.1)
90+
rubocop-ast (1.45.1)
9191
parser (>= 3.3.7.2)
9292
prism (~> 1.4)
9393
rubocop-rake (0.7.1)
@@ -125,9 +125,9 @@ DEPENDENCIES
125125
rdoc
126126
reline
127127
rspec (~> 3.12)
128-
rubocop (>= 1.0)
129-
rubocop-rake (>= 0.6)
130-
rubocop-rspec
128+
rubocop (>= 1.76)
129+
rubocop-rake (>= 0.7)
130+
rubocop-rspec (>= 3.6)
131131
ruby_llm-mcp!
132132

133133
BUNDLED WITH
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# frozen_string_literal: true
2+
3+
require "bundler/setup"
4+
require "ruby_llm/mcp"
5+
require "debug"
6+
require "dotenv"
7+
8+
Dotenv.load
9+
10+
RubyLLM.configure do |config|
11+
config.openai_api_key = ENV.fetch("OPENAI_API_KEY", nil)
12+
end
13+
14+
client = RubyLLM::MCP.client(
15+
name: "streamable_mcp",
16+
transport_type: :streamable,
17+
config: {
18+
url: "http://localhost:3005/mcp"
19+
}
20+
)
21+
resources = client.resources
22+
23+
resources.each do |resource|
24+
puts "Resource: #{resource.name}"
25+
puts "Description: #{resource.description}"
26+
puts "MIME Type: #{resource.mime_type}"
27+
puts "Template: #{resource.template?}"
28+
puts "Content: #{resource.content}"
29+
puts "--------------------------------"
30+
end

lib/ruby_llm/mcp/capabilities.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ def resource_subscribe?
2020
def tools_list_changed?
2121
@capabilities.dig("tools", "listChanged") || false
2222
end
23+
24+
def completion?
25+
@capabilities["completion"].present?
26+
end
2327
end
2428
end
2529
end

lib/ruby_llm/mcp/client.rb

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ def initialize(name:, transport_type:, request_timeout: 8000, reverse_proxy_url:
3636
notification_request
3737
end
3838

39-
def request(body, add_id: true, wait_for_response: true, **options)
40-
@transport.request(body, add_id: add_id, wait_for_response: wait_for_response, **options)
39+
def request(body, **options)
40+
@transport.request(body, **options)
4141
end
4242

4343
def tools(refresh: false)
@@ -50,6 +50,11 @@ def resources(refresh: false)
5050
@resources ||= fetch_and_create_resources
5151
end
5252

53+
def resource_templates(refresh: false)
54+
@resource_templates = nil if refresh
55+
@resource_templates ||= fetch_and_create_resources(set_as_template: true)
56+
end
57+
5358
def execute_tool(name:, parameters:)
5459
response = execute_tool_request(name: name, parameters: parameters)
5560
result = response["result"]
@@ -59,8 +64,12 @@ def execute_tool(name:, parameters:)
5964
result["content"].map { |content| content["text"] }.join("\n")
6065
end
6166

62-
def resource_read_request(uri:)
63-
@resource_read_response = RubyLLM::MCP::Requests::ResourceRead.new(self, uri: uri).call
67+
def resource_read_request(**args)
68+
RubyLLM::MCP::Requests::ResourceRead.new(self, **args).call
69+
end
70+
71+
def completion(**args)
72+
RubyLLM::MCP::Requests::Completion.new(self, **args).call
6473
end
6574

6675
private
@@ -71,23 +80,23 @@ def initialize_request
7180
end
7281

7382
def notification_request
74-
@notification_response = RubyLLM::MCP::Requests::Notification.new(self).call
83+
RubyLLM::MCP::Requests::Notification.new(self).call
7584
end
7685

7786
def tool_list_request
78-
@tool_request = RubyLLM::MCP::Requests::ToolList.new(self).call
87+
RubyLLM::MCP::Requests::ToolList.new(self).call
7988
end
8089

81-
def execute_tool_request(name:, parameters:)
82-
@execute_tool_response = RubyLLM::MCP::Requests::ToolCall.new(self, name: name, parameters: parameters).call
90+
def execute_tool_request(**args)
91+
RubyLLM::MCP::Requests::ToolCall.new(self, **args).call
8392
end
8493

8594
def resources_list_request
86-
@resources_request = RubyLLM::MCP::Requests::ResourceList.new(self).call
95+
RubyLLM::MCP::Requests::ResourceList.new(self).call
8796
end
8897

8998
def resource_template_list_request
90-
@resource_template_list_response = RubyLLM::MCP::Requests::ResourceTemplateList.new(self).call
99+
RubyLLM::MCP::Requests::ResourceTemplateList.new(self).call
91100
end
92101

93102
def fetch_and_create_tools
@@ -99,12 +108,12 @@ def fetch_and_create_tools
99108
end
100109
end
101110

102-
def fetch_and_create_resources
111+
def fetch_and_create_resources(set_as_template: false)
103112
resources_response = resources_list_request
104113
resources_response = resources_response["result"]["resources"]
105114

106115
@resources = resources_response.map do |resource|
107-
RubyLLM::MCP::Resource.new(self, resource)
116+
RubyLLM::MCP::Resource.new(self, resource, template: set_as_template)
108117
end
109118
end
110119
end
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# frozen_string_literal: true
2+
3+
module RubyLLM
4+
module MCP
5+
module Requests
6+
class Completion
7+
def initialize(client, type:, name:, argument:, value:)
8+
@client = client
9+
@type = type
10+
@name = name
11+
@argument = argument
12+
@value = value
13+
end
14+
15+
def call
16+
@client.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_type,
29+
name: @name
30+
},
31+
argument: {
32+
name: @argument,
33+
value: @value
34+
}
35+
}
36+
}
37+
end
38+
39+
def ref_type
40+
case @type
41+
when :prompt
42+
"ref/prompt"
43+
when :resource
44+
"ref/resource"
45+
end
46+
end
47+
end
48+
end
49+
end
50+
end

lib/ruby_llm/mcp/resource.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,18 @@ def content(parsable_information: {})
2727
response.dig("result", "contents", 0, "blob")
2828
end
2929

30+
def arguments_search(argument, value)
31+
if template? && @mcp_client.capabilities.completion?
32+
response = @mcp_client.completion(type: :resource, name: @name, argument: argument, value: value)
33+
response = response.dig("result", "completion")
34+
35+
Struct.new(:arg_values, :total, :has_more)
36+
.new(response["values"], response["total"], response["hasMore"])
37+
else
38+
[]
39+
end
40+
end
41+
3042
def template?
3143
@template
3244
end

0 commit comments

Comments
 (0)