active_mcp 0.10.8 → 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 +33 -114
- data/app/controllers/concerns/active_mcp/request_handlable.rb +2 -2
- data/app/controllers/concerns/active_mcp/resource_readable.rb +3 -3
- data/app/controllers/concerns/active_mcp/tool_executable.rb +7 -5
- data/app/views/active_mcp/prompts_get.json.jbuilder +2 -2
- data/app/views/active_mcp/prompts_list.json.jbuilder +3 -3
- data/app/views/active_mcp/resource_templates_list.json.jbuilder +5 -5
- data/app/views/active_mcp/resources_list.json.jbuilder +1 -1
- data/app/views/active_mcp/tools_list.json.jbuilder +3 -3
- data/lib/active_mcp/completion.rb +1 -1
- data/lib/active_mcp/message/resource.rb +1 -1
- data/lib/active_mcp/prompt/base.rb +9 -7
- data/lib/active_mcp/resource/base.rb +13 -3
- data/lib/active_mcp/schema/base.rb +28 -19
- data/lib/active_mcp/server.rb +1 -1
- data/lib/active_mcp/tool/base.rb +18 -16
- data/lib/active_mcp/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dfbed9e2449de9de95e9c207351c157ebb8c4bf3c3e8483ca3c2083f4222d003
|
4
|
+
data.tar.gz: a29ac4be0a08aff010bead8ad35f46047ce698da651a709754b0ae8ec50f447c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9bcf5ed73689ac7ce9e6a83b375a5cbfb02f4b20d6c4eb0a653f27675f2bae4c12b3f37e05b62379ebf3b924fb14677f418577e4fe09c0c669ea057a36fad244
|
7
|
+
data.tar.gz: 05afff2d249672089f785232d26a9c0bc0235d600bdf4a807f4dac9bda66f52437f7f625b619f3ebf649876143525e24559b8db248ed7c51b796600f6f47036d
|
data/README.md
CHANGED
@@ -38,7 +38,6 @@ A Ruby on Rails engine for the [Model Context Protocol (MCP)](https://modelconte
|
|
38
38
|
- [Creating Resource Templates](#creating-resource-templates)
|
39
39
|
- [💬 MCP Prompts](#-mcp-prompts)
|
40
40
|
- [Creating Prompt](#creating-prompt)
|
41
|
-
- [📥 Using Context in the Schema](#-using-context-in-the-schema)
|
42
41
|
- [💡 Best Practices](#-best-practices)
|
43
42
|
- [1. Create Specific Tool Classes](#1-create-specific-tool-classes)
|
44
43
|
- [2. Validate and Sanitize Inputs](#2-validate-and-sanitize-inputs)
|
@@ -95,13 +94,9 @@ $ rails generate active_mcp:tool create_note
|
|
95
94
|
|
96
95
|
```ruby
|
97
96
|
class CreateNoteTool < ActiveMcp::Tool::Base
|
98
|
-
|
99
|
-
"create_note"
|
100
|
-
end
|
97
|
+
tool_name "create_note"
|
101
98
|
|
102
|
-
|
103
|
-
"Create Note"
|
104
|
-
end
|
99
|
+
description "Create Note"
|
105
100
|
|
106
101
|
argument :title, :string, required: true
|
107
102
|
argument :content, :string, required: true
|
@@ -118,11 +113,7 @@ end
|
|
118
113
|
|
119
114
|
```ruby
|
120
115
|
class MySchema < ActiveMcp::Schema::Base
|
121
|
-
|
122
|
-
[
|
123
|
-
CreateNoteTool.new
|
124
|
-
]
|
125
|
-
end
|
116
|
+
tools CreateNoteTool
|
126
117
|
end
|
127
118
|
```
|
128
119
|
|
@@ -223,13 +214,9 @@ MCP tools are Ruby classes that inherit from `ActiveMcp::Tool::Base` and define
|
|
223
214
|
|
224
215
|
```ruby
|
225
216
|
class SearchUsersTool < ActiveMcp::Tool::Base
|
226
|
-
|
227
|
-
"Search Users"
|
228
|
-
end
|
217
|
+
tool_name "Search Users"
|
229
218
|
|
230
|
-
|
231
|
-
'Search users by criteria'
|
232
|
-
end
|
219
|
+
description 'Search users by criteria'
|
233
220
|
|
234
221
|
argument :email, :string, required: false, description: 'Email to search for'
|
235
222
|
argument :name, :string, required: false, description: 'Name to search for'
|
@@ -278,18 +265,14 @@ Control access to tools by overriding the `visible?` class method:
|
|
278
265
|
|
279
266
|
```ruby
|
280
267
|
class AdminOnlyTool < ActiveMcp::Tool::Base
|
281
|
-
|
282
|
-
"admin_only_tool"
|
283
|
-
end
|
268
|
+
tool_name "admin_only_tool"
|
284
269
|
|
285
|
-
|
286
|
-
"Admin-only tool"
|
287
|
-
end
|
270
|
+
description "Admin-only tool"
|
288
271
|
|
289
272
|
argument :command, :string, required: true, description: "Admin command"
|
290
273
|
|
291
274
|
# Only allow admins to access this tool
|
292
|
-
def visible?(context:)
|
275
|
+
def self.visible?(context:)
|
293
276
|
return false unless context
|
294
277
|
return false unless context[:auth_info][:type] == :bearer
|
295
278
|
|
@@ -350,11 +333,7 @@ Resources are Ruby classes `**Resource`:
|
|
350
333
|
|
351
334
|
```ruby
|
352
335
|
class UserResource < ActiveMcp::Resource::Base
|
353
|
-
|
354
|
-
def mime_type
|
355
|
-
"application/json"
|
356
|
-
end
|
357
|
-
end
|
336
|
+
mime_type "application/json"
|
358
337
|
|
359
338
|
def initialize(id:)
|
360
339
|
@user = User.find(id)
|
@@ -372,7 +351,7 @@ class UserResource < ActiveMcp::Resource::Base
|
|
372
351
|
@user.profile
|
373
352
|
end
|
374
353
|
|
375
|
-
def visible?(context:)
|
354
|
+
def self.visible?(context:)
|
376
355
|
# Your logic...
|
377
356
|
end
|
378
357
|
|
@@ -390,10 +369,8 @@ end
|
|
390
369
|
|
391
370
|
```ruby
|
392
371
|
class MySchema < ActiveMcp::Schema::Base
|
393
|
-
|
394
|
-
|
395
|
-
UserResource.new(id: user.id)
|
396
|
-
end
|
372
|
+
resource UserResource, items: User.all.each do |user|
|
373
|
+
{ id: user.id }
|
397
374
|
end
|
398
375
|
end
|
399
376
|
```
|
@@ -415,11 +392,7 @@ end
|
|
415
392
|
|
416
393
|
```ruby
|
417
394
|
class ImageResource < ActiveMcp::Resource::Base
|
418
|
-
|
419
|
-
def mime_type
|
420
|
-
"image/png"
|
421
|
-
end
|
422
|
-
end
|
395
|
+
mime_type "image/png"
|
423
396
|
|
424
397
|
def resource_name
|
425
398
|
"profile_image"
|
@@ -462,32 +435,22 @@ Resource teamplates are Ruby classes `**Resource`:
|
|
462
435
|
|
463
436
|
```ruby
|
464
437
|
class UserResource < ActiveMcp::Resource::Base
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
end
|
473
|
-
|
474
|
-
def mime_type
|
475
|
-
"application/json"
|
476
|
-
end
|
477
|
-
|
478
|
-
def description
|
479
|
-
"This is a test."
|
480
|
-
end
|
481
|
-
|
482
|
-
def visible?(context:)
|
483
|
-
# Your logic...
|
484
|
-
end
|
485
|
-
end
|
438
|
+
resource_template_name "users"
|
439
|
+
|
440
|
+
uri_template "data://localhost/users/{id}"
|
441
|
+
|
442
|
+
mime_type "application/json"
|
443
|
+
|
444
|
+
description "This is a test."
|
486
445
|
|
487
446
|
argument :id, complete: ->(value, context) do
|
488
447
|
User.all.pluck(:id).filter { _1.match(value) }
|
489
448
|
end
|
490
449
|
|
450
|
+
def self.visible?(context:)
|
451
|
+
# Your logic...
|
452
|
+
end
|
453
|
+
|
491
454
|
def initialize(id:)
|
492
455
|
@user = User.find(id)
|
493
456
|
end
|
@@ -512,10 +475,8 @@ end
|
|
512
475
|
|
513
476
|
```ruby
|
514
477
|
class MySchema < ActiveMcp::Schema::Base
|
515
|
-
|
516
|
-
|
517
|
-
UserResource.new(id: user.id)
|
518
|
-
end
|
478
|
+
resource UserResource, items: User.all.each do |user|
|
479
|
+
{ id: user.id }
|
519
480
|
end
|
520
481
|
end
|
521
482
|
```
|
@@ -530,23 +491,15 @@ Resources are Ruby classes `**Prompt`:
|
|
530
491
|
|
531
492
|
```ruby
|
532
493
|
class HelloPrompt < ActiveMcp::Prompt::Base
|
533
|
-
|
534
|
-
User.all.pluck(:name).filter { _1.match(value) }
|
535
|
-
end
|
536
|
-
|
537
|
-
def initialize(greeting:)
|
538
|
-
@greeting = greeting
|
539
|
-
end
|
494
|
+
prompt_name "hello"
|
540
495
|
|
541
|
-
|
542
|
-
"hello"
|
543
|
-
end
|
496
|
+
description "This is a test."
|
544
497
|
|
545
|
-
|
546
|
-
|
498
|
+
argument :name, required: true, description: "User name", complete: ->(value, context) do
|
499
|
+
User.all.pluck(:name).filter { _1.match(value) }
|
547
500
|
end
|
548
501
|
|
549
|
-
def visible?(context:)
|
502
|
+
def self.visible?(context:)
|
550
503
|
# Your logic...
|
551
504
|
end
|
552
505
|
|
@@ -554,7 +507,7 @@ class HelloPrompt < ActiveMcp::Prompt::Base
|
|
554
507
|
[
|
555
508
|
ActiveMcp::Message::Text.new(
|
556
509
|
role: "user",
|
557
|
-
text: "
|
510
|
+
text: "Hello! #{name}"
|
558
511
|
),
|
559
512
|
ActiveMcp::Message::Image.new(
|
560
513
|
role: "assistant",
|
@@ -577,41 +530,7 @@ end
|
|
577
530
|
|
578
531
|
```ruby
|
579
532
|
class MySchema < ActiveMcp::Schema::Base
|
580
|
-
|
581
|
-
[
|
582
|
-
HelloPrompt.new(greeting: "Hello!")
|
583
|
-
]
|
584
|
-
end
|
585
|
-
end
|
586
|
-
```
|
587
|
-
|
588
|
-
## 📥 Using Context in the Schema
|
589
|
-
|
590
|
-
```ruby
|
591
|
-
class MySchema < ActiveMcp::Schema::Base
|
592
|
-
def prompts
|
593
|
-
user = User.find_by_token(context[:auth_info][:token])
|
594
|
-
|
595
|
-
user.greetings.map do |greeting|
|
596
|
-
GreetingPrompt.new(greeting: greeting)
|
597
|
-
end
|
598
|
-
end
|
599
|
-
end
|
600
|
-
```
|
601
|
-
|
602
|
-
```ruby
|
603
|
-
class GreetingPrompt < ActiveMcp::Prompt::Base
|
604
|
-
def initialize(greeting:)
|
605
|
-
@greeting = greeting
|
606
|
-
end
|
607
|
-
|
608
|
-
def prompt_name
|
609
|
-
"greeting_#{@greeting.text}"
|
610
|
-
end
|
611
|
-
|
612
|
-
def messages
|
613
|
-
# ...
|
614
|
-
end
|
533
|
+
prompt HelloPrompt
|
615
534
|
end
|
616
535
|
```
|
617
536
|
|
@@ -50,7 +50,7 @@ module ActiveMcp
|
|
50
50
|
@format = :jsonrpc
|
51
51
|
render "active_mcp/prompts_list", formats: :json
|
52
52
|
when Method::PROMPTS_GET
|
53
|
-
@prompt = schema.visible_prompts.find { _1.
|
53
|
+
@prompt = schema.visible_prompts.find { _1.prompt_name_value == params[:params][:name] }
|
54
54
|
@format = :jsonrpc
|
55
55
|
render "active_mcp/prompts_get", formats: :json
|
56
56
|
else
|
@@ -91,7 +91,7 @@ module ActiveMcp
|
|
91
91
|
@format = :json
|
92
92
|
render "active_mcp/prompts_list", formats: :json
|
93
93
|
when Method::PROMPTS_GET
|
94
|
-
@prompt = schema.visible_prompts&.find { _1.
|
94
|
+
@prompt = schema.visible_prompts&.find { _1.prompt_name_value == params[:params][:name] }
|
95
95
|
@format = :json
|
96
96
|
render "active_mcp/prompts_get", formats: :json
|
97
97
|
else
|
@@ -25,7 +25,7 @@ module ActiveMcp
|
|
25
25
|
}
|
26
26
|
end
|
27
27
|
|
28
|
-
if resource.respond_to?(:visible?) && !resource.visible?(context:)
|
28
|
+
if resource.class.respond_to?(:visible?) && !resource.class.visible?(context:)
|
29
29
|
return {
|
30
30
|
isError: true,
|
31
31
|
contents: []
|
@@ -38,7 +38,7 @@ module ActiveMcp
|
|
38
38
|
contents: [
|
39
39
|
{
|
40
40
|
uri:,
|
41
|
-
mimeType: resource.class.
|
41
|
+
mimeType: resource.class.mime_type_value,
|
42
42
|
text: content
|
43
43
|
}
|
44
44
|
]
|
@@ -48,7 +48,7 @@ module ActiveMcp
|
|
48
48
|
contents: [
|
49
49
|
{
|
50
50
|
uri:,
|
51
|
-
mimeType: resource.class.
|
51
|
+
mimeType: resource.class.mime_type_value,
|
52
52
|
blob: Base64.strict_encode64(content)
|
53
53
|
}
|
54
54
|
]
|
@@ -20,11 +20,11 @@ module ActiveMcp
|
|
20
20
|
}
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
tc.
|
23
|
+
tool_class = schema.visible_tools&.find do |tc|
|
24
|
+
tc.tool_name_value == tool_name
|
25
25
|
end
|
26
26
|
|
27
|
-
unless
|
27
|
+
unless tool_class
|
28
28
|
return {
|
29
29
|
isError: true,
|
30
30
|
content: [
|
@@ -36,7 +36,7 @@ module ActiveMcp
|
|
36
36
|
}
|
37
37
|
end
|
38
38
|
|
39
|
-
unless
|
39
|
+
unless tool_class.visible?(context:)
|
40
40
|
return {
|
41
41
|
isError: true,
|
42
42
|
content: [
|
@@ -64,7 +64,9 @@ module ActiveMcp
|
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
|
-
|
67
|
+
tool = tool_class.new
|
68
|
+
|
69
|
+
validation_result = tool.validate(arguments)
|
68
70
|
|
69
71
|
if validation_result.is_a?(Hash) && validation_result[:error]
|
70
72
|
return {
|
@@ -2,6 +2,6 @@ json.jsonrpc ActiveMcp::JSON_RPC_VERSION if @format == :jsonrpc
|
|
2
2
|
json.id @id if @format == :jsonrpc && @id.present?
|
3
3
|
|
4
4
|
json.result do
|
5
|
-
json.description @prompt.
|
6
|
-
json.messages @prompt.messages(**params[:params][:arguments].permit!.to_h.symbolize_keys).map(&:to_h)
|
5
|
+
json.description @prompt.description_value
|
6
|
+
json.messages @prompt.new.messages(**params[:params][:arguments].permit!.to_h.symbolize_keys).map(&:to_h)
|
7
7
|
end
|
@@ -4,9 +4,9 @@ json.id @id if @format == :jsonrpc && @id.present?
|
|
4
4
|
json.result do
|
5
5
|
json.prompts do
|
6
6
|
json.array!(@prompts) do |prompt|
|
7
|
-
json.name prompt.
|
8
|
-
json.description prompt.
|
9
|
-
json.arguments prompt.
|
7
|
+
json.name prompt.prompt_name_value
|
8
|
+
json.description prompt.description_value
|
9
|
+
json.arguments prompt.arguments ? prompt.arguments.map { _1.except(:complete) } : []
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
@@ -3,11 +3,11 @@ json.id @id if @format == :jsonrpc && @id.present?
|
|
3
3
|
|
4
4
|
json.result do
|
5
5
|
json.resourceTemplates do
|
6
|
-
json.array!(@resource_templates) do |
|
7
|
-
json.name
|
8
|
-
json.uriTemplate
|
9
|
-
json.mimeType
|
10
|
-
json.description
|
6
|
+
json.array!(@resource_templates) do |template|
|
7
|
+
json.name template.resource_template_name_value
|
8
|
+
json.uriTemplate template.uri_template_value
|
9
|
+
json.mimeType template.mime_type_value
|
10
|
+
json.description template.description_value
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
@@ -4,9 +4,9 @@ json.id @id if @format == :jsonrpc && @id.present?
|
|
4
4
|
json.result do
|
5
5
|
json.tools do
|
6
6
|
json.array!(@tools) do |tool|
|
7
|
-
json.name tool.
|
8
|
-
json.description tool.
|
9
|
-
json.inputSchema tool.
|
7
|
+
json.name tool.tool_name_value
|
8
|
+
json.description tool.description_value
|
9
|
+
json.inputSchema tool.schema
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
@@ -7,7 +7,7 @@ module ActiveMcp
|
|
7
7
|
value = params.dig(:argument, :value)
|
8
8
|
|
9
9
|
if uri_template
|
10
|
-
resource_class = refs.find { _1.
|
10
|
+
resource_class = refs.find { _1.uri_template_value == uri_template }
|
11
11
|
values = resource_class.arguments[arg_name.to_sym].call(value, context)
|
12
12
|
{values:, total: values.length}
|
13
13
|
elsif ref_name
|
@@ -2,7 +2,15 @@ module ActiveMcp
|
|
2
2
|
module Prompt
|
3
3
|
class Base
|
4
4
|
class << self
|
5
|
-
attr_reader :arguments
|
5
|
+
attr_reader :prompt_name_value, :description_value, :arguments
|
6
|
+
|
7
|
+
def prompt_name(value)
|
8
|
+
@prompt_name_value = value
|
9
|
+
end
|
10
|
+
|
11
|
+
def description(value)
|
12
|
+
@description_value = value
|
13
|
+
end
|
6
14
|
|
7
15
|
def argument(name, required: false, description: "", complete: -> {})
|
8
16
|
@arguments ||= []
|
@@ -19,12 +27,6 @@ module ActiveMcp
|
|
19
27
|
def initialize(*args, context: {})
|
20
28
|
end
|
21
29
|
|
22
|
-
def prompt_name
|
23
|
-
end
|
24
|
-
|
25
|
-
def description
|
26
|
-
end
|
27
|
-
|
28
30
|
def visible?(context: {})
|
29
31
|
true
|
30
32
|
end
|
@@ -4,12 +4,22 @@ module ActiveMcp
|
|
4
4
|
module Resource
|
5
5
|
class Base
|
6
6
|
class << self
|
7
|
-
attr_reader :schema, :arguments
|
7
|
+
attr_reader :resource_template_name_value, :description_value, :mime_type_value, :uri_template_value, :schema, :arguments
|
8
8
|
|
9
|
-
def
|
9
|
+
def resource_template_name(value)
|
10
|
+
@resource_template_name_value = value
|
10
11
|
end
|
11
12
|
|
12
|
-
def
|
13
|
+
def uri_template(value)
|
14
|
+
@uri_template_value = value
|
15
|
+
end
|
16
|
+
|
17
|
+
def description(value)
|
18
|
+
@description_value = value
|
19
|
+
end
|
20
|
+
|
21
|
+
def mime_type(value)
|
22
|
+
@mime_type_value = value
|
13
23
|
end
|
14
24
|
|
15
25
|
def argument(name, complete:)
|
@@ -1,46 +1,55 @@
|
|
1
1
|
module ActiveMcp
|
2
2
|
module Schema
|
3
3
|
class Base
|
4
|
-
|
4
|
+
class << self
|
5
|
+
attr_reader :tools, :resources, :prompts
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
7
|
+
def tool(value)
|
8
|
+
@tools ||= []
|
9
|
+
@tools << value
|
10
|
+
end
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
-
|
12
|
+
def resource(value, items: [])
|
13
|
+
@resources ||= []
|
14
|
+
@resources << {klass: value, items:}
|
15
|
+
end
|
13
16
|
|
14
|
-
|
15
|
-
|
17
|
+
def prompt(value)
|
18
|
+
@prompts ||= []
|
19
|
+
@prompts << value
|
20
|
+
end
|
16
21
|
end
|
17
22
|
|
18
|
-
def
|
19
|
-
|
23
|
+
def initialize(context: {})
|
24
|
+
@context = context
|
20
25
|
end
|
21
26
|
|
22
27
|
def visible_resources
|
23
|
-
resources&.filter do |resource|
|
24
|
-
!resource.respond_to?(:visible?) || resource.visible?(context: @context)
|
28
|
+
visibles = self.class.resources&.filter do |resource|
|
29
|
+
!resource[:klass].respond_to?(:visible?) || resource[:klass].visible?(context: @context)
|
25
30
|
end
|
31
|
+
visibles&.map do |resource|
|
32
|
+
resource[:items].map do |item|
|
33
|
+
resource[:klass].new(**item)
|
34
|
+
end
|
35
|
+
end&.flatten || []
|
26
36
|
end
|
27
37
|
|
28
38
|
def visible_resource_templates
|
29
|
-
|
30
|
-
resource.
|
39
|
+
visibles = self.class.resources&.filter do |resource|
|
40
|
+
resource[:klass].respond_to?(:uri_template) && (!resource[:klass].respond_to?(:visible?) || resource[:klass].visible?(context: @context))
|
31
41
|
end
|
32
|
-
|
33
|
-
resource_instances.map(&:class).uniq
|
42
|
+
visibles&.map { _1[:klass] } || []
|
34
43
|
end
|
35
44
|
|
36
45
|
def visible_tools
|
37
|
-
tools&.filter do |tool|
|
46
|
+
self.class.tools&.filter do |tool|
|
38
47
|
!tool.respond_to?(:visible?) || tool.visible?(context: @context)
|
39
48
|
end
|
40
49
|
end
|
41
50
|
|
42
51
|
def visible_prompts
|
43
|
-
prompts&.filter do |resource|
|
52
|
+
self.class.prompts&.filter do |resource|
|
44
53
|
!resource.respond_to?(:visible?) || resource.visible?(context: @context)
|
45
54
|
end
|
46
55
|
end
|
data/lib/active_mcp/server.rb
CHANGED
data/lib/active_mcp/tool/base.rb
CHANGED
@@ -4,7 +4,15 @@ module ActiveMcp
|
|
4
4
|
module Tool
|
5
5
|
class Base
|
6
6
|
class << self
|
7
|
-
attr_reader :schema
|
7
|
+
attr_reader :tool_name_value, :description_value, :schema
|
8
|
+
|
9
|
+
def tool_name(value)
|
10
|
+
@tool_name_value = value
|
11
|
+
end
|
12
|
+
|
13
|
+
def description(value)
|
14
|
+
@description_value = value
|
15
|
+
end
|
8
16
|
|
9
17
|
def argument(name, type, required: false, description: "")
|
10
18
|
@schema ||= default_schema
|
@@ -21,32 +29,26 @@ module ActiveMcp
|
|
21
29
|
"required" => []
|
22
30
|
}
|
23
31
|
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def initialize
|
27
|
-
end
|
28
|
-
|
29
|
-
def tool_name
|
30
|
-
end
|
31
32
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
def visible?(context: {})
|
36
|
-
true
|
33
|
+
def visible?(context: {})
|
34
|
+
true
|
35
|
+
end
|
37
36
|
end
|
38
37
|
|
39
|
-
def
|
40
|
-
raise NotImplementedError, "#{self.class.name}#call must be implemented"
|
38
|
+
def initialize
|
41
39
|
end
|
42
40
|
|
43
|
-
def
|
41
|
+
def validate(args)
|
44
42
|
return true unless self.class.schema
|
45
43
|
|
46
44
|
JSON::Validator.validate!(self.class.schema, args)
|
47
45
|
rescue JSON::Schema::ValidationError => e
|
48
46
|
{error: e.message}
|
49
47
|
end
|
48
|
+
|
49
|
+
def call(context: {}, **args)
|
50
|
+
raise NotImplementedError, "#{self.class.name}#call must be implemented"
|
51
|
+
end
|
50
52
|
end
|
51
53
|
end
|
52
54
|
end
|
data/lib/active_mcp/version.rb
CHANGED