Class: Woods::Console::DispatchPipeline
- Inherits:
-
Object
- Object
- Woods::Console::DispatchPipeline
- Defined in:
- lib/woods/console/dispatch_pipeline.rb
Overview
Per-tool dispatch flow for the Console MCP server.
Encapsulates everything that happens between MCP’s ‘define_tool` block firing and the `MCP::Tool::Response` returning to the client:
1. Coerce integer-typed args from strings. MCP clients sometimes send
`"10"` for an `integer` property — we normalize before dispatch.
2. Run the Layer 1 table gate ({ResponseContext#enforce!}).
3. Translate the tool args into a bridge/executor request via the
handler proc supplied in the {ToolSpec}.
4. Send the request through the connection manager / embedded executor.
5. Apply Layer 3 column + EAV redaction to the result
({ResponseContext#redact}).
6. Apply Layer 2 credential scanning to the result and/or error text
({ResponseContext#scan}), logging hit counts when any fire.
7. Render the result via the optional renderer or JSON, wrap in a
response object.
Previously this flow lived inline in ‘Server.register` with four `method(:…)` captures closing over module-level methods. Pulling it into a first-class object collapses that wiring, removes the need for the captures, and makes the pipeline directly testable without going through the full server build path.
Instance Method Summary collapse
-
#call(args) ⇒ MCP::Tool::Response
Run the full dispatch pipeline for a single tool call.
-
#initialize(tool_name:, handler:, integer_keys:, conn_mgr:, ctx: NullResponseContext.instance, renderer: nil, logger: nil) ⇒ DispatchPipeline
constructor
A new instance of DispatchPipeline.
Constructor Details
#initialize(tool_name:, handler:, integer_keys:, conn_mgr:, ctx: NullResponseContext.instance, renderer: nil, logger: nil) ⇒ DispatchPipeline
Returns a new instance of DispatchPipeline.
43 44 45 46 47 48 49 50 51 52 |
# File 'lib/woods/console/dispatch_pipeline.rb', line 43 def initialize(tool_name:, handler:, integer_keys:, conn_mgr:, # rubocop:disable Metrics/ParameterLists ctx: NullResponseContext.instance, renderer: nil, logger: nil) @tool_name = tool_name @handler = handler @integer_keys = integer_keys @conn_mgr = conn_mgr @ctx = ctx @renderer = renderer @logger = logger end |
Instance Method Details
#call(args) ⇒ MCP::Tool::Response
Run the full dispatch pipeline for a single tool call.
58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/woods/console/dispatch_pipeline.rb', line 58 def call(args) coerce_integer_args!(args) @ctx.enforce!(args) request = @handler.call(args).transform_keys(&:to_s) send_to_bridge(request) rescue TableGateError => e log_table_gate_rejection(args, e) error_response(e.) rescue SqlValidationError, ForbiddenExpressionError => e error_response(e.) end |