Module: Textus::MCP::Catalog
- Defined in:
- lib/textus/mcp/catalog.rb
Overview
Derives the entire MCP tool surface from the per-verb contracts (ADR 0039). ‘tool_schemas` feeds tools/list; `call` is the generic tools/call dispatch: map JSON args -> (positional, keyword) per the contract, invoke the verb through the role scope, then shape the return value with the contract’s default view. No per-tool code.
Class Method Summary collapse
- .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.
- .tool_schemas ⇒ Object
-
.write_verbs ⇒ Object
MCP-surfaced write verbs, by Dispatcher class namespace — the mirror of read_verbs for the write side.
Class Method Details
.call(name, session:, store:, args:) ⇒ Object
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/textus/mcp/catalog.rb', line 53 def call(name, session:, store:, args:) klass = Textus::Dispatcher::VERBS[name.to_sym] raise ToolError.new("unknown tool: #{name}") unless klass && mcp_surfaced?(klass) spec = klass.contract inputs = Textus::Contract::Binder.inputs_from_wire(spec, args) result = store.as(session.role).dispatch_bound(spec.verb, inputs, session: session) Textus::Contract::View.render(spec, :default, result, inputs) rescue Textus::Contract::MissingArgs => e raise ToolError.new("#{spec.verb}: missing #{e.missing.map { |a| a.wire.to_s }.join(", ")}") rescue ContractDrift, CursorExpired raise rescue Textus::Error => e raise ToolError.new("#{name}: #{e.}") end |
.mcp_surfaced?(klass) ⇒ Boolean
49 50 51 |
# File 'lib/textus/mcp/catalog.rb', line 49 def mcp_surfaced?(klass) klass.respond_to?(:contract?) && klass.contract? && klass.contract.mcp? end |
.names ⇒ Object
24 25 26 |
# File 'lib/textus/mcp/catalog.rb', line 24 def names specs.map { |s| s.verb.to_s } 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.
32 33 34 35 36 |
# File 'lib/textus/mcp/catalog.rb', line 32 def read_verbs Textus::Dispatcher::VERBS .select { |_verb, klass| mcp_surfaced?(klass) && klass.name.start_with?("Textus::Read::") } .keys.map(&:to_s) end |
.specs ⇒ Object
Contracts of every MCP-surfaced verb, in Dispatcher order.
12 13 14 15 16 |
# File 'lib/textus/mcp/catalog.rb', line 12 def specs Textus::Dispatcher::VERBS.values .select { |k| mcp_surfaced?(k) } .map(&:contract) end |
.tool_schemas ⇒ Object
18 19 20 21 22 |
# File 'lib/textus/mcp/catalog.rb', line 18 def tool_schemas specs.map do |s| { name: s.verb.to_s, description: s.summary, inputSchema: s.input_schema } end.freeze 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).
43 44 45 46 47 |
# File 'lib/textus/mcp/catalog.rb', line 43 def write_verbs Textus::Dispatcher::VERBS .select { |_verb, klass| mcp_surfaced?(klass) && klass.name.start_with?("Textus::Write::") } .keys.map(&:to_s) end |