Module: Textus::Surface::MCP::Catalog
- Defined in:
- lib/textus/surface/mcp/catalog.rb
Overview
Derives the entire MCP tool surface from the per-verb contracts (ADR 0039). ‘build_tools` builds MCP::Tool instances for the SDK; `call` is the generic dispatch: map JSON args -> (positional, keyword) per the contract, invoke the verb through the role scope, then shape the return value. No per-tool code.
Constant Summary collapse
- PROJECTOR =
Projector.new(view_key: :default, binder_method: :inputs_from_wire).freeze
- WRITE_VERBS =
%i[ put propose key_delete key_mv accept reject enqueue ].freeze
- MAINTENANCE_VERBS =
%i[ data_mv key_mv_prefix key_delete_prefix drain rule_lint ].freeze
Class Method Summary collapse
-
.build_tools(mcp_server) ⇒ Object
Builds MCP::Tool instances for the SDK, bound to mcp_server.dispatch.
- .call(name, session:, store:, args:) ⇒ Object
- .mcp_surfaced?(klass) ⇒ Boolean
- .names ⇒ Object
-
.read_verbs ⇒ Object
MCP-surfaced read verbs, by Dispatcher class namespace — the agent’s real read/discovery surface.
-
.specs ⇒ Object
Contracts of every MCP-surfaced verb, in Dispatcher order.
-
.write_verbs ⇒ Object
MCP-surfaced write verbs, by Dispatcher class namespace — the mirror of read_verbs for the write side.
Class Method Details
.build_tools(mcp_server) ⇒ Object
Builds MCP::Tool instances for the SDK, bound to mcp_server.dispatch.
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/textus/surface/mcp/catalog.rb', line 29 def build_tools(mcp_server) Textus::Action::VERBS .select { |_, klass| mcp_surfaced?(klass) } .map do |name, action| schema = action.contract.input_schema schema = schema.reject { |k, v| k == :required && Array(v).empty? } ::MCP::Tool.define( name: name.to_s, description: action.contract.summary, input_schema: schema, ) do |server_context:, **args| mcp_server.dispatch(name, args, server_context) end end end |
.call(name, session:, store:, args:) ⇒ Object
78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/textus/surface/mcp/catalog.rb', line 78 def call(name, session:, store:, args:) klass = Textus::Action::VERBS[name.to_sym] raise ToolError.new("unknown tool: #{name}") unless klass && mcp_surfaced?(klass) PROJECTOR.dispatch(name, inputs: args, store:, role: session.role, session:) rescue Textus::Gate::MissingArgs => e spec = klass.contract raise ToolError.new("#{spec.verb}: missing #{e.missing.map { |a| a.wire.to_s }.join(", ")}") rescue Textus::ContractDrift, CursorExpired raise rescue Textus::Error => e raise ToolError.new("#{name}: #{e.}") end |
.mcp_surfaced?(klass) ⇒ Boolean
74 75 76 |
# File 'lib/textus/surface/mcp/catalog.rb', line 74 def mcp_surfaced?(klass) klass.respond_to?(:contract?) && klass.contract? && klass.contract.mcp? end |
.names ⇒ Object
45 46 47 48 49 |
# File 'lib/textus/surface/mcp/catalog.rb', line 45 def names PROJECTOR.names( Textus::Action::VERBS.select { |_, klass| mcp_surfaced?(klass) }, ) end |
.read_verbs ⇒ Object
MCP-surfaced read verbs, by Dispatcher class namespace — the agent’s real read/discovery surface. ‘boot.agent_quickstart.read_verbs` derives from this so it can never advertise a verb the agent cannot call, nor omit one it can (ADR 0056). Excludes write/maintenance verbs by verb identity (routing may be legacy UseCases or Dispatch::Actions).
56 57 58 59 60 61 |
# File 'lib/textus/surface/mcp/catalog.rb', line 56 def read_verbs Textus::Action::VERBS .reject { |verb, _klass| WRITE_VERBS.include?(verb) || MAINTENANCE_VERBS.include?(verb) } .select { |_verb, klass| mcp_surfaced?(klass) } .keys.map(&:to_s) end |
.specs ⇒ Object
Contracts of every MCP-surfaced verb, in Dispatcher order.
22 23 24 25 26 |
# File 'lib/textus/surface/mcp/catalog.rb', line 22 def specs Textus::Action::VERBS.values .select { |k| mcp_surfaced?(k) } .map(&:contract) end |
.write_verbs ⇒ Object
MCP-surfaced write verbs, by Dispatcher class namespace — the mirror of read_verbs for the write side. ‘boot.agent_quickstart.write_verbs` derives from this so it advertises bare verb names the agent can call (no `–as`/ `–stdin` CLI framing), finishing the de-CLI-ing of the agent surface (ADR 0056, ADR 0057).
68 69 70 71 72 |
# File 'lib/textus/surface/mcp/catalog.rb', line 68 def write_verbs Textus::Action::VERBS .select { |verb, klass| WRITE_VERBS.include?(verb) && mcp_surfaced?(klass) } .keys.map(&:to_s) end |