model_context_protocol_riccardo 0.7.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 +7 -0
- data/.cursor/rules/release-changelogs.mdc +32 -0
- data/.gitattributes +4 -0
- data/.github/workflows/ci.yml +22 -0
- data/.gitignore +8 -0
- data/.rubocop.yml +5 -0
- data/.ruby-version +1 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +117 -0
- data/LICENSE.txt +21 -0
- data/README.md +473 -0
- data/Rakefile +17 -0
- data/bin/console +15 -0
- data/bin/rake +31 -0
- data/bin/setup +8 -0
- data/dev.yml +31 -0
- data/examples/stdio_server.rb +94 -0
- data/lib/mcp-ruby.rb +3 -0
- data/lib/model_context_protocol/configuration.rb +75 -0
- data/lib/model_context_protocol/content.rb +33 -0
- data/lib/model_context_protocol/instrumentation.rb +26 -0
- data/lib/model_context_protocol/json_rpc.rb +11 -0
- data/lib/model_context_protocol/methods.rb +86 -0
- data/lib/model_context_protocol/prompt/argument.rb +21 -0
- data/lib/model_context_protocol/prompt/message.rb +19 -0
- data/lib/model_context_protocol/prompt/result.rb +19 -0
- data/lib/model_context_protocol/prompt.rb +82 -0
- data/lib/model_context_protocol/resource/contents.rb +45 -0
- data/lib/model_context_protocol/resource/embedded.rb +18 -0
- data/lib/model_context_protocol/resource.rb +24 -0
- data/lib/model_context_protocol/resource_template.rb +24 -0
- data/lib/model_context_protocol/server.rb +258 -0
- data/lib/model_context_protocol/string_utils.rb +26 -0
- data/lib/model_context_protocol/tool/annotations.rb +27 -0
- data/lib/model_context_protocol/tool/input_schema.rb +26 -0
- data/lib/model_context_protocol/tool/response.rb +18 -0
- data/lib/model_context_protocol/tool.rb +85 -0
- data/lib/model_context_protocol/transport.rb +33 -0
- data/lib/model_context_protocol/transports/stdio.rb +33 -0
- data/lib/model_context_protocol/version.rb +5 -0
- data/lib/model_context_protocol.rb +44 -0
- data/model_context_protocol.gemspec +32 -0
- metadata +116 -0
@@ -0,0 +1,258 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json_rpc_handler"
|
4
|
+
require_relative "instrumentation"
|
5
|
+
require_relative "methods"
|
6
|
+
|
7
|
+
module ModelContextProtocol
|
8
|
+
class Server
|
9
|
+
class RequestHandlerError < StandardError
|
10
|
+
attr_reader :error_type
|
11
|
+
attr_reader :original_error
|
12
|
+
|
13
|
+
def initialize(message, request, error_type: :internal_error, original_error: nil)
|
14
|
+
super(message)
|
15
|
+
@request = request
|
16
|
+
@error_type = error_type
|
17
|
+
@original_error = original_error
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
include Instrumentation
|
22
|
+
|
23
|
+
attr_accessor :name, :tools, :prompts, :resources, :server_context, :configuration, :capabilities
|
24
|
+
|
25
|
+
def initialize(
|
26
|
+
name: "model_context_protocol",
|
27
|
+
tools: [],
|
28
|
+
prompts: [],
|
29
|
+
resources: [],
|
30
|
+
resource_templates: [],
|
31
|
+
server_context: nil,
|
32
|
+
configuration: nil,
|
33
|
+
capabilities: { prompts: {}, resources: {}, tools: {} }
|
34
|
+
)
|
35
|
+
@name = name
|
36
|
+
@tools = tools.to_h { |t| [t.name_value, t] }
|
37
|
+
@prompts = prompts.to_h { |p| [p.name_value, p] }
|
38
|
+
@resources = resources
|
39
|
+
@resource_templates = resource_templates
|
40
|
+
@resource_index = index_resources_by_uri(resources)
|
41
|
+
@server_context = server_context
|
42
|
+
@configuration = ModelContextProtocol.configuration.merge(configuration)
|
43
|
+
@capabilities = capabilities
|
44
|
+
|
45
|
+
@handlers = {
|
46
|
+
Methods::RESOURCES_LIST => method(:list_resources),
|
47
|
+
Methods::RESOURCES_READ => method(:read_resource_no_content),
|
48
|
+
Methods::RESOURCES_TEMPLATES_LIST => method(:list_resource_templates),
|
49
|
+
Methods::TOOLS_LIST => method(:list_tools),
|
50
|
+
Methods::TOOLS_CALL => method(:call_tool),
|
51
|
+
Methods::PROMPTS_LIST => method(:list_prompts),
|
52
|
+
Methods::PROMPTS_GET => method(:get_prompt),
|
53
|
+
Methods::INITIALIZE => method(:init),
|
54
|
+
Methods::PING => ->(_) { {} },
|
55
|
+
|
56
|
+
# No op handlers for currently unsupported methods
|
57
|
+
Methods::RESOURCES_SUBSCRIBE => ->(_) {},
|
58
|
+
Methods::RESOURCES_UNSUBSCRIBE => ->(_) {},
|
59
|
+
Methods::LOGGING_SET_LEVEL => ->(_) {},
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
def handle(request)
|
64
|
+
JsonRpcHandler.handle(request) do |method|
|
65
|
+
handle_request(request, method)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def handle_json(request)
|
70
|
+
JsonRpcHandler.handle_json(request) do |method|
|
71
|
+
handle_request(request, method)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def define_tool(name: nil, description: nil, input_schema: nil, annotations: nil, &block)
|
76
|
+
tool = Tool.define(name:, description:, input_schema:, annotations:, &block)
|
77
|
+
@tools[tool.name_value] = tool
|
78
|
+
end
|
79
|
+
|
80
|
+
def define_prompt(name: nil, description: nil, arguments: [], &block)
|
81
|
+
prompt = Prompt.define(name:, description:, arguments:, &block)
|
82
|
+
@prompts[prompt.name_value] = prompt
|
83
|
+
end
|
84
|
+
|
85
|
+
def resources_list_handler(&block)
|
86
|
+
@handlers[Methods::RESOURCES_LIST] = block
|
87
|
+
end
|
88
|
+
|
89
|
+
def resources_read_handler(&block)
|
90
|
+
@handlers[Methods::RESOURCES_READ] = block
|
91
|
+
end
|
92
|
+
|
93
|
+
def resources_templates_list_handler(&block)
|
94
|
+
@handlers[Methods::RESOURCES_TEMPLATES_LIST] = block
|
95
|
+
end
|
96
|
+
|
97
|
+
def tools_list_handler(&block)
|
98
|
+
@handlers[Methods::TOOLS_LIST] = block
|
99
|
+
end
|
100
|
+
|
101
|
+
def tools_call_handler(&block)
|
102
|
+
@handlers[Methods::TOOLS_CALL] = block
|
103
|
+
end
|
104
|
+
|
105
|
+
def prompts_list_handler(&block)
|
106
|
+
@handlers[Methods::PROMPTS_LIST] = block
|
107
|
+
end
|
108
|
+
|
109
|
+
def prompts_get_handler(&block)
|
110
|
+
@handlers[Methods::PROMPTS_GET] = block
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def handle_request(request, method)
|
116
|
+
handler = @handlers[method]
|
117
|
+
unless handler
|
118
|
+
instrument_call("unsupported_method") {}
|
119
|
+
return
|
120
|
+
end
|
121
|
+
|
122
|
+
Methods.ensure_capability!(method, capabilities)
|
123
|
+
|
124
|
+
->(params) {
|
125
|
+
instrument_call(method) do
|
126
|
+
case method
|
127
|
+
when Methods::TOOLS_LIST
|
128
|
+
{ tools: @handlers[Methods::TOOLS_LIST].call(params) }
|
129
|
+
when Methods::PROMPTS_LIST
|
130
|
+
{ prompts: @handlers[Methods::PROMPTS_LIST].call(params) }
|
131
|
+
when Methods::RESOURCES_LIST
|
132
|
+
{ resources: @handlers[Methods::RESOURCES_LIST].call(params) }
|
133
|
+
when Methods::RESOURCES_READ
|
134
|
+
{ contents: @handlers[Methods::RESOURCES_READ].call(params) }
|
135
|
+
when Methods::RESOURCES_TEMPLATES_LIST
|
136
|
+
{ resourceTemplates: @handlers[Methods::RESOURCES_TEMPLATES_LIST].call(params) }
|
137
|
+
else
|
138
|
+
@handlers[method].call(params)
|
139
|
+
end
|
140
|
+
rescue => e
|
141
|
+
report_exception(e, { request: request })
|
142
|
+
if e.is_a?(RequestHandlerError)
|
143
|
+
add_instrumentation_data(error: e.error_type)
|
144
|
+
raise e
|
145
|
+
end
|
146
|
+
|
147
|
+
add_instrumentation_data(error: :internal_error)
|
148
|
+
raise RequestHandlerError.new("Internal error handling #{method} request", request, original_error: e)
|
149
|
+
end
|
150
|
+
}
|
151
|
+
end
|
152
|
+
|
153
|
+
def server_info
|
154
|
+
@server_info ||= {
|
155
|
+
name:,
|
156
|
+
version: ModelContextProtocol::VERSION,
|
157
|
+
}
|
158
|
+
end
|
159
|
+
|
160
|
+
def init(request)
|
161
|
+
add_instrumentation_data(method: Methods::INITIALIZE)
|
162
|
+
{
|
163
|
+
protocolVersion: configuration.protocol_version,
|
164
|
+
capabilities: capabilities,
|
165
|
+
serverInfo: server_info,
|
166
|
+
}
|
167
|
+
end
|
168
|
+
|
169
|
+
def list_tools(request)
|
170
|
+
add_instrumentation_data(method: Methods::TOOLS_LIST)
|
171
|
+
@tools.map { |_, tool| tool.to_h }
|
172
|
+
end
|
173
|
+
|
174
|
+
def call_tool(request)
|
175
|
+
add_instrumentation_data(method: Methods::TOOLS_CALL)
|
176
|
+
tool_name = request[:name]
|
177
|
+
tool = tools[tool_name]
|
178
|
+
unless tool
|
179
|
+
add_instrumentation_data(error: :tool_not_found)
|
180
|
+
raise RequestHandlerError.new("Tool not found #{tool_name}", request, error_type: :tool_not_found)
|
181
|
+
end
|
182
|
+
|
183
|
+
arguments = request[:arguments]
|
184
|
+
add_instrumentation_data(tool_name:)
|
185
|
+
|
186
|
+
if tool.input_schema&.missing_required_arguments?(arguments)
|
187
|
+
add_instrumentation_data(error: :missing_required_arguments)
|
188
|
+
raise RequestHandlerError.new(
|
189
|
+
"Missing required arguments: #{tool.input_schema.missing_required_arguments(arguments).join(", ")}",
|
190
|
+
request,
|
191
|
+
error_type: :missing_required_arguments,
|
192
|
+
)
|
193
|
+
end
|
194
|
+
|
195
|
+
begin
|
196
|
+
call_params = tool.method(:call).parameters.flatten
|
197
|
+
if call_params.include?(:server_context)
|
198
|
+
tool.call(**arguments.transform_keys(&:to_sym), server_context:).to_h
|
199
|
+
else
|
200
|
+
tool.call(**arguments.transform_keys(&:to_sym)).to_h
|
201
|
+
end
|
202
|
+
rescue => e
|
203
|
+
raise RequestHandlerError.new("Internal error calling tool #{tool_name}", request, original_error: e)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def list_prompts(request)
|
208
|
+
add_instrumentation_data(method: Methods::PROMPTS_LIST)
|
209
|
+
@prompts.map { |_, prompt| prompt.to_h }
|
210
|
+
end
|
211
|
+
|
212
|
+
def get_prompt(request)
|
213
|
+
add_instrumentation_data(method: Methods::PROMPTS_GET)
|
214
|
+
prompt_name = request[:name]
|
215
|
+
prompt = @prompts[prompt_name]
|
216
|
+
unless prompt
|
217
|
+
add_instrumentation_data(error: :prompt_not_found)
|
218
|
+
raise RequestHandlerError.new("Prompt not found #{prompt_name}", request, error_type: :prompt_not_found)
|
219
|
+
end
|
220
|
+
|
221
|
+
add_instrumentation_data(prompt_name:)
|
222
|
+
|
223
|
+
prompt_args = request[:arguments]
|
224
|
+
prompt.validate_arguments!(prompt_args)
|
225
|
+
|
226
|
+
prompt.template(prompt_args, server_context:).to_h
|
227
|
+
end
|
228
|
+
|
229
|
+
def list_resources(request)
|
230
|
+
add_instrumentation_data(method: Methods::RESOURCES_LIST)
|
231
|
+
|
232
|
+
@resources.map(&:to_h)
|
233
|
+
end
|
234
|
+
|
235
|
+
# Server implementation should set read_resource_handler to override no-op default
|
236
|
+
def read_resource_no_content(request)
|
237
|
+
add_instrumentation_data(method: Methods::RESOURCES_READ)
|
238
|
+
add_instrumentation_data(resource_uri: request[:uri])
|
239
|
+
[]
|
240
|
+
end
|
241
|
+
|
242
|
+
def list_resource_templates(request)
|
243
|
+
add_instrumentation_data(method: Methods::RESOURCES_TEMPLATES_LIST)
|
244
|
+
|
245
|
+
@resource_templates.map(&:to_h)
|
246
|
+
end
|
247
|
+
|
248
|
+
def report_exception(exception, server_context = {})
|
249
|
+
configuration.exception_reporter.call(exception, server_context)
|
250
|
+
end
|
251
|
+
|
252
|
+
def index_resources_by_uri(resources)
|
253
|
+
resources.each_with_object({}) do |resource, hash|
|
254
|
+
hash[resource.uri] = resource
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module ModelContextProtocol
|
5
|
+
module StringUtils
|
6
|
+
extend self
|
7
|
+
|
8
|
+
def handle_from_class_name(class_name)
|
9
|
+
underscore(demodulize(class_name))
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def demodulize(path)
|
15
|
+
path.to_s.split("::").last || path.to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
def underscore(camel_cased_word)
|
19
|
+
camel_cased_word.dup
|
20
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
21
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
22
|
+
.tr("-", "_")
|
23
|
+
.downcase
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ModelContextProtocol
|
4
|
+
class Tool
|
5
|
+
class Annotations
|
6
|
+
attr_reader :title, :read_only_hint, :destructive_hint, :idempotent_hint, :open_world_hint
|
7
|
+
|
8
|
+
def initialize(title: nil, read_only_hint: nil, destructive_hint: nil, idempotent_hint: nil, open_world_hint: nil)
|
9
|
+
@title = title
|
10
|
+
@read_only_hint = read_only_hint
|
11
|
+
@destructive_hint = destructive_hint
|
12
|
+
@idempotent_hint = idempotent_hint
|
13
|
+
@open_world_hint = open_world_hint
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_h
|
17
|
+
{
|
18
|
+
title:,
|
19
|
+
readOnlyHint: read_only_hint,
|
20
|
+
destructiveHint: destructive_hint,
|
21
|
+
idempotentHint: idempotent_hint,
|
22
|
+
openWorldHint: open_world_hint,
|
23
|
+
}.compact
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ModelContextProtocol
|
4
|
+
class Tool
|
5
|
+
class InputSchema
|
6
|
+
attr_reader :properties, :required
|
7
|
+
|
8
|
+
def initialize(properties: {}, required: [])
|
9
|
+
@properties = properties
|
10
|
+
@required = required.map(&:to_sym)
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_h
|
14
|
+
{ type: "object", properties:, required: }
|
15
|
+
end
|
16
|
+
|
17
|
+
def missing_required_arguments?(arguments)
|
18
|
+
missing_required_arguments(arguments).any?
|
19
|
+
end
|
20
|
+
|
21
|
+
def missing_required_arguments(arguments)
|
22
|
+
(required - arguments.keys.map(&:to_sym))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ModelContextProtocol
|
4
|
+
class Tool
|
5
|
+
class Response
|
6
|
+
attr_reader :content, :is_error
|
7
|
+
|
8
|
+
def initialize(content, is_error = false)
|
9
|
+
@content = content
|
10
|
+
@is_error = is_error
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_h
|
14
|
+
{ content:, isError: is_error }.compact
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ModelContextProtocol
|
4
|
+
class Tool
|
5
|
+
class << self
|
6
|
+
NOT_SET = Object.new
|
7
|
+
|
8
|
+
attr_reader :description_value
|
9
|
+
attr_reader :input_schema_value
|
10
|
+
attr_reader :annotations_value
|
11
|
+
|
12
|
+
def call(*args, server_context:)
|
13
|
+
raise NotImplementedError, "Subclasses must implement call"
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_h
|
17
|
+
result = {
|
18
|
+
name: name_value,
|
19
|
+
description: description_value,
|
20
|
+
inputSchema: input_schema_value.to_h,
|
21
|
+
}
|
22
|
+
result[:annotations] = annotations_value.to_h if annotations_value
|
23
|
+
result
|
24
|
+
end
|
25
|
+
|
26
|
+
def inherited(subclass)
|
27
|
+
super
|
28
|
+
subclass.instance_variable_set(:@name_value, nil)
|
29
|
+
subclass.instance_variable_set(:@description_value, nil)
|
30
|
+
subclass.instance_variable_set(:@input_schema_value, nil)
|
31
|
+
subclass.instance_variable_set(:@annotations_value, nil)
|
32
|
+
end
|
33
|
+
|
34
|
+
def tool_name(value = NOT_SET)
|
35
|
+
if value == NOT_SET
|
36
|
+
name_value
|
37
|
+
else
|
38
|
+
@name_value = value
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def name_value
|
43
|
+
@name_value || StringUtils.handle_from_class_name(name)
|
44
|
+
end
|
45
|
+
|
46
|
+
def description(value = NOT_SET)
|
47
|
+
if value == NOT_SET
|
48
|
+
@description_value
|
49
|
+
else
|
50
|
+
@description_value = value
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def input_schema(value = NOT_SET)
|
55
|
+
if value == NOT_SET
|
56
|
+
input_schema_value
|
57
|
+
elsif value.is_a?(Hash)
|
58
|
+
properties = value[:properties] || value["properties"] || {}
|
59
|
+
required = value[:required] || value["required"] || []
|
60
|
+
@input_schema_value = InputSchema.new(properties:, required:)
|
61
|
+
elsif value.is_a?(InputSchema)
|
62
|
+
@input_schema_value = value
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def annotations(hash = NOT_SET)
|
67
|
+
if hash == NOT_SET
|
68
|
+
@annotations_value
|
69
|
+
else
|
70
|
+
@annotations_value = Annotations.new(**hash)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def define(name: nil, description: nil, input_schema: nil, annotations: nil, &block)
|
75
|
+
Class.new(self) do
|
76
|
+
tool_name name
|
77
|
+
description description
|
78
|
+
input_schema input_schema
|
79
|
+
self.annotations(annotations) if annotations
|
80
|
+
define_singleton_method(:call, &block) if block
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ModelContextProtocol
|
4
|
+
class Transport
|
5
|
+
def initialize(server)
|
6
|
+
@server = server
|
7
|
+
end
|
8
|
+
|
9
|
+
def send_response(response)
|
10
|
+
raise NotImplementedError, "Subclasses must implement send_response"
|
11
|
+
end
|
12
|
+
|
13
|
+
def open
|
14
|
+
raise NotImplementedError, "Subclasses must implement open"
|
15
|
+
end
|
16
|
+
|
17
|
+
def close
|
18
|
+
raise NotImplementedError, "Subclasses must implement close"
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def handle_request(request)
|
24
|
+
response = @server.handle(request)
|
25
|
+
send_response(response) if response
|
26
|
+
end
|
27
|
+
|
28
|
+
def handle_json_request(request)
|
29
|
+
response = @server.handle_json(request)
|
30
|
+
send_response(response) if response
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../transport"
|
4
|
+
require "json"
|
5
|
+
|
6
|
+
module ModelContextProtocol
|
7
|
+
module Transports
|
8
|
+
class StdioTransport < Transport
|
9
|
+
def initialize(server)
|
10
|
+
@server = server
|
11
|
+
@open = false
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def open
|
16
|
+
@open = true
|
17
|
+
while @open && (line = $stdin.gets)
|
18
|
+
handle_json_request(line.strip)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def close
|
23
|
+
@open = false
|
24
|
+
end
|
25
|
+
|
26
|
+
def send_response(message)
|
27
|
+
json_message = message.is_a?(String) ? message : JSON.generate(message)
|
28
|
+
$stdout.puts(json_message)
|
29
|
+
$stdout.flush
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "model_context_protocol/server"
|
5
|
+
require "model_context_protocol/string_utils"
|
6
|
+
require "model_context_protocol/tool"
|
7
|
+
require "model_context_protocol/tool/input_schema"
|
8
|
+
require "model_context_protocol/tool/annotations"
|
9
|
+
require "model_context_protocol/tool/response"
|
10
|
+
require "model_context_protocol/content"
|
11
|
+
require "model_context_protocol/resource"
|
12
|
+
require "model_context_protocol/resource/contents"
|
13
|
+
require "model_context_protocol/resource/embedded"
|
14
|
+
require "model_context_protocol/resource_template"
|
15
|
+
require "model_context_protocol/prompt"
|
16
|
+
require "model_context_protocol/prompt/argument"
|
17
|
+
require "model_context_protocol/prompt/message"
|
18
|
+
require "model_context_protocol/prompt/result"
|
19
|
+
require "model_context_protocol/version"
|
20
|
+
require "model_context_protocol/configuration"
|
21
|
+
require "model_context_protocol/methods"
|
22
|
+
|
23
|
+
module ModelContextProtocol
|
24
|
+
class << self
|
25
|
+
def configure
|
26
|
+
yield(configuration)
|
27
|
+
end
|
28
|
+
|
29
|
+
def configuration
|
30
|
+
@configuration ||= Configuration.new
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Annotations
|
35
|
+
attr_reader :audience, :priority
|
36
|
+
|
37
|
+
def initialize(audience: nil, priority: nil)
|
38
|
+
@audience = audience
|
39
|
+
@priority = priority
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
MCP = ModelContextProtocol
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/model_context_protocol/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "model_context_protocol_riccardo"
|
7
|
+
spec.version = ModelContextProtocol::VERSION
|
8
|
+
spec.authors = ["Model Context Protocol"]
|
9
|
+
spec.email = ["mcp-support@anthropic.com"]
|
10
|
+
|
11
|
+
spec.summary = "The official Ruby SDK for Model Context Protocol servers and clients"
|
12
|
+
spec.description = spec.summary
|
13
|
+
spec.homepage = "https://github.com/modelcontextprotocol/ruby-sdk"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.required_ruby_version = ">= 3.2.0"
|
17
|
+
|
18
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
19
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
20
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
21
|
+
|
22
|
+
spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
|
23
|
+
%x(git ls-files -z).split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
24
|
+
end
|
25
|
+
|
26
|
+
spec.bindir = "exe"
|
27
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
|
+
spec.require_paths = ["lib"]
|
29
|
+
|
30
|
+
spec.add_dependency("json_rpc_handler", "~> 0.1")
|
31
|
+
spec.add_development_dependency("activesupport")
|
32
|
+
end
|