fix(server): check tool callback output schemas - #2800
Open
hngpt52 wants to merge 1 commit into
Open
Conversation
Closes modelcontextprotocol#2754. Agent: codex-1
🦋 Changeset detectedLatest commit: d5669c4 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: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2754.
A tool declaring
outputSchema: z.object({ data: z.string() })currently accepts a callback returningstructuredContent: "pong". That compiles and only fails when the tool runs. This change makes the mismatch a TypeScript error; returning{ data: "pong" }compiles.The registration overloads now carry the inferred output schema into callback result types. Successful results require matching, defined structured content, including when the schema output is
unknown. Error and input-required results remain valid, and registrations without an output schema keep their existing broad result type. The change covers Standard Schema providers and deprecated raw Zod shapes; runtime validation and serialization are unchanged.Compiler regressions cover valid and invalid output, sync/async callbacks, input inference, exceptional branches, non-object roots, coercion, and ArkType/Valibot. The provider assertions run in the server package's CI typecheck. ESM/CJS consumer checks exercise the built declarations with
skipLibCheck: false. Deliberately malformed runtime fixtures remain in place with explicit casts so runtime rejection is still tested.The tool guide and API comments explain the output contract, including defaults/coercion and the fact that validation does not replace returned values with parsed data. A server patch changeset calls out the stricter compile-time behavior.
Validation
Local environment: macOS, Node 25.6.1, pnpm 10.26.1, clean worktree based on
b6542615.pnpm install --frozen-lockfilepnpm run check:all— passes, including workspace typechecks, lint, TypeDoc, and VitePress.pnpm run build:allpnpm --filter @modelcontextprotocol/server exec tsc -p tsconfig.json --noEmitnode scripts/smoke-dist-types.mjs— ESM and CJS pass.pnpm -r --filter '!@modelcontextprotocol/test-e2e' test— 4,233 tests pass.git diff --checkThe full e2e run finished with 2,640 passed, 147 expected failures, one failure in
protocol:timeout:max-total [sse 2026-07-28](ticks.lengthwas 0), and two unhandled request timeouts. Running the unchanged SSE timeout cases on pristine upstreamb6542615also exits nonzero with the same two unhandled timeouts; the assertion failure did not recur in that focused baseline run. No protocol timing code is changed here. The hosted Node 20/22/24 test and e2e matrix subsequently passed; see the CI results below.CI results
All 14 reported checks passed for commit
d5669c47: