---
summary: "The enrichment block on tool(): a typed, success-path contract for agent-facing context — empty-result notices, query echo, pagination totals — populated via ctx.enrich() and surfaced to both structuredContent and content[] without a format() entry. The success-path counterpart to errors[]."
breaking: false
agent-notes: |
  Skills updated this release (Phase A picks these up): add-tool 2.9 → 2.10, design-mcp-server 2.12 → 2.13, api-context 1.3 → 1.4, api-linter 1.3 → 1.4.
  New optional builder field `enrichment` + `ctx.enrich(...)` API — adopt it to move agent-facing context (empty-result notices, query/filter echo, pagination totals) out of `format()`-only authoring (invisible to structuredContent-only clients) into a typed block that reaches both surfaces. No migration required; existing tools are unaffected.
  New testing helper `getEnrichment(ctx)` from `@cyanheads/mcp-ts-core/testing` reads what a handler accumulated via `ctx.enrich`.
  New advisory lint `enrichment-prefer-block` may flag existing `output` fields named `notice` / `effectiveQuery` / `queryEcho` — a warning suggesting they move to `enrichment`. Ignore if the field is genuinely domain data.
---

# 0.9.14 — 2026-05-29

## Added

- **`enrichment` block on `tool()`** — the success-path counterpart to `errors[]`. Declare `enrichment: { <name>: <ZodType> }` and populate it via `ctx.enrich(...)` (or the kind-tagged helpers `ctx.enrich.notice()` / `.total()` / `.echo()`) from the handler or service layer. The framework merges enrichment into `structuredContent`, advertises `output.extend(enrichment)` as the tool's `outputSchema` in `tools/list`, and mirrors it into a `content[]` trailer — so agent-facing context (empty-result notices, the query/filter as the server parsed it, pagination totals) reaches both `structuredContent`-only and `content[]`-only clients without a `format()` entry. Enrichment never rides in the domain return; a required enrichment field the handler never populates fails the effective-output parse, surfacing the bug. Applies to standard and auto-task (`task: true`) tools; the `TaskToolDefinition` escape hatch is unchanged. ([#173](https://github.com/cyanheads/mcp-ts-core/issues/173))
- **`ctx.enrich`** on `Context` — always present and callable from the service layer (like `ctx.log`/`ctx.state`); strictly typed on `HandlerContext<R, E>` to a `Partial` of the declared enrichment fields when a block is present.
- **`getEnrichment(ctx)`** test helper (`@cyanheads/mcp-ts-core/testing`) — reads the enrichment a handler accumulated on a mock context, for assertions.
- **`mcp.tool.enriched`** span attribute — set when a tool populates enrichment on a call, alongside the existing `mcp.tool.partial_success`.
- **Enrichment lint rules** — `enrichment-output-collision` and `enrichment-field-type` / `enrichment-type` (errors guarding the block's shape and its disjointness from `output`, which `output.extend` would otherwise silently override), `enrichment-empty` (warning), and the advisory `enrichment-prefer-block` (nudges meta-looking `output` fields toward enrichment).
- **`Enrich`, `EnrichHelpers`, `TypedEnrich`** exported from the main entry for typing against `ctx.enrich`.

## Changed

- **`ToolDefinition` / `tool()`** gain a 4th type parameter `TEnrich` (defaulted to `undefined`); **`HandlerContext<R, E>`** gains the enrichment dimension `E` (defaulted). Both additive — existing `HandlerContext<R>` and three-argument `ToolDefinition` usages are unchanged.
- **`ToolDefinition.format`** is now declared as a method (bivariant parameters) rather than an arrow property, so concrete tools stay assignable to the type-erased `AnyToolDefinition` once the enrichment type dimension is in play. Internal — no call-site change; `format: (result) => [...]` is unaffected.
- **Skills** — `add-tool` 2.9 → 2.10, `design-mcp-server` 2.12 → 2.13, `api-context` 1.3 → 1.4, `api-linter` 1.3 → 1.4: document the `enrichment` block / `ctx.enrich`, add the named "agent-facing context belongs in `enrichment`" rule, and revise the empty-results and operational-metadata examples to use enrichment as the primary home.

## Docs

- **README** — the headline example replaces `greet` with a complete `search` showing the `enrichment` block and the typed error contract side by side (an empty result is a `notice`, not a throw); "What you get" pivots to `format()` and the redundant lower error-contract example folds into the headline.
- **Init scaffold** — the echo starter tool gains an `enrichment` block so freshly scaffolded servers mirror the README.
