Repository navigation
fix(server): type registerTool structuredContent from outputSchema - #2449
mattzcarey wants to merge 1 commit into
Conversation
🦋 Changeset detectedLatest commit: 83b661f The changes in this PR will be included in the next version bump. This PR includes changesets to release 6 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
@modelcontextprotocol/client
@modelcontextprotocol/codemod
@modelcontextprotocol/core
@modelcontextprotocol/server
@modelcontextprotocol/server-legacy
@modelcontextprotocol/express
@modelcontextprotocol/fastify
@modelcontextprotocol/hono
@modelcontextprotocol/node
commit: |
ea5c666 to
d92a8bf
Compare
There was a problem hiding this comment.
2 optional notes from this repository's REVIEW.md or CLAUDE.md checks were not posted as comments, over this review's limit for such notes; they are on this commit's check card.
Findings marked 🟡 are optional suggestions and need no follow-up push.
Additional findings (outside the current diff — GitHub can't attach inline comments there):
-
🟡
skills/mcp-typescript-sdk-upgrade-to-v2/references/server-registration.md— nit: The upgrade skill describes theregisterTooloverload error and thecontentrule in ways this change makes false. Lines 113-117 say TS2769 lists "both overloads" with the cause in "the first overload's elaboration".registerToolnow has three overloads and the Standard Schema one is last (packages/server/src/server/mcp.ts:1088). Fix: reword each skill statement the new typing contradicts, which covers the 2 sites listed. Same instruction at 2 sites (server-registration.md:117, behavioral-changes.md:200). The second says the TypeScript surface requirescontenton handler results. [also at: packages/server/src/server/mcp.ts:1033 - nit: The upgrade guide's zod-version diagnosis no longer matches theregisterToolerror users see. skills/mcp-typescript-sdk-upgrade-to-v2/references/server-registration.md:113-119 describes a "two-overload error" with the cause in "the first overload's elaboration".; skills/mcp-typescript-sdk-upgrade-to-v2/references/server-registration.md:46 - nit: The upgrade skill's troubleshooting text no longer matches theregisterToolerror it describes. Lines 113-117 of this file sayTS2769lists "both overloads" with the cause in "the first overload's elaboration".] (Finding ID:f-fd569433)Why this was flagged
No runtime trigger; this is a words-are-true check on the upgrade skill that users and agents follow to diagnose migration compile errors. The diff reorders the
registerTooloverloads at packages/server/src/server/mcp.ts:1032-1105: two deprecated raw-shape overloads come first and the Standard Schema overload is third. With zod typings that lack~standard.jsonSchema, tsc now reports three overloads and theProperty 'jsonSchema' is missingelaboration sits under the last one, not the first, so the "two-overload error" cue at server-registration.md:117 no longer matches. The diff also makescontentoptional on typed successes (mcp.ts:1403), while skills/mcp-typescript-sdk-upgrade-to-v2/references/behavioral-changes.md:199-201 still says "the TypeScript surface requirescontenton handler results". On the base both statements matchedregisterTool. No safeguard applies: the skill text is not checked against the types.Verification: On the base,
registerToolhad two overloads with the Standard Schema one first, so the text was accurate. At HEAD there are three: raw-shape at packages/server/src/server/mcp.ts:1033, raw-shape output-only at :1048, Standard Schema last at :1088. The diff addsToolResultWithStructuredContentwithcontent?: CallToolResult['content'](mcp.ts:1403), socontentis optional on typed successes.
d92a8bf to
518c67c
Compare
There was a problem hiding this comment.
Code review completed
Nothing new to post: everything this review found is already covered by existing comments on this pull request or didn't merit a separate one.
3 further findings on code this push did not change were outside the scope of this re-review and not posted.
Still open from earlier reviews (7):
- 🔴
.changeset/register-tool-output-typing.md:5—Users upgrading get compile errors on correct tool callbacks that the changeset does not list as breaking. Line 5 names… - Also unresolved: 6 minor or pre-existing.
If you have decided not to act on one of these findings, resolve its thread (a reply alone leaves it open) and the next review stops counting it. To review this commit again now, use Re-run on its "Claude Code Review" check.
A tool's outputSchema now types its callback's successful result: structuredContent is required and must match the schema, for both the Standard Schema overload and the deprecated raw-shape overloads. isError results, input-required results and schema-less tools keep their existing types. Typed successes may omit content, which the server already fills in. The required value satisfies both sides of the schema because the server validates and sends the handler's raw value while tools/list advertises the output-side JSON Schema. undefined is excluded because the runtime treats it as absent. The raw-shape overloads move ahead of the Standard Schema overload and now require a raw shape, so overload errors for the common case point at the callback rather than at ZodRawShape. Closes #2754.
518c67c to
83b661f
Compare
McpServer.registerToolnow type-checks a callback's successful result against the tool'soutputSchema.structuredContentis required and must match the schema, for Standard Schema and the deprecated raw-shape overloads.isError: trueresults, input-required results and tools without anoutputSchemakeep their current types. Closes #2754.Why it is shaped this way:
tools/listadvertises the output-side JSON Schema that clients validate against. So the required type is the schema's output when that is also a valid input, else input & output. A.default()field must be supplied, a coerced field must already have the output type, and an incoherent.transform()resolves tonever.undefinedis rejected even forz.unknown(), because the runtime treats it as absent.nullis allowed when the schema allows it.contentis optional on typed successes. When it is omitted,McpServersends the JSON ofstructuredContentas a text block, so clients that only readcontentstill see the result. This is the one runtime change: such results used to go out withcontent: [].configlets it match only configs that really use a raw shape. TypeScript reports the last overload's error, so a mismatch now points atstructuredContentrather than atZodRawShape, and zero-argument raw-shape callbacks returningisError: trueno longer hit a false positive.unknownschema output (an untypedfromJsonSchema(...)) accepts any value, so forwardedunknownresults still compile.ToolResultFor,ToolStructuredContent,ToolResultWithStructuredContent,ToolErrorResult.ToolCallback<In, Out?>takes an optional output schema.This is a compile-time break for tools with an
outputSchema, so the changeset is a server minor and lists each case. Besides mismatched or missingstructuredContent, it breaks callbacks whose result is typed as plainCallToolResult, and registries forwarding anoutputSchematypedS | undefined, which TypeScript checks as if present.Runtime validation is unchanged and still authoritative for refinements,
fromJsonSchemaschemas, casts and JavaScript callers.Supersedes #2438 and #2800, which type the same callback; this version also catches missing
structuredContent, keepscontenttyped and handles transforms. Compile-time tests cover the #2754 snippet, Zod, ArkType, Valibot and raw shapes under tsgo and tsc.