hub_kernel-mcp 0.1.0 → 0.3.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: 3113f06c6af7ead9f6321fdb00d2518557f17d03fbc79f3684260c2e146b641e
4
- data.tar.gz: aaa88888cd32c9ea2e28e731c968596d27ce27360c5b4725cb6020c7146de1ba
3
+ metadata.gz: 921598b05d30bf9e211477dbc575f7e59a8cde2487bdaa935e13242c7a80b5e7
4
+ data.tar.gz: d3e4111ecee2b448bee1120f7f9653b06c31bfd50d6a5143d622626fe42e7cc5
5
5
  SHA512:
6
- metadata.gz: facf0d8f1a0d4f9f68ee8f21ee33623dcbcda13fa9d3905337c898b047e0b8f67c16aab0374d6254135b15413e6de2b2efb1b6e972a3c2b2212790196d47ca69
7
- data.tar.gz: ba377f8a885f55972913d953daf6c766609880298cba383e2507ebcfdd564c538ed6d13c669edfa4cdb7540f620b1326e40106d35d7e773912af37a8d039ca00
6
+ metadata.gz: eeb8295b220d5cdc288ba99e991eeced8e0e5be262d7052a95715a4703e886ddb5db31f2369234a093fd2858ff08e89a2910a388c531121710058f09fbd83612
7
+ data.tar.gz: 73f9ce82ab316a2dbf92b912ba0676f871d311975b4f297c7cdb8a0e263c722c954c53705a23a779038494e7a1b2e48a1ffea254389c6ff2f64c0c8e1e624446
data/README.md CHANGED
@@ -40,9 +40,29 @@ Each tool is named `<hub>__<method>`, where the hub part is the name the hub is
40
40
  its input schema names the values the method takes:
41
41
 
42
42
  ```json
43
- { "name": "supplies__price_of", "inputSchema": { "type": "object", "properties": { "item": {} } } }
43
+ {
44
+ "name": "supplies__price_of",
45
+ "description": "Reads data from the supplies hub.",
46
+ "inputSchema": { "type": "object", "properties": { "item": {} } },
47
+ "annotations": { "readOnlyHint": true }
48
+ }
44
49
  ```
45
50
 
51
+ A tool for a method that writes has `readOnlyHint` set to false and a description saying it
52
+ changes data, so a client can ask before it calls one.
53
+
54
+ `tools/call` runs the hub method a tool names, for the person and account the host's methods
55
+ give, and returns the method's answer as JSON text:
56
+
57
+ ```json
58
+ { "content": [ { "type": "text", "text": "\"soap costs 3\"" } ], "isError": false }
59
+ ```
60
+
61
+ A hub's refusal, or a value the method requires and the call left out, comes back as a tool
62
+ error carrying the reason, with `isError` set. A tool the caller may not call, a tool that does
63
+ not exist, and a tool naming a hub the host does not serve are all answered with the same
64
+ JSON-RPC error, code -32602, `Unknown tool: <name>`.
65
+
46
66
  A caller the host's sign-in refuses is refused before any hub is asked.
47
67
 
48
68
  ## Installation
@@ -1,12 +1,16 @@
1
1
  module HubKernel
2
2
  module Mcp
3
3
  class MessagesController < HubKernel::Mcp.base_controller.constantize
4
+ UnknownTool = Class.new(StandardError)
5
+
4
6
  PROTOCOL_VERSIONS = %w[2025-11-25 2025-06-18 2025-03-26 2024-11-05].freeze
5
7
 
6
8
  def create
7
9
  return head :accepted unless params.key?(:id)
8
10
 
9
11
  render json: { jsonrpc: "2.0", id: params[:id], result: answer }
12
+ rescue UnknownTool, HubKernel::UnexposedMethodError, HubKernel::NotAllowed
13
+ render json: { jsonrpc: "2.0", id: params[:id], error: { code: -32602, message: "Unknown tool: #{tool_name}" } }
10
14
  end
11
15
 
12
16
  private
@@ -15,6 +19,7 @@ module HubKernel
15
19
  case params[:method]
16
20
  when "initialize" then initialized
17
21
  when "tools/list" then { tools: tools }
22
+ when "tools/call" then called
18
23
  end
19
24
  end
20
25
 
@@ -28,7 +33,22 @@ module HubKernel
28
33
  end
29
34
  end
30
35
 
31
- 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
+
38
+ def called
39
+ served_name, method_name = tool_name.split("__", 2)
40
+ hub = HubKernel::Interface.find(served_name) || raise(UnknownTool)
41
+ answer = hub.call_exposed(method_name, values: arguments, person: caller_person, account: caller_account)
42
+ { content: [ { type: "text", text: answer.to_json } ], isError: false }
43
+ rescue HubKernel::Refused, HubKernel::MissingArgumentError => refusal
44
+ { content: [ { type: "text", text: refusal.message } ], isError: true }
45
+ end
46
+
47
+ def tool_name = params.dig(:params, :name).to_s
48
+
49
+ def arguments = params.dig(:params, :arguments)&.to_unsafe_h.to_h.deep_symbolize_keys
50
+
51
+ def description(served_name, exposure) = exposure.writes ? "Changes data in the #{served_name} hub." : "Reads data from the #{served_name} hub."
32
52
 
33
53
  def caller_person = send(HubKernel::Mcp.person_method)
34
54
 
@@ -1,5 +1,5 @@
1
1
  module HubKernel
2
2
  module Mcp
3
- VERSION = "0.1.0"
3
+ VERSION = "0.3.0"
4
4
  end
5
5
  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.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - tylercschneider