Wymcp. Tool. Schema
(Wymcp v0.9.1)
View Source
Builds the JSON Schema inputSchema for Wymcp tools.
One shape: the action field lists the declared action names as an enum
whose description carries the action summaries, one per line, and data is
a bare object. build/1 and action_summaries/1 render those summaries
from one private function, so the enum description and the help index
cannot drift. The newline separator stays
unambiguous because Wymcp.Tool.Actions.fetch_validated!/1 — run at every moment
a tool's schemas are validated — rejects a newline in an action's name or
its description, the two halves a summary joins. Wymcp.Tool's generated
input_schema/0 is the only caller of build/1.
Both documented functions take the tool module, not an actions map,
and obtain the schemas themselves through
Wymcp.Tool.Actions.fetch_schemas!/1. Each obtains once and hands the map
on: obtaining twice on one path could publish an action enum that
disagrees with its own summaries, for a tool whose
Wymcp.Tool.actions/0 varies between calls.
One function takes a map instead, and is kept out of these docs because
only the registration moment calls it: build_from_actions builds the
schema from the actions map Wymcp.Tool.Actions.fetch_validated!/1 has
just validated, so a macro tool's definition is built without obtaining
its actions a second time. build/1, which the generated input_schema/0
calls, is the same build over a fresh obtain. So every map this module
reads has been through a validator — a documented function's through the
obtaining accessor, build_from_actions' through its one caller,
Wymcp.Tool — and the direct schema.description read below needs no
check of its own.
The key set is closed and said so out loud: the root carries
additionalProperties: false, which is the server stating its contract in
tools/list so a schema-aware client can catch a misspelled key before it
sends. Enforcement is not this schema's job — a dispatch gate answers a
stray key or a wrong-typed argument in the tool dialect, naming it and
pointing at help (see "Dispatch errors and self-correction" in
Wymcp.Tool). The declaration is the root's alone:
data stays a bare object in tools/list, which keeps the payload
compact; the key sets inside it are closed per action, published by
Wymcp.Help and enforced by that same gate.
The generated schema carries no
header annotation, so a modern
tools/call to a use Wymcp.Tool tool mirrors no argument into an
Mcp-Param-* header. The spec leaves annotating to the server and has it
refuse a call whose client left an annotated argument unmirrored, so a
header annotation the framework wrote on every tool's behalf would put
each tool's whole surface behind a client feature its author never asked
for — one some clients still lack. A tool that wants an argument routable
by header implements Wymcp.Tool without the macro and writes its own
input schema. header_annotations/1 reads the header annotations out of
such a schema, and validate_header_annotations!/2 is what it is held to.
Per-action constraints are deliberately not encoded here: :required,
:required_one_of and every property's own schema are enforced at
dispatch by Wymcp.Tool — values by the value gate
(Wymcp.Tool.ValueGate) — and the full per-action schemas are surfaced on
demand by Wymcp.Help. This keeps the tools/list payload compact;
agents act from the action summaries and pay for a tool's full schemas
only when they ask.
Summary
Functions
An action summary is one action's name joined to its description as
"<action>: <description>". Returns one summary per action of module,
sorted by action name.
The header annotations schema
declares, sorted by property path.
Validates every header annotation
in schema, raising Wymcp.ConfigurationError naming module and the
rule it breaks — and the property, wherever there is one to name. The
configuration refusal carries module and input_schema/0 as the
callback at fault.
Types
Functions
An action summary is one action's name joined to its description as
"<action>: <description>". Returns one summary per action of module,
sorted by action name.
What the help tool's server index renders from. build/1 renders the
tools/list action description from the same private function rather than
from this one, so a change made here alone reaches the index only.
Example
Given a tool whose Wymcp.Tool.actions/0 returns
%{
get: %{description: "Get a widget", properties: %{}},
create: %{description: "Create a widget", properties: %{}}
}the summaries are
["create: Create a widget", "get: Get a widget"]
The header annotations schema
declares, sorted by property path.
Each entry is a map of :header — the annotation's value, the display half
of the Mcp-Param-* name a conforming client sends — :path, the
property's keys from the schema root, which is also the path into a call's
arguments, and :type, the property's
declared JSON Schema type.
Only properties reachable from the root through "properties" keys are
returned, because those are the only ones the spec lets a client honour.
An annotation anywhere else is not silently ignored: it is what
validate_header_annotations!/2 refuses, by counting both sets and
comparing them.
Validates every header annotation
in schema, raising Wymcp.ConfigurationError naming module and the
rule it breaks — and the property, wherever there is one to name. The
configuration refusal carries module and input_schema/0 as the
callback at fault.
The rules are the spec's, and a conforming client enforces the same set by excluding a tool whose schema breaks any of them from its own tool list — silently, as far as the server is concerned. Refusing the schema at the registration moment is what turns that disappearance into a message naming the tool.
Only a hand-written Wymcp.Tool.input_schema/0 can break a rule: the
generated schema carries no header annotation. What reaches this
function is a map that is not a struct, because the callback-shape check
(Wymcp.Tool.validate_callback_shape!/1) refuses any other return from that
callback before a definition is built.