The search and execute MCP tools, as definitions and handlers.
tama-dex runs no MCP server and doesn't depend on one. A host's server
advertises two tools built from search_tool/0 and execute_tool/0, and
calls handle_search/3 and handle_execute/4 from them. Each definition
is a map with name, title, description, input_schema and
output_schema (JSON Schema 2020-12 maps with string keys) and
annotations (MCP tool hints).
Callers
A caller is any map or struct whose scopes field holds the caller's
verified scope list, such as TamaMCP.Context. The handlers check every
operation against those scopes, so a host's own scope on the search or
execute tool is only an outer gate, never per-operation authorization.
handle_execute/4 passes the whole caller to the executor as
call.context.
Responses
Handlers return JSON-safe maps with string keys, matching the tool's output schema, for the host to send as structured content:
search:%{"results" => results, "truncated" => boolean}.execute:%{"cassette", "operation_id", "source", "result"}; or, for the executor's own valid error,%{"cassette", "operation_id", "source", "operation_error", "dispatched" => true}.- Either tool, on failure:
%{"error" => %{"kind", "dispatched", "message"}}, with"details"when the kind has any. SeeTama.Dex.Errorfor the kindsexecutereturns. Arguments that don't match the tool's input schema give"invalid_arguments"before any lookup.
An error with "dispatched" => true means the operation may have taken
effect: reconcile its state rather than retrying.
A TamaMCP host
TamaMCP.Tool takes literal schemas, so a host builds its two tool
modules with a macro that injects the definitions at compile time:
defmodule MyHost.DexTool do
defmacro __using__(opts) do
tool = apply(Tama.Dex.MCP, Keyword.fetch!(opts, :tool), [])
quote do
use TamaMCP.Tool,
scopes: unquote(Keyword.fetch!(opts, :scopes)),
title: unquote(tool.title),
description: unquote(tool.description),
annotations: unquote(Map.to_list(tool.annotations))
raw_input_schema(unquote(Macro.escape(tool.input_schema)))
raw_output_schema(unquote(Macro.escape(tool.output_schema)))
end
end
def respond(structured) do
failed? = Map.has_key?(structured, "error") or Map.has_key?(structured, "operation_error")
build = if failed?, do: &TamaMCP.Response.tool_error/1, else: &TamaMCP.Response.success/1
{:ok,
build.(
structured_content: structured,
content: [TamaMCP.Response.text(Jason.encode!(structured))]
)}
end
end
defmodule MyHost.Tools.Search do
use MyHost.DexTool, tool: :search_tool, scopes: ["ops.search"]
@impl TamaMCP.Tool
def call(arguments, context) do
MyHost.Dex
|> Tama.Dex.MCP.handle_search(arguments, context)
|> MyHost.DexTool.respond()
end
end
defmodule MyHost.Tools.Execute do
use MyHost.DexTool, tool: :execute_tool, scopes: ["ops.execute"]
@impl TamaMCP.Tool
def call(arguments, context) do
MyHost.Dex
|> Tama.Dex.MCP.handle_execute(arguments, context, MyHost.executors())
|> MyHost.DexTool.respond()
end
endThe server registers them as tool MyHost.Tools.Search, name: "search" and
tool MyHost.Tools.Execute, name: "execute".
Summary
Functions
The execute tool definition.
Handles an execute tool call: runs Tama.Dex.execute/5 with the
caller's scopes, the host's executors (see Tama.Dex.Executor) and the
caller as call.context.
Handles a search tool call: searches the operations the caller's scopes
allow, using the tool's arguments.
The search tool definition.
Types
Functions
@spec execute_tool() :: definition()
The execute tool definition.
@spec handle_execute(Tama.Dex.Index.t(), term(), caller(), map()) :: map()
Handles an execute tool call: runs Tama.Dex.execute/5 with the
caller's scopes, the host's executors (see Tama.Dex.Executor) and the
caller as call.context.
Returns the result, the executor's own valid error with
"dispatched" => true, or an "error" object. Raises ArgumentError
when caller has no scopes list or executors isn't a map.
@spec handle_search(Tama.Dex.Index.t(), term(), caller()) :: map()
Handles a search tool call: searches the operations the caller's scopes
allow, using the tool's arguments.
Returns %{"results" => results, "truncated" => boolean}, with the result
fields of Tama.Dex.search/3, or an "error" object. Raises
ArgumentError when caller has no scopes list.
@spec search_tool() :: definition()
The search tool definition.