mcp_toolkit 0.4.0 → 0.5.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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +231 -0
  3. data/config/routes.rb +1 -1
  4. data/lib/mcp_toolkit/authority/controller_methods.rb +15 -0
  5. data/lib/mcp_toolkit/authority/registry_tool_provider.rb +9 -10
  6. data/lib/mcp_toolkit/authority/single_tool_provider.rb +25 -0
  7. data/lib/mcp_toolkit/authority/tools/base.rb +31 -3
  8. data/lib/mcp_toolkit/authority/tools/get.rb +2 -1
  9. data/lib/mcp_toolkit/authority/tools/list.rb +49 -1
  10. data/lib/mcp_toolkit/authority/tools/resource_schema.rb +10 -2
  11. data/lib/mcp_toolkit/authority/tools/resources.rb +26 -4
  12. data/lib/mcp_toolkit/configuration.rb +161 -7
  13. data/lib/mcp_toolkit/dispatcher.rb +17 -3
  14. data/lib/mcp_toolkit/engine.rb +5 -2
  15. data/lib/mcp_toolkit/engine_controllers.rb +11 -3
  16. data/lib/mcp_toolkit/filtering.rb +168 -23
  17. data/lib/mcp_toolkit/gateway/aggregator.rb +25 -5
  18. data/lib/mcp_toolkit/list_executor.rb +48 -4
  19. data/lib/mcp_toolkit/resource.rb +55 -6
  20. data/lib/mcp_toolkit/resource_schema.rb +125 -16
  21. data/lib/mcp_toolkit/serializer/association_descriptor.rb +11 -0
  22. data/lib/mcp_toolkit/serializer/target_ref.rb +7 -0
  23. data/lib/mcp_toolkit/session.rb +2 -2
  24. data/lib/mcp_toolkit/tool_reference_rewriter.rb +33 -0
  25. data/lib/mcp_toolkit/tools/authority_base.rb +23 -2
  26. data/lib/mcp_toolkit/tools/base.rb +23 -3
  27. data/lib/mcp_toolkit/tools/get.rb +1 -1
  28. data/lib/mcp_toolkit/tools/list.rb +27 -9
  29. data/lib/mcp_toolkit/tools/resource_schema.rb +12 -3
  30. data/lib/mcp_toolkit/tools/resources.rb +30 -7
  31. data/lib/mcp_toolkit/usage_metering/recorder.rb +28 -2
  32. data/lib/mcp_toolkit/version.rb +1 -1
  33. metadata +5 -1
@@ -5,9 +5,10 @@ class McpToolkit::Tools::Resources < McpToolkit::Tools::Base
5
5
  tool_name "resources"
6
6
  description <<~DESC.strip
7
7
  List all read-only resources available via the `list` and `get` tools. Returns each
8
- resource's name and a short description. Call this once at the start of a session to learn
9
- what exists, then use `resource_schema` for a specific resource's attributes and
10
- relationships.
8
+ resource's name, a short description, whether it accepts filters (`filterable`) and when
9
+ present a usage `note` (read it before interpreting the resource's data). Call this once
10
+ at the start of a session to learn what exists, then use `resource_schema` for a specific
11
+ resource's attributes, relationships and filters.
11
12
  DESC
12
13
 
13
14
  input_schema(properties: {})
@@ -16,12 +17,34 @@ class McpToolkit::Tools::Resources < McpToolkit::Tools::Base
16
17
  config = config_from(server_context)
17
18
  # Discovery requires the registry-level default scope (the satellite's
18
19
  # app-wide scope); per-resource scopes are enforced by `get` / `list`.
19
- with_authentication(server_context, required_scope: config.registry.default_required_permissions_scope) do
20
+ with_authentication(server_context,
21
+ required_scope: config.registry.default_required_permissions_scope) do |introspection|
20
22
  {
21
- resources: config.registry.resources.map do |resource|
22
- { name: resource.name, description: resource.description }
23
- end
23
+ resources: config.registry.resources
24
+ .reject { |resource| resource.superusers_only? && !introspection.superuser? }
25
+ .map do |resource|
26
+ {
27
+ name: resource.name,
28
+ description: resource.description,
29
+ filterable: filterable?(resource, config),
30
+ note: resource.note
31
+ }.compact
32
+ end
24
33
  }
25
34
  end
26
35
  end
36
+
37
+ # Whether the resource can be filtered at all — via the generic allowlist OR a
38
+ # resource-specific custom filter. Mirrors the authority-path resources tool:
39
+ # resolving a lazily-declared allowlist may run host code, and one resource's
40
+ # failing resolution must not take down the whole discovery index, so a raise
41
+ # degrades to nil (the key is omitted) and the source is retried on the next
42
+ # read (see Resource#filterable).
43
+ def self.filterable?(resource, config)
44
+ resource.filterable_columns.any? || resource.custom_filters.any?
45
+ rescue StandardError => e
46
+ config.logger&.warn("mcp_toolkit: filterable resolution failed for #{resource.name}: #{e.message}")
47
+ nil
48
+ end
49
+ private_class_method :filterable?
27
50
  end
@@ -65,18 +65,44 @@ class McpToolkit::UsageMetering::Recorder
65
65
  end
66
66
 
67
67
  # `config.usage_flusher` target. Persists the request's accumulated events via the
68
- # sink in one shot. No-op when nothing was accumulated.
68
+ # sink in one shot. No-op when nothing was accumulated. If the batch write fails,
69
+ # falls back to per-event writes so one un-persistable ("poison") event can't drop
70
+ # metering for the whole request.
69
71
  def flush(controller:)
70
72
  events = buffer_for(controller)
71
73
  return if events.empty?
72
74
 
73
75
  @sink.call(events)
74
76
  rescue StandardError => e
75
- report("failed to flush #{events&.size} event(s)", e)
77
+ flush_individually(events, e)
76
78
  end
77
79
 
78
80
  private
79
81
 
82
+ # The batch write failed. Retry each event on its own so a single un-persistable
83
+ # event (a constraint violation, bad encoding) loses ONLY itself instead of
84
+ # dropping every sibling call's metering — which a caller could otherwise
85
+ # exploit to evade billing for a whole batch by appending one poison call.
86
+ # Assumes the batch sink is atomic (nothing persisted on failure — true for
87
+ # `insert_all`); a non-atomic sink could double-write the events that did land,
88
+ # so this stays a fallback, not the default path.
89
+ def flush_individually(events, batch_error)
90
+ @logger&.warn(
91
+ "MCP usage tracking: batch flush of #{events.size} event(s) failed " \
92
+ "(#{batch_error.message}), retrying individually"
93
+ )
94
+ events.each do |event|
95
+ @sink.call([event])
96
+ rescue StandardError => e
97
+ report("dropped 1 unpersistable usage event", e)
98
+ end
99
+ rescue StandardError
100
+ # Metering MUST NEVER affect the MCP response. `flush` already runs this from
101
+ # its rescue, so a raise here (e.g. a misbehaving logger or error_reporter)
102
+ # would escape into the after_action. Swallow it as the last resort.
103
+ nil
104
+ end
105
+
80
106
  def scrub(arguments)
81
107
  hash = arguments.to_h
82
108
  @parameter_filter ? @parameter_filter.filter(hash) : hash
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module McpToolkit
4
- VERSION = "0.4.0"
4
+ VERSION = "0.5.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mcp_toolkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Karol Galanciak
@@ -109,6 +109,7 @@ files:
109
109
  - lib/mcp_toolkit/authority/context.rb
110
110
  - lib/mcp_toolkit/authority/controller_methods.rb
111
111
  - lib/mcp_toolkit/authority/registry_tool_provider.rb
112
+ - lib/mcp_toolkit/authority/single_tool_provider.rb
112
113
  - lib/mcp_toolkit/authority/token.rb
113
114
  - lib/mcp_toolkit/authority/tools/base.rb
114
115
  - lib/mcp_toolkit/authority/tools/get.rb
@@ -139,11 +140,14 @@ files:
139
140
  - lib/mcp_toolkit/resource.rb
140
141
  - lib/mcp_toolkit/resource_schema.rb
141
142
  - lib/mcp_toolkit/serialization.rb
143
+ - lib/mcp_toolkit/serializer/association_descriptor.rb
142
144
  - lib/mcp_toolkit/serializer/base.rb
145
+ - lib/mcp_toolkit/serializer/target_ref.rb
143
146
  - lib/mcp_toolkit/server.rb
144
147
  - lib/mcp_toolkit/session.rb
145
148
  - lib/mcp_toolkit/sql_sanitizer.rb
146
149
  - lib/mcp_toolkit/token_kinds.rb
150
+ - lib/mcp_toolkit/tool_reference_rewriter.rb
147
151
  - lib/mcp_toolkit/tools/authority_base.rb
148
152
  - lib/mcp_toolkit/tools/base.rb
149
153
  - lib/mcp_toolkit/tools/get.rb