Wymcp. Tool. Schema
(Wymcp v0.6.2)
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.validate!/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 public functions take the tool module, not an actions map, and
obtain the schemas themselves through Wymcp.Tool.Actions.fetch_schemas!/1
— so there is no way to hand this module a map that no validator has seen,
and the direct schema.description read below needs no check of its own.
Each obtains once and hands the map to a private function: 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.
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 — argument validation checks
structure only, and a dispatch gate answers a stray key in the tool
dialect, naming the key 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, so a tool that nests free-form structure under
it is unaffected.
The action property carries one further key: the
header annotation
"x-mcp-header" => "Action", which asks a conforming modern client to
mirror the chosen action into an Mcp-Param-Action request header. It is
the only property a generated schema can annotate — the spec reaches a
property through "properties" keys alone, and data declares none — and
it costs a tool author nothing, since the framework writes it. What a
gateway gets for it is the tool and the action of every call without
parsing a body. header_annotations/1 reads such annotations back out of
any input schema, generated or hand-written, and
validate_header_annotations!/2 is what a hand-written one is held to.
Per-action constraints are deliberately not encoded here: :required and
:required_one_of are enforced at dispatch by Wymcp.Tool, and the full
per-action schemas are surfaced on demand by Wymcp.Help. Property
values (types, formats) are not validated by the framework at all — a
tool that needs value guarantees checks them in run_action/3. 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 ArgumentError naming module and the rule it
breaks — and the property, wherever there is one to name.
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 ArgumentError naming module and the rule it
breaks — and the property, wherever there is one to name.
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's one annotation is the framework's own. That callback
is also the one caller that can return something other than a JSON
Schema object — a struct included — and a return like that is refused
here too, naming the tool and this rule and no property, since there is
none: both registration moments
hand this function whatever the callback returned, and nothing upstream
checks its shape.