Inline @eval annotations for description tuning (spec §4).
Attach evals to a tool to continuously grade the rendered descriptions it advertises across model × verbosity permutations, so terser or model-specific variants (spec §2/§3) do not silently degrade call quality.
Declaring evals
On a classic use Noizu.MCP.Server.Tool module, pass the :evals option — a
list of eval specs:
use Noizu.MCP.Server.Tool,
description: "...",
evals: [
[
name: :simple_task,
prompt: [%{role: "user", content: "Find recent docs about X."}],
rubric: [
covers_pitfall: "resulting call includes the required filters",
fresh: "mentions post-cutoff knowledge-base entries"
]
]
]On a use Noizu.MCP.Server.Toolkit function, annotate with @eval (module
attribute, accumulate: true) — each @eval drains onto the following
@mcp tool, mirroring how @mcp itself is collected:
@eval name: :simple_task, prompt: [...], rubric: [...]
@mcp description: "...", input: [...]
# ⟦𓉧𓀞𓊆𓉥⟧ read_file :: auto-generated pointer for public function read_file
def read_file(args, ctx), do: ...Each eval spec is a keyword list:
:name(required) — an atom or non-empty string; unique per tool:prompt(required) — a non-empty list of messages or a non-empty string:rubric(required) — a non-empty keyword list ofcriterion: "description"(each description a string)
Malformed specs are a compile error (ArgumentError from the classic tool DSL,
CompileError from the toolkit DSL, matching each path's existing convention).
Introspection
list/1 returns [{tool_name, [%Noizu.MCP.Eval.Spec{}]}] for every tool on a
server module that carries evals — the entry point for the harness and any
app-layer tooling.
Harness
mix noizu.mcp.eval (delegating to Noizu.MCP.Eval.Harness) renders each
tool's wire schema through the §0/§2/§3 resolution pipeline for every selected
permutation, runs the eval prompt against a target via a pluggable
Noizu.MCP.Eval.Runner, and grades each rubric criterion via a pluggable
Noizu.MCP.Eval.Judge. Adapters are selected via the :noizu_mcp
:eval_runner / :eval_judge application env; a deterministic no-LLM stub
pair ships for tests/CI. See those modules for the callback contracts.
Summary
Functions
Compile and validate a list of raw eval specs into [%Noizu.MCP.Eval.Spec{}].
List the evals declared on a server module.
Functions
@spec compile_specs(nil | list(), String.t()) :: [Noizu.MCP.Eval.Spec.t()]
Compile and validate a list of raw eval specs into [%Noizu.MCP.Eval.Spec{}].
context names the owning tool for error messages. Raises ArgumentError on
any malformed spec, missing required key, non-string rubric description, or
duplicate eval name / rubric criterion. nil compiles to [].
@spec list(module()) :: [{String.t(), [Noizu.MCP.Eval.Spec.t()]}]
List the evals declared on a server module.
Returns [{tool_name, [%Noizu.MCP.Eval.Spec{}]}] for every registered tool
that carries at least one eval; tools without evals are omitted. Order follows
the server's tool registration order.
Works against servers whose tool registry comes from the tool DSL macro (it
reads server.__mcp__(:tools)); hand-written handle_list_tools/2 servers
report an empty list.