fix(core): restore the v1 content default for tools/call results on the legacy era (#2456)

This commit is contained in:
Felix Weinberger 2026-07-09 14:02:08 +01:00 • committed by GitHub
commit 44797d7779
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 347 additions and 96 deletions

View file

@ -340,9 +340,11 @@ If you were on a v2 alpha and consumed wire schemas directly:
The `resultType` / `EmptyResultSchema` / `specTypeSchemas` rules above have **no v1.x
impact** — these members did not exist before 2026-07-28. The neutral-model wire
tightening that **does** affect v1 code (`content` required, custom-handler `_meta`
passthrough, `specTypeSchemas` narrowing) is in
[upgrade-to-v2.md › Wire tightening](./upgrade-to-v2.md#wire-tightening-every-era).
tightening that **does** affect v1 code (custom-handler `_meta` passthrough,
`specTypeSchemas` narrowing) is in
[upgrade-to-v2.md › Wire tightening](./upgrade-to-v2.md#wire-tightening-every-era);
`CallToolResult.content` keeps its v1 default on the legacy era (2026-07-28
connections require it explicitly).
> **If you were on a v2 alpha:** the 2026-07-28 draft error codes were renumbered:
> `HeaderMismatch` `-32001`→`-32020`, `MissingRequiredClientCapability` `-32003`→`-32021`,

View file

@ -1673,10 +1673,16 @@ requests, the per-request `_meta.logLevel` envelope key is the filter — see
#### Wire tightening (every era)
- **`CallToolResult.content` is required at the wire boundary.** The `content.default([])`
affordance was removed. Tool handlers MUST include `content` (the TypeScript surface
always required it; `content: []` is fine). A handler result without it is rejected
with `-32602`.
- **`CallToolResult.content` keeps the v1 parse tolerance on the legacy era.** An
inbound result without `content` defaults to `[]` (deployed servers omit it
alongside `structuredContent`); 2026-07-28 connections stay strict. Authoring is
unchanged and era-independent: the TypeScript surface requires `content` on handler
results, and a content-less handler result is normalized to `content: []` before it
reaches the wire. One sharpening remains: a content-less body carrying another
result family's vocabulary (a task handle or an `input_required` round) is still
rejected loudly — tolerance never turns a different result kind into a silent empty
success. A body whose only foreign key was `resultType` strips to an empty object
and defaults, exactly as v1 parsed a payload-free body.
- **`ElicitResult.content` values are typed and validated as
`string | number | boolean | string[]`.** v1's TypeScript surface accepted
`Record<string, unknown>` content values; an elicitation handler returning arbitrary