A tailored description: one string chosen per render context, with gap-fill interpolation for verbosity levels that no variant covers and — for weak harnesses/models — per-runner/model overrides (spec §3).
Verbosity variants (spec §2)
Anywhere a description string is accepted today — a tool's description:, a
toolkit @mcp description:, a field ... description: — a variant list is
also accepted:
description: [
{{:verbosity, {2, 3}}, "Medium description."},
{{:verbosity, 0}, "Terse."},
default: "Definitive fallback text"
]A bare string (description: "just text") is unchanged and covers every level.
Keys
{:verbosity, n}— a single leveln{:verbosity, {lo, hi}}— an inclusive range{:verbosity, [n, ...]}— an explicit set of levelsdefault: "text"— the definitive/fallback string, used when nothing more specific appliesdefault_verbosity: n— the annotation-level default verbosity, applied when a render context supplies no explicit verbosity
The verbosity domain is 0–9 (0 = tersest). Levels, range bounds, and set members outside that domain are a compile error, as are malformed keys and two entries covering the same exact level.
Deliberate deviation from the design spec. The spec sketched the annotation-level default as
default: [{:verbosity, 3}], overloading thedefault:key (fallback text vs. default-verbosity setting). This module splits them:default:is always the fallback text;default_verbosity:is the default level. Flagged for review.
Named variants + runner/model rules (spec §3)
Alongside description:, three sibling options — accepted on use Noizu.MCP.Server.Tool, @mcp, and field — build a tailored description
without forking the tool. from_opts/2 compiles them together:
description: "definitive fallback", # the default text
descriptions: [foo_bar: "…", "hippo-5": "…", codex_foobar: "…"],
verbosity_map: [{{0, 5}, :foo_bar}], # verbosity → named variant
runners: [
{{:grok, :*}, [{{:verbosity, {0, 5}}, :"hippo-5"}]},
{{:codex, [:spark, :"5.4"]}, [default: :codex_foobar]}
]descriptions:— a keyword list oftag: "text"named variants. Tags may be atoms or strings; they are stored normalized to strings.verbosity_map:—[{verbosity_spec, tag}, ...], mapping a verbosity selector (int /{lo, hi}/[levels]) to a named variant.runners:—[{{provider, model_matcher}, rules}, ...].provideris an atom (or:*wildcard);model_matcheris:*, an exact atom/string, or a list of atoms/strings (membership).rulesis a keyword-ish list mixing{{:verbosity, spec}, tag}entries and adefault: tag.
Every tag referenced by verbosity_map:/runners: must be declared in
descriptions:, and matchers must be well-formed — both are validated at
compile time (an ArgumentError, surfaced as a compile error at the DSL call
site).
Resolution
resolve/2 maps a normalized description and a Noizu.MCP.RenderCtx to a
concrete string (or nil). Precedence (spec §0), first match wins:
- the most specific matching runner rule — its own verbosity → tag map
(same gap-fill), falling back to the rule's
default:tag; - the tool/field-level
verbosity_map(verbosity → tag, gap-filled); - the inline
levelsvariants (verbosity → text, gap-filled — the §2 path); - the
default:fallback text (ornil).
Runner specificity (most specific wins; ties break toward declaration
order): the model matcher dominates the provider matcher — exact model (2) >
model-in-list (1) > :* (0); then provider exact (1) > :* (0). Model and
provider comparisons are insensitive to atom-vs-string representation, so
"5.4" matches :"5.4".
For an uncovered verbosity level, gap-fill picks the entry whose nearest
covered level is the smallest absolute distance away; ties prefer the lower
level ("left preference"). Worked examples (from the spec): defined {2,3} and
0, request 1 → 0; defined 3 and 9, request 8 → 9, 5 → 3, 6
→ 3.
Summary
Types
A compiled runner rule. provider is an atom or :*; model is :any,
{:exact, normalized}, or {:list, [normalized]}; levels maps a verbosity
level to a variant tag (gap-filled); default_tag is the rule's fallback tag.
Functions
Normalize a plain description: value into nil, a bare string, or a
%Description{}.
Compile a DSL option set into a description, combining description: with the
named-variant options descriptions:, verbosity_map:, and runners:.
Resolve a description against a render context, yielding a concrete string or
nil.
Types
@type input() :: nil | String.t() | [variant_entry()] | t()
@type runner_rule() :: %{ provider: atom() | String.t(), model: :any | {:exact, String.t()} | {:list, [String.t()]}, levels: %{optional(0..9) => String.t()}, default_tag: String.t() | nil }
A compiled runner rule. provider is an atom or :*; model is :any,
{:exact, normalized}, or {:list, [normalized]}; levels maps a verbosity
level to a variant tag (gap-filled); default_tag is the rule's fallback tag.
@type variant_entry() :: {variant_key(), String.t()} | {:default, String.t()} | {:default_verbosity, integer()}
Functions
Normalize a plain description: value into nil, a bare string, or a
%Description{}.
Bare strings pass through unchanged (so plain-string tools stay
byte-identical). A verbosity variant list compiles to a struct, validating the
domain and rejecting malformed keys or duplicate level coverage. context
names the owning tool/field for error messages.
For the named-variant / runner-rule form, use from_opts/2.
Compile a DSL option set into a description, combining description: with the
named-variant options descriptions:, verbosity_map:, and runners:.
When none of the three sibling options are present this is exactly
compile(opts[:description], context) — plain strings and §2 variant lists are
unchanged. When any is present, the description: value becomes the base (a
bare string becomes the default: text; a §2 variant list contributes its
levels), then named variants, the verbosity map, and runner rules are layered
on and every referenced tag is validated.
@spec resolve(nil | String.t() | t(), Noizu.MCP.RenderCtx.t()) :: String.t() | nil
Resolve a description against a render context, yielding a concrete string or
nil.
Precedence for the effective level: the context's explicit verbosity, then
the description's default_verbosity, then the context's defaults chain, then
the built-in 5; the result is clamped to 0..9.
Variant precedence (spec §0, first match wins): the most specific matching
runner rule; then verbosity_map (verbosity → tag); then inline levels
(verbosity → text); then the default: fallback text (or nil).