---
summary: "Tool error responses gain structuredContent.error parity with content[]; recovery hint mirrors into text; _meta.error and _meta['mcp-ts-core/errors'] wire publication dropped"
breaking: true
---

# 0.8.3 — 2026-04-29

Error-surface cleanup. The success-path `format-parity` invariant — every field in both `structuredContent` and `content[]` — now extends to errors. Closes [#84](https://github.com/cyanheads/mcp-ts-core/issues/84).

## Changed

- **Tool error response shape** (`src/mcp-server/tools/utils/toolHandlerFactory.ts`) — replaces `_meta.error: { code, data? }` with `structuredContent.error: { code, message, data? }`. Both surfaces clients forward to the agent now carry the same payload: `content[]` (markdown, read by clients like Claude Desktop) and `structuredContent.error` (JSON, read by clients like Claude Code). `data` propagation rules unchanged — only `McpError.data` and `ZodError.issues` flow through.
- **Recovery hint mirroring** — when `data.recovery.hint` is a non-empty string, `content[0].text` becomes `Error: <msg>\n\nRecovery: <hint>`. Without a hint, the text remains `Error: <msg>`. Format-only clients now see the same recovery guidance `structuredContent.error`-readers receive.
- **Auto-task error path** (`src/mcp-server/tools/tool-registration.ts`) — uses the same shaping helpers. Timeout produces `McpError(Timeout, …)` rather than the prior `getErrorMessage` stringification, so timed-out tasks now carry a real JSON-RPC code through to the stored result.
- **Templates** — `templates/src/mcp-server/tools/definitions/echo.tool.ts` gains a typed `errors[]` contract example (`empty_message → InvalidParams`) demonstrating the `ctx.fail(reason, …)` pattern for new servers.

## Removed

- **`_meta.error` on tool error responses.** The pre-parity workaround for giving programmatic clients structured access to error info. `structuredContent.error` does that job correctly.
- **`_meta['mcp-ts-core/errors']` wire publication in `tools/list` and `resources/list`.** Removed `ERROR_CONTRACT_META_KEY` and `buildMetaWithErrorContract` from `src/types-global/errors.ts`; the registries now pass `def._meta` through unchanged. Contract-based ergonomics — typed `ctx.fail`, conformance lint — are unaffected.

## Added

- **`buildToolErrorResult(code, message, data?)`** and **`classifyAndBuildToolErrorResult(error)`** — exported from `src/mcp-server/tools/utils/toolHandlerFactory.ts` for shaping tool error envelopes consistently. Used internally by both the regular and auto-task error paths.

## Docs

- `CLAUDE.md` / `AGENTS.md` — added "Error-path parity" paragraph to the Error Handling section.
- `skills/api-errors/SKILL.md` — replaced `_meta.error` references with `structuredContent.error`, added Error-path parity table, removed stale `tools/list` references.
- `skills/field-test/SKILL.md` — updated tool error projections from `result._meta.error.{code, data.reason}` → `result.structuredContent.error.{code, message, data?.reason}`.
- `skills/design-mcp-server/SKILL.md` — updated typed-contract paragraph.
- `docs/audit/` — empirical helpfulness-patterns audit across 8 reference servers (47 tools, ~133 pattern instances). Foundation referenced in [#81](https://github.com/cyanheads/mcp-ts-core/issues/81).

## Migration

| Before | After |
|:-------|:------|
| `result._meta.error.code` | `result.structuredContent.error.code` |
| `result._meta.error.data` | `result.structuredContent.error.data` |
| `result._meta.error.data.reason` (typed contract) | `result.structuredContent.error.data.reason` |
| `tool._meta['mcp-ts-core/errors']` (in `tools/list` / `resources/list`) | Not published — read the contract from the source definition or its TypeScript types |

`error.message` is now consistently surfaced on both surfaces (was only in `content[]` text before). Code that read `result.content[0].text` continues to work; recovery-hint-aware clients can opt into the markdown form or read `data.recovery.hint` directly.
