toolchest 0.3.2 → 0.3.3
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/LLMS.txt +22 -1
- data/README.md +26 -0
- data/lib/toolchest/router.rb +4 -0
- data/lib/toolchest/tool_definition.rb +3 -2
- data/lib/toolchest/toolbox.rb +3 -2
- data/lib/toolchest/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: 545413528704477fdfc39328f3380e82b1f80c9be8096bc36fe201cddf90ce02
|
|
4
|
+
data.tar.gz: 4beea37ac5456c21b9b4ec41711643f5c1b2155669e2370badb2e03ad45c0b49
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 60ef42ecc96cecf2c0a9b9ea26cf786dc72ced48fafa1840cc56f53141657f9791fc2ec2446dc328f6463aaca9cc37564f9365e8a7c851b30256cdb8fb9e3669
|
|
7
|
+
data.tar.gz: a8ea33024b69f8154a78d7a4664afdbddc57e01b87c4daa5f01b64dc5a8d1191b44004d9fedd060a57a013bc87cc14f8c462be683d08d82d78708d16210d98e1
|
data/LLMS.txt
CHANGED
|
@@ -213,7 +213,12 @@ end
|
|
|
213
213
|
|
|
214
214
|
Types: `:string`, `:integer`, `:number`, `:boolean`, `:object`, `[:object]`, `[:string]`, etc.
|
|
215
215
|
|
|
216
|
-
Options on `tool`:
|
|
216
|
+
Options on `tool`:
|
|
217
|
+
|
|
218
|
+
- `name: "custom_tool_name"` — override generated tool name
|
|
219
|
+
- `access: :read` or `access: :write` — scope filtering + MCP annotations
|
|
220
|
+
- `scope: "admin"` or `scope: ["admin", "superuser"]` — per-tool scope override (see below)
|
|
221
|
+
- `annotations: { openWorldHint: true }` — override MCP hints
|
|
217
222
|
|
|
218
223
|
`access: :read` → `readOnlyHint: true, destructiveHint: false`. `access: :write` → `readOnlyHint: false, destructiveHint: true`.
|
|
219
224
|
|
|
@@ -345,6 +350,22 @@ Scopes filter `tools/list` — clients only see tools their token allows. Fails
|
|
|
345
350
|
|
|
346
351
|
Disable: `config.filter_tools_by_scope = false`
|
|
347
352
|
|
|
353
|
+
### Per-tool scope override
|
|
354
|
+
|
|
355
|
+
When a tool doesn't fit its toolbox's scope boundary, set `scope:` to bypass the convention:
|
|
356
|
+
|
|
357
|
+
```ruby
|
|
358
|
+
tool "Move ticket", scope: "admin" do # only "admin" scope grants access
|
|
359
|
+
param :status, :string, "New status"
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
tool "Escalate", scope: ["admin", "superuser"] do # either scope works (OR)
|
|
363
|
+
param :id, :string, "ID"
|
|
364
|
+
end
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
`scope:` replaces convention matching for that tool. `tickets:write` won't grant access to a tool with `scope: "admin"`. Enforced on both `tools/list` and `tools/call`.
|
|
368
|
+
|
|
348
369
|
### Optional scopes (checkboxes on consent)
|
|
349
370
|
|
|
350
371
|
```ruby
|
data/README.md
CHANGED
|
@@ -421,6 +421,32 @@ end
|
|
|
421
421
|
|
|
422
422
|
Turn it off: `config.filter_tools_by_scope = false`
|
|
423
423
|
|
|
424
|
+
### Per-tool scope override
|
|
425
|
+
|
|
426
|
+
The convention derives scopes from the toolbox name — `OrdersToolbox` tools require `orders:*`. When a tool doesn't fit its toolbox's scope boundary, override it:
|
|
427
|
+
|
|
428
|
+
```ruby
|
|
429
|
+
class TicketsToolbox < ApplicationToolbox
|
|
430
|
+
tool "List tickets" do
|
|
431
|
+
end
|
|
432
|
+
def list = # ... requires tickets:read (convention)
|
|
433
|
+
|
|
434
|
+
# Only tokens with the "admin" scope can see or call this tool
|
|
435
|
+
tool "Move ticket", scope: "admin" do
|
|
436
|
+
param :status, :string, "New status"
|
|
437
|
+
end
|
|
438
|
+
def move = # ...
|
|
439
|
+
|
|
440
|
+
# Either "admin" OR "superuser" grants access
|
|
441
|
+
tool "Escalate ticket", scope: ["admin", "superuser"] do
|
|
442
|
+
param :id, :string, "Ticket ID"
|
|
443
|
+
end
|
|
444
|
+
def escalate = # ...
|
|
445
|
+
end
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
`scope:` replaces the convention entirely for that tool — `tickets:write` won't grant access to a tool with `scope: "admin"`. The token must include the literal scope string. Enforced on both `tools/list` (visibility) and `tools/call` (execution).
|
|
449
|
+
|
|
424
450
|
### Optional scopes (checkboxes)
|
|
425
451
|
|
|
426
452
|
By default, the consent screen is all-or-nothing — approve all requested scopes or deny. Enable `optional_scopes` and users get checkboxes:
|
data/lib/toolchest/router.rb
CHANGED
|
@@ -219,6 +219,10 @@ module Toolchest
|
|
|
219
219
|
def tool_allowed_by_scopes?(tool_definition, scopes)
|
|
220
220
|
return true if scopes.empty?
|
|
221
221
|
|
|
222
|
+
if tool_definition.scope
|
|
223
|
+
return tool_definition.scope.any? { |s| scopes.include?(s) }
|
|
224
|
+
end
|
|
225
|
+
|
|
222
226
|
prefix = tool_definition.toolbox_class.controller_name.split("/").last
|
|
223
227
|
tool_access = tool_definition.access_level ||
|
|
224
228
|
(READ_ACTIONS.include?(tool_definition.method_name) ? :read : :write)
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
module Toolchest
|
|
2
2
|
class ToolDefinition
|
|
3
|
-
attr_reader :method_name, :description, :params, :toolbox_class, :custom_name, :access_level, :annotations
|
|
3
|
+
attr_reader :method_name, :description, :params, :toolbox_class, :custom_name, :access_level, :scope, :annotations
|
|
4
4
|
|
|
5
|
-
def initialize(method_name:, description:, params:, toolbox_class:, custom_name: nil, access_level: nil, annotations: nil)
|
|
5
|
+
def initialize(method_name:, description:, params:, toolbox_class:, custom_name: nil, access_level: nil, scope: nil, annotations: nil)
|
|
6
6
|
@method_name = method_name.to_sym
|
|
7
7
|
@description = description
|
|
8
8
|
@params = params
|
|
9
9
|
@toolbox_class = toolbox_class
|
|
10
10
|
@custom_name = custom_name
|
|
11
11
|
@access_level = access_level
|
|
12
|
+
@scope = scope ? Array(scope) : nil
|
|
12
13
|
@annotations = annotations
|
|
13
14
|
end
|
|
14
15
|
|
data/lib/toolchest/toolbox.rb
CHANGED
|
@@ -46,10 +46,10 @@ module Toolchest
|
|
|
46
46
|
.flat_map { |a| a.send(:own_prompts) }
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
def tool(description, name: nil, access: nil, annotations: nil, &block)
|
|
49
|
+
def tool(description, name: nil, access: nil, scope: nil, annotations: nil, &block)
|
|
50
50
|
builder = ToolBuilder.new
|
|
51
51
|
builder.instance_eval(&block) if block
|
|
52
|
-
@_pending_tool = { description
|
|
52
|
+
@_pending_tool = { description:, custom_name: name, access_level: access, scope:, annotations:, builder: }
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
def default_param(name, type, description = "", **options)
|
|
@@ -110,6 +110,7 @@ module Toolchest
|
|
|
110
110
|
toolbox_class: self,
|
|
111
111
|
custom_name: pending[:custom_name],
|
|
112
112
|
access_level: pending[:access_level],
|
|
113
|
+
scope: pending[:scope],
|
|
113
114
|
annotations: pending[:annotations]
|
|
114
115
|
)
|
|
115
116
|
|
data/lib/toolchest/version.rb
CHANGED