Class: VectorMCP::Middleware::Anonymizer
- Inherits:
-
Object
- Object
- VectorMCP::Middleware::Anonymizer
- Defined in:
- lib/vector_mcp/middleware/anonymizer.rb
Overview
Middleware that rewrites selected string fields in outbound tool results into opaque tokens and restores them on inbound tool invocations. All domain knowledge (which keys to match, token prefixes, which keys to treat as atomic blobs) is supplied by the application via the constructor.
Instance Method Summary collapse
-
#after_tool_call(context) ⇒ Object
Middleware hook: tokenize matched fields in the tool result.
-
#before_tool_call(context) ⇒ Object
Middleware hook: rewrite tool arguments before the handler runs.
-
#initialize(store:, field_rules:, atomic_keys: nil) ⇒ Anonymizer
constructor
A new instance of Anonymizer.
-
#install_on(server, priority: Hook::DEFAULT_PRIORITY) ⇒ Class
Register this anonymizer instance on
serverfor the tool call lifecycle. -
#sweep_inbound(obj) ⇒ Object
Resolve tokens in an inbound payload back to their original values.
-
#sweep_outbound(obj) ⇒ Object
Tokenize sensitive string fields in an outbound payload.
Constructor Details
#initialize(store:, field_rules:, atomic_keys: nil) ⇒ Anonymizer
Returns a new instance of Anonymizer.
34 35 36 37 38 39 40 41 |
# File 'lib/vector_mcp/middleware/anonymizer.rb', line 34 def initialize(store:, field_rules:, atomic_keys: nil) raise ArgumentError, "store is required" if store.nil? raise ArgumentError, "field_rules is required" if field_rules.nil? @store = store @field_rules = field_rules.map { |rule| validate_rule!(rule) }.freeze @atomic_keys = atomic_keys end |
Instance Method Details
#after_tool_call(context) ⇒ Object
Middleware hook: tokenize matched fields in the tool result.
85 86 87 88 89 |
# File 'lib/vector_mcp/middleware/anonymizer.rb', line 85 def after_tool_call(context) return if context.result.nil? context.result = sweep_outbound(context.result) end |
#before_tool_call(context) ⇒ Object
Middleware hook: rewrite tool arguments before the handler runs.
74 75 76 77 78 79 80 81 |
# File 'lib/vector_mcp/middleware/anonymizer.rb', line 74 def before_tool_call(context) return unless context.params.is_a?(Hash) arguments = context.params["arguments"] return unless arguments.is_a?(Hash) || arguments.is_a?(Array) context.params = context.params.merge("arguments" => sweep_inbound(arguments)) end |
#install_on(server, priority: Hook::DEFAULT_PRIORITY) ⇒ Class
Register this anonymizer instance on server for the tool call lifecycle. Creates a thin adapter class so the middleware manager’s argumentless instantiation can still deliver the configured instance.
98 99 100 101 102 103 104 105 106 |
# File 'lib/vector_mcp/middleware/anonymizer.rb', line 98 def install_on(server, priority: Hook::DEFAULT_PRIORITY) instance = self adapter = Class.new(Base) do define_method(:before_tool_call) { |context| instance.before_tool_call(context) } define_method(:after_tool_call) { |context| instance.after_tool_call(context) } end server.use_middleware(adapter, %i[before_tool_call after_tool_call], priority: priority) adapter end |
#sweep_inbound(obj) ⇒ Object
Resolve tokens in an inbound payload back to their original values. Unknown token-shaped strings pass through unchanged.
61 62 63 64 65 66 67 68 69 70 |
# File 'lib/vector_mcp/middleware/anonymizer.rb', line 61 def sweep_inbound(obj) VectorMCP::Util::TokenSweeper.sweep(obj) do |value, _parent_key| if @store.token?(value) resolved = @store.resolve(value) resolved.nil? ? value : resolved else value end end end |
#sweep_outbound(obj) ⇒ Object
Tokenize sensitive string fields in an outbound payload.
47 48 49 50 51 52 53 54 |
# File 'lib/vector_mcp/middleware/anonymizer.rb', line 47 def sweep_outbound(obj) replace_atomic_nodes(obj).then do |shaped| VectorMCP::Util::TokenSweeper.sweep(shaped) do |value, parent_key| rule = rule_for(parent_key) rule ? @store.tokenize(value, prefix: rule[:prefix]) : value end end end |