Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

v1.x and v2 disagree on validating an error result's structuredContent — and the v1.x comment describes the v2 behaviour

Abierto
#2,748 5 comentarios 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 1 día

@v0ropaev ya está trabajando en esto.

Desde el 18/9/2026.

  • #2836 de @v0ropaev — abierto

Evaluación

Dificultad
4/5
Tiempo estimado
3-5 días
Aptitud para principiantes
48/100
Tipo de issue
Error
Claridad
Bastante claro
Estado de actividad
Activo
Stack tecnológico
typescript

Línea de trabajo

Compara las validaciones de protección en src/client/index.ts:740 y packages/client/src/client/client.ts:2448, luego inspecciona validateToolOutput en server/mcp.js y reproduce la diferencia de caché de tools/list. Se considera terminado cuando se haya decidido el comportamiento previsto de los resultados de error, las rutas y los comentarios de v1.x y v2 coincidan, y se haya corregido la documentación o guía engañosa.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

v1

Summary

Since the v2 split on 2026-07-27, the two published lines disagree about whether a tool result with isError: true has its structuredContent validated against the tool's outputSchema — and the v1.x source comment describes the v2 behaviour rather than its own.

v2 / main — packages/client/src/client/client.ts:2448 (shipped in @modelcontextprotocol/[email protected]):

// Only validate structured content if present (not when there's an error)
if (result.structuredContent !== undefined && !result.isError) {

v1.x — src/client/index.ts:740 (shipped in @modelcontextprotocol/[email protected], still the latest dist-tag, not deprecated):

// Only validate structured content if present (not when there's an error)
if (result.structuredContent) {

Identical comment, different condition. On v1.x the parenthetical is simply untrue: an error result carrying structuredContent is validated, and callTool throws McpError -32602 before the caller can read the payload.

Note the guard directly above it on both lines does test isError (!result.structuredContent && !result.isError), which is what makes the omission below read as an oversight rather than a decision.

Reproduction

Self-contained, against @modelcontextprotocol/[email protected] — SDK server + SDK client over InMemoryTransport, no third-party code:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
import { z } from "zod";

const server = new McpServer({ name: "repro", version: "1.0.0" });
server.registerTool(
  "get_score",
  { description: "Returns a score.", inputSchema: {}, outputSchema: { score: z.number() } },
  async () => ({
    isError: true,
    content: [{ type: "text", text: JSON.stringify({ code: "AUTH_REQUIRED" }) }],
    structuredContent: { code: "AUTH_REQUIRED" },
  }),
);

const client = new Client({ name: "c", version: "1.0.0" });
const [ct, st] = InMemoryTransport.createLinkedPair();
await Promise.all([server.connect(st), client.connect(ct)]);

await client.listTools();                                  // <-- the only difference
await client.callTool({ name: "get_score", arguments: {} });
--- WITHOUT tools/list (validator not cached) ---
OK  -> {"code":"AUTH_REQUIRED"}

--- WITH tools/list first (validator cached) ---
THREW -> McpError: MCP error -32602: Structured content does not match the tool's
         output schema: data must have required property 'score', ...

Two things worth drawing out:

  1. The server half sends this happily. validateToolOutput in server/mcp.js short-circuits with an explicit if (result.isError) { return; }. So the v1.x SDK will emit a result that the v1.x SDK then refuses to receive.
  2. The failure is conditional on unrelated prior state. The same call succeeds or throws depending only on whether tools/list was called earlier, since that is what populates _cachedToolOutputValidators. Clients that list before calling — i.e. essentially all real ones — always get the throw; a test client that never lists never sees it. That asymmetry makes this easy to miss in a test suite and guaranteed in production.

Why I'm filing rather than commenting on the existing threads

This has been reported and fixed five times, and I don't want to add a sixth duplicate — the divergence itself is the new part, and it only came into existence with the v2 split:

#1428 Fix targeting v1.x, from MCP Inspector being unable to display JetBrains' error payloads. Closed after review discussion.
#1690 Same fix. Closed by its author believing main already skipped on error.
#1943 The canonical issue. Closed not_planned as superseded by #1945.
#1945 Open, now unmergeable: main was fixed independently, and the second file it patched (experimental/tasks/client.ts) was removed by #2128. Probably closeable.
#1947 Same fix again, opened and closed within a day in favour of #1945.

I'd also rather not relitigate the substantive question. On #1428 @cliffhall made the case that validating whenever structuredContent is present is the correct behaviour, and asked reasonably what an error result's structuredContent is even for. I find that persuasive — in our own server we resolved this by simply not setting structuredContent on error results, which costs nothing since the payload is already in content[0].text.

But main now does the opposite of what that review concluded, so whichever answer is right, the two lines currently can't both be.

What I'm asking for

Whichever of these fits — I'm happy to send the PR for any of them:

  1. Say which behaviour is intended. If v1.x is correct, v2 has a regression. If v2 is correct, v1.x has the bug five people have now reported.
  2. At minimum, fix the v1.x comment. If the v1.x behaviour is deliberate, // Only validate structured content if present (not when there's an error) is actively misleading and is the proximate cause of the repeat reports. Something like // Validated whenever present — error results are NOT exempt; see #1428 would stop the cycle for a one-line change.
  3. If servers must not put structuredContent on error results, document it where server authors will see it. Nothing in the tool-registration docs says so today, and registerTool accepts it without complaint on both lines.

Related but not the same: SEP-2145 (still open) would make output-validation failures surface as tool execution errors rather than protocol errors, which would change how this failure presents but not whether it happens.

Real-world impact

We ship a hosted MCP server with 15 tools that all declare outputSchema. Every one returned its AUTH_REQUIRED / PRO_REQUIRED body — price, trial terms, signup link — as structuredContent, and every listing client silently converted that into a thrown McpError instead. Unauthenticated users got a protocol exception where the actionable message should have been. Our test suite missed it for months for exactly the reason above: our test client never called listTools().

Environment

  • @modelcontextprotocol/[email protected] (and 1.29.0 — the block is byte-identical), Node 20+, macOS
  • Verified against v1.x @ a9f6eb7 and main as of 2026-09-02
Lenguaje dominante
TypeScript
Estrellas
13.5k
Forks
2.3k
Merge medio
1 d 22 h
PR fusionados (30 d)
52

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de modelcontextprotocol/typescript-sdk

Todos los issues de modelcontextprotocol/typescript-sdk

Issues similares

Más issues de TypeScript

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.