hub_kernel-mcp 0.2.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fdf5562d9d62588f25ee064ae1571430d08a6ac2c452b957b1df4784f5c9cc1d
4
- data.tar.gz: e122d851e02746457f5f4232eb118f3a2cd21100fb1931827f5af939c234076e
3
+ metadata.gz: 363a48c785a072c9ba3c744969cb93de55d2514c0e68008873a9bb7312fd8fb0
4
+ data.tar.gz: c3f27a9e3a246c1742cd101415b286f7096dfeed8e52bb618e604b7e5127060b
5
5
  SHA512:
6
- metadata.gz: 120c5a8941826f02ceea5d9cf251d3ec30e0061f4282010526fd067da2f5b7fdfde270d90900842b58cefed05aafb9decf8acb52c49d05131eaf8ab0fe4a499d
7
- data.tar.gz: 9082038898f81950d9a26c9973bc8d05e5d6769485d43f20eea358df2d274a388012fb3a1cd24393b88c73a4fecb2d3330e68923ec296f6ec34f6b0d9860b97c
6
+ metadata.gz: 58097086aeed03bd87cb0d10ae8b554b2963823300f1d70f85f8efd7ddcaf5d195eaf2e397edf5cad03fc98966fa754fe0eb489251bc3e3c552178d50d5cc292
7
+ data.tar.gz: 581abee68889b126bb28291ad58329fab0b7d5c48e7bef6be0860a766105fde7afe633d5ca72e715defe35721268f7572dc4e35421b3050c6d2be752cbf6c2f4
data/README.md CHANGED
@@ -21,9 +21,16 @@ serves:
21
21
  ```ruby
22
22
  Rails.application.config.to_prepare do
23
23
  HubKernel::Interface.hubs = [ Supplies, { "money" => Billing::Ledger } ]
24
+ HubKernel::Mcp.check!
24
25
  end
25
26
  ```
26
27
 
28
+ `HubKernel::Mcp.check!` raises `HubKernel::Mcp::UnservableHubError` naming every problem
29
+ in one error. It names each problem hub_kernel-interface's own check finds in the served
30
+ list, a served name holding two underscores in a row, and a tool whose name holds a
31
+ character other than a letter, a digit, an underscore or a hyphen or is longer than 64
32
+ characters. Inside `to_prepare` it runs again after every code reload.
33
+
27
34
  Mount the engine:
28
35
 
29
36
  ```ruby
@@ -40,9 +47,17 @@ Each tool is named `<hub>__<method>`, where the hub part is the name the hub is
40
47
  its input schema names the values the method takes:
41
48
 
42
49
  ```json
43
- { "name": "supplies__price_of", "inputSchema": { "type": "object", "properties": { "item": {} } } }
50
+ {
51
+ "name": "supplies__price_of",
52
+ "description": "Reads data from the supplies hub.",
53
+ "inputSchema": { "type": "object", "properties": { "item": {} } },
54
+ "annotations": { "readOnlyHint": true }
55
+ }
44
56
  ```
45
57
 
58
+ A tool for a method that writes has `readOnlyHint` set to false and a description saying it
59
+ changes data, so a client can ask before it calls one.
60
+
46
61
  `tools/call` runs the hub method a tool names, for the person and account the host's methods
47
62
  give, and returns the method's answer as JSON text:
48
63
 
@@ -33,7 +33,7 @@ module HubKernel
33
33
  end
34
34
  end
35
35
 
36
- def tool(served_name, exposure) = { name: "#{served_name}__#{exposure.name}", inputSchema: { type: "object", properties: exposure.takes.index_with { {} } } }
36
+ def tool(served_name, exposure) = { name: "#{served_name}__#{exposure.name}", description: description(served_name, exposure), inputSchema: { type: "object", properties: exposure.takes.index_with { {} } }, annotations: { readOnlyHint: !exposure.writes } }
37
37
 
38
38
  def called
39
39
  served_name, method_name = tool_name.split("__", 2)
@@ -48,6 +48,8 @@ module HubKernel
48
48
 
49
49
  def arguments = params.dig(:params, :arguments)&.to_unsafe_h.to_h.deep_symbolize_keys
50
50
 
51
+ def description(served_name, exposure) = exposure.writes ? "Changes data in the #{served_name} hub." : "Reads data from the #{served_name} hub."
52
+
51
53
  def caller_person = send(HubKernel::Mcp.person_method)
52
54
 
53
55
  def caller_account = send(HubKernel::Mcp.account_method)
@@ -1,5 +1,5 @@
1
1
  module HubKernel
2
2
  module Mcp
3
- VERSION = "0.2.0"
3
+ VERSION = "0.4.0"
4
4
  end
5
5
  end
@@ -4,8 +4,46 @@ require "hub_kernel/mcp/engine"
4
4
 
5
5
  module HubKernel
6
6
  module Mcp
7
+ UnservableHubError = HubKernel::Interface::UnservableHubError
8
+
7
9
  mattr_accessor :base_controller, default: "ActionController::API"
8
10
  mattr_accessor :person_method
9
11
  mattr_accessor :account_method
12
+
13
+ def self.check!
14
+ problems = shared_problems + doubled_underscores + unlisted_characters + long_names
15
+ raise UnservableHubError, problems.join("\n") if problems.any?
16
+ end
17
+
18
+ def self.shared_problems
19
+ HubKernel::Interface.check!
20
+ []
21
+ rescue UnservableHubError => error
22
+ error.message.split("\n")
23
+ end
24
+
25
+ def self.doubled_underscores
26
+ HubKernel::Interface.served.select { |name, _hub| name.include?("__") }.map do |name, hub|
27
+ "#{hub.name} is served at #{name}, which holds two underscores in a row"
28
+ end
29
+ end
30
+
31
+ def self.unlisted_characters
32
+ tool_names.grep_v(/\A[A-Za-z0-9_-]*\z/).map do |name|
33
+ "The tool #{name} holds a character other than a letter, a digit, an underscore or a hyphen"
34
+ end
35
+ end
36
+
37
+ def self.long_names
38
+ tool_names.select { |name| name.length > 64 }.map { |name| "The tool #{name} is longer than 64 characters" }
39
+ end
40
+
41
+ def self.tool_names
42
+ HubKernel::Interface.served.select { |_name, hub| hub.respond_to?(:exposures) }.flat_map do |served_name, hub|
43
+ hub.exposures.map { |exposure| "#{served_name}__#{exposure.name}" }
44
+ end
45
+ end
46
+
47
+ private_class_method :shared_problems, :doubled_underscores, :unlisted_characters, :long_names, :tool_names
10
48
  end
11
49
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hub_kernel-mcp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - tylercschneider
@@ -29,14 +29,14 @@ dependencies:
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '0.3'
32
+ version: '0.6'
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '0.3'
39
+ version: '0.6'
40
40
  description: hub_kernel-mcp serves the methods every hub a host serves exposes as
41
41
  MCP tools at one address, with every call going through the host's sign-in, permission
42
42
  check and account scope.