-
Notifications
You must be signed in to change notification settings - Fork 1.8k
feat(compat): registerTool/registerPrompt accept raw Zod shape, auto-wrap with z.object() #1901
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 10 commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
27e4ddf
feat(compat): registerTool/registerPrompt accept raw Zod shape (auto-…
felixweinberger 5266131
fix: isZodRawShape treats empty object as raw shape (matches v1)
felixweinberger f2fdbe7
docs: changeset wording aligns with @deprecated overloads (not first-…
felixweinberger 9576f20
docs: clarify isZodRawShape only supports Zod values for auto-wrap
felixweinberger 0152b26
fix(compat): narrow ZodRawShape to Zod-only (detector + type); add ou…
felixweinberger 1af9ed2
test(compat): add e2e raw-shape tools/call test; drop vestigial warn-…
felixweinberger 3155be7
Merge branch 'main' into fweinberger/v2-bc-register-rawshape
KKonstantinov aba1d39
feat(compat): widen completable() constraint to StandardSchemaV1
felixweinberger 0febd83
refactor(compat): move zod helpers to zodCompat.ts; throw on invalid …
felixweinberger 7e80880
Merge branch 'main' into fweinberger/v2-bc-register-rawshape
felixweinberger c75bc88
test(compat): move zod-compat tests to zodCompat.test.ts; tighten nor…
felixweinberger a6b25ee
fix(compat): reject Zod v3 fields in raw-shape auto-wrap with actiona…
felixweinberger b5854c1
fix(compat): require plain-object prototype in isZodRawShape; null-gu…
felixweinberger 9b7ee90
Merge branch 'main' into fweinberger/v2-bc-register-rawshape
felixweinberger 27e2c4b
fix(compat): pass StandardSchema without ~standard.jsonSchema through…
felixweinberger 617830b
Merge branch 'main' into fweinberger/v2-bc-register-rawshape
felixweinberger File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| --- | ||
| '@modelcontextprotocol/core': patch | ||
| '@modelcontextprotocol/server': patch | ||
| --- | ||
|
|
||
| `registerTool`/`registerPrompt` accept a raw Zod shape (`{ field: z.string() }`) for `inputSchema`/`outputSchema`/`argsSchema` in addition to a wrapped Standard Schema. Raw shapes are auto-wrapped with `z.object()`. The raw-shape overloads are `@deprecated`; prefer wrapping with `z.object()`. | ||
|
|
||
| Also widens the `completable()` constraint from `StandardSchemaWithJSON` to `StandardSchemaV1` so v1's `completable(z.string(), fn)` continues to work. |
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| /** | ||
| * Zod-specific helpers for the v1-compat raw-shape shorthand on | ||
| * `registerTool`/`registerPrompt`. Kept separate from `standardSchema.ts` so | ||
| * that file stays library-agnostic per the Standard Schema spec. | ||
| */ | ||
|
|
||
| import * as z from 'zod/v4'; | ||
|
|
||
| import type { StandardSchemaV1, StandardSchemaWithJSON } from './standardSchema.js'; | ||
| import { isStandardSchema } from './standardSchema.js'; | ||
|
|
||
| function isZodSchema(v: unknown): v is z.ZodType { | ||
| if (typeof v !== 'object' || v === null) return false; | ||
| if ('_def' in v) return true; | ||
| return isStandardSchema(v) && (v as StandardSchemaV1)['~standard'].vendor === 'zod'; | ||
| } | ||
|
Check warning on line 16 in packages/core/src/util/zodCompat.ts
|
||
|
felixweinberger marked this conversation as resolved.
Outdated
|
||
|
|
||
| /** | ||
| * Detects a "raw shape" — a plain object whose values are Zod field schemas, | ||
| * e.g. `{ name: z.string() }`. Powers the auto-wrap in | ||
| * {@linkcode normalizeRawShapeSchema}, which wraps with `z.object()`, so only | ||
| * Zod values are supported. | ||
| * | ||
| * @internal | ||
| */ | ||
| export function isZodRawShape(obj: unknown): obj is Record<string, z.ZodType> { | ||
| if (typeof obj !== 'object' || obj === null) return false; | ||
| if (isStandardSchema(obj)) return false; | ||
| // [].every() is true, so an empty object is a valid raw shape (matches v1). | ||
| return Object.values(obj).every(v => isZodSchema(v)); | ||
| } | ||
|
claude[bot] marked this conversation as resolved.
|
||
|
|
||
| /** | ||
| * Accepts either a {@linkcode StandardSchemaWithJSON} or a raw Zod shape | ||
| * `{ field: z.string() }` and returns a {@linkcode StandardSchemaWithJSON}. | ||
| * Raw shapes are wrapped with `z.object()` so the rest of the pipeline sees a | ||
| * uniform schema type; already-wrapped schemas pass through unchanged. | ||
| * | ||
| * @internal | ||
| */ | ||
| export function normalizeRawShapeSchema( | ||
| schema: StandardSchemaWithJSON | Record<string, z.ZodType> | undefined | ||
| ): StandardSchemaWithJSON | undefined { | ||
| if (schema === undefined) return undefined; | ||
| if (isZodRawShape(schema)) { | ||
| return z.object(schema) as StandardSchemaWithJSON; | ||
| } | ||
| if (!isStandardSchema(schema)) { | ||
| throw new TypeError( | ||
| 'inputSchema/outputSchema/argsSchema must be a Standard Schema (e.g. z.object({...})) or a raw Zod shape ({ field: z.string() }).' | ||
| ); | ||
| } | ||
| return schema; | ||
|
felixweinberger marked this conversation as resolved.
|
||
| } | ||
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
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
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
Oops, something went wrong.
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 nit: this file header says it's "Kept separate from
standardSchema.tsso that file stays library-agnostic", and the reply on the earlier thread said "standardSchema.tsno longer imports zod" — both were true at 0febd83, but merge 9b7ee90 brought in #1895 (b256546), which re-addedimport * as z from 'zod/v4'tostandardSchema.ts:9for thez.toJSONSchema()fallback at line 178. Suggest softening to e.g. "Kept separate sostandardSchema.tsstays focused on the Standard Schema spec interface", or moving the #1895 zod fallback intozodCompat.tsso the claim actually holds.Extended reasoning...
What's wrong
The new file-level JSDoc at
packages/core/src/util/zodCompat.ts:3-4reads:And the author's reply on inline thread 3147227355 (resolving KKonstantinov's "move these out into a
zodCompatone" ask) stated "standardSchema.tsno longer imports zod." Both statements were accurate at commit 0febd83, when the split was made. But the subsequent merge commit 9b7ee90 brought b256546 (#1895) onto this branch, and #1895 re-introduced a zod import intostandardSchema.tsfor its zod-4.0–4.1z.toJSONSchema()fallback. So at HEAD (617830b), the rationale clause in this PR's newly-added comment is factually incorrect —standardSchema.tsis not library-agnostic.Step-by-step proof
packages/core/src/util/zodCompat.ts:1-5(newly added in this PR's diff):git logshows 0febd83 (createszodCompat.tsand removes the zod import fromstandardSchema.ts) was committed before merge 9b7ee90.standardSchemaToJsonSchema.packages/core/src/util/standardSchema.ts:9readsimport * as z from 'zod/v4';and line 178 readsresult = z.toJSONSchema(schema as unknown as z.ZodType, { target: 'draft-2020-12', io }) ....standardSchema.ts.Why nothing catches it
There's no lint or test that cross-references prose comments against imports. The comment was correct when written; it became stale via a textual-clean merge (no conflict markers, since #1895 touched
standardSchema.tsand this PR added a new file). The author's earlier resolved reply ("standardSchema.tsno longer imports zod") is on a closed thread, so nothing prompts a re-check after the merge.Impact
Zero behavioral impact — this is an internal file-header comment, not user-facing JSDoc, changelog, or
.d.ts. The organizational split itself (raw-shape compat helpers vs. Standard Schema spec utilities) remains perfectly sound; only the stated rationale for the split is wrong. Hence nit, non-blocking. The reason it's worth a one-line fix is that it sits at the top of a brand-new file added by this PR and will mislead the next contributor who reads it ("so I shouldn't add zod tostandardSchema.ts" — but it's already there).Suggested fix
Either soften the comment so it doesn't make a falsifiable claim:
…or, if you actually want to deliver on the "library-agnostic" claim, move #1895's
z.toJSONSchema()fallback (standardSchema.ts:158-178) intozodCompat.tsand call it fromstandardSchemaToJsonSchema— that would make both files match their stated purpose. The first option is the one-liner.