---
summary: "mcp-ts-core 0.13.6 brings structured consent-refusal and argument-rejection errors, drops the upstream request URL from unclassified error data, and normalizes sequence_id-style argument variants before validation."
breaking: false
security: false
---

# 2.3.5 — 2026-09-21

## Changed

- **Consent-gate refusal is now structured.** A 2025-era client declaring no `elicitation.form` capability, calling `ntfy_manage_message` or an outbound-action publish, is refused with `InvalidRequest` (`-32600`), `data.reason: "client_capability_missing"`, and a recovery hint naming the capability, on both `structuredContent.error` and `content[]` — in place of a bare `isError` text block (mcp-ts-core 0.13.5, cyanheads/mcp-ts-core#379).
- **Argument rejections carry `data.reason: "invalid_arguments"` and a schema-derived `Recovery:` hint** — an unknown key lists the keys the tool accepts, a wrong type names the type to send; undeclared keys are still rejected, never dropped (mcp-ts-core 0.13.3, cyanheads/mcp-ts-core#445).
- **Tool error text now closes with `(reason <reason>)`**, plus ` · retryable` where the contract entry declares `retryable`; `structuredContent` is unchanged (mcp-ts-core 0.13.5, cyanheads/mcp-ts-core#458).
- **A case-style key variant such as `sequenceId` is rewritten to the declared `sequence_id`, and a JSON-stringified array argument is repaired before validation** (mcp-ts-core 0.13.4, cyanheads/mcp-ts-core#452, cyanheads/mcp-ts-core#234).
- **`tools/list` contract-error descriptions now terminate each entry's `when`** — `ntfy_manage_message`'s `not_found` `when` was reworded to read as one sentence under that rendering; no schema constraint changed (mcp-ts-core 0.13.5, cyanheads/mcp-ts-core#389).
- **Server instructions tightened to three sentences**, now stating plainly that a published message's `id` is passed back as `sequence_id`; behavior is unchanged.
- `consent_declined` now logs at `notice` rather than `error` on both gated tools, and `ntfy_publish_message`'s six upstream reasons carry `thrownBy: 'service'` for the contract linter — both are log/lint-only, no caller-visible change (mcp-ts-core 0.13.5, 0.13.6, cyanheads/mcp-ts-core#462).
- `devcheck.config.json` gains a `lint` block that `lint-mcp.ts` reads for rule knobs (mcp-ts-core 0.13.6); unset here, so behavior is unchanged. Framework skills, the CodeQL workflow, and the issue templates are brought up to the 0.13.6 template.

## Fixed

- **An unclassified upstream HTTP failure no longer carries the request URL on `error.data.url`** — `status`, `body`, `operation`, and `topic` remain (mcp-ts-core 0.13.4, cyanheads/mcp-ts-core#307).

## Dependencies

- `@cyanheads/mcp-ts-core` `^0.13.2` → `^0.13.6`
- `zod` `^4.6.4` → `^4.6.5`
- `@biomejs/biome` `^2.5.13` → `^2.5.14` (dev)
- `@types/node` `^26.4.0` → `^26.6.2` (dev)
- `vitest` `^5.0.0` → `^5.0.1` (dev)
