- 
                Notifications
    You must be signed in to change notification settings 
- Fork 1.4k
feat: zod v4 #869
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
base: main
Are you sure you want to change the base?
feat: zod v4 #869
Changes from 17 commits
6db0e68
              08513d3
              3b28aac
              1cc8c7b
              9b178b7
              9298723
              aca892b
              e2d351c
              2010203
              8531d8e
              1461fa2
              9cf8b2e
              5a761b5
              30fb023
              3cd0546
              5a64ed1
              ab26df8
              aa5e35b
              374a673
              79f6c04
              a55f3aa
              467c0c2
              3440675
              e8e91ed
              b6b7d96
              5813fc3
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
|  | @@ -2,7 +2,7 @@ | |
| /* eslint-disable no-constant-binary-expression */ | ||
| /* eslint-disable @typescript-eslint/no-unused-expressions */ | ||
| import { Client } from "./index.js"; | ||
| import { z } from "zod"; | ||
| import { z } from "zod/v4"; | ||
|          | ||
| import { | ||
| RequestSchema, | ||
| NotificationSchema, | ||
|  | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -1,13 +1,4 @@ | ||
| import { | ||
| ZodTypeAny, | ||
| ZodTypeDef, | ||
| ZodType, | ||
| ParseInput, | ||
| ParseReturnType, | ||
| RawCreateParams, | ||
| ZodErrorMap, | ||
| ProcessedCreateParams, | ||
| } from "zod"; | ||
| import { ZodTypeAny } from "zod/v4"; | ||
|  | ||
| export enum McpZodTypeKind { | ||
| Completable = "McpCompletable", | ||
|  | @@ -17,82 +8,38 @@ export type CompleteCallback<T extends ZodTypeAny = ZodTypeAny> = ( | |
| value: T["_input"], | ||
| context?: { | ||
| arguments?: Record<string, string>; | ||
| }, | ||
| } | ||
| ) => T["_input"][] | Promise<T["_input"][]>; | ||
|  | ||
| export interface CompletableDef<T extends ZodTypeAny = ZodTypeAny> | ||
| extends ZodTypeDef { | ||
| export interface CompletableDef<T extends ZodTypeAny = ZodTypeAny> { | ||
| type: T; | ||
| complete: CompleteCallback<T>; | ||
| typeName: McpZodTypeKind.Completable; | ||
| } | ||
|  | ||
| export class Completable<T extends ZodTypeAny> extends ZodType< | ||
| T["_output"], | ||
| CompletableDef<T>, | ||
| T["_input"] | ||
| > { | ||
| _parse(input: ParseInput): ParseReturnType<this["_output"]> { | ||
| const { ctx } = this._processInputParams(input); | ||
| const data = ctx.data; | ||
| return this._def.type._parse({ | ||
| data, | ||
| path: ctx.path, | ||
| parent: ctx, | ||
| }); | ||
| } | ||
|  | ||
| unwrap() { | ||
| return this._def.type; | ||
| } | ||
|  | ||
| static create = <T extends ZodTypeAny>( | ||
| type: T, | ||
| params: RawCreateParams & { | ||
| complete: CompleteCallback<T>; | ||
| }, | ||
| ): Completable<T> => { | ||
| return new Completable({ | ||
| type, | ||
| typeName: McpZodTypeKind.Completable, | ||
| complete: params.complete, | ||
| ...processCreateParams(params), | ||
| }); | ||
| }; | ||
| } | ||
|  | ||
| /** | ||
| * Wraps a Zod type to provide autocompletion capabilities. Useful for, e.g., prompt arguments in MCP. | ||
| */ | ||
| export function completable<T extends ZodTypeAny>( | ||
| schema: T, | ||
| complete: CompleteCallback<T>, | ||
| ): Completable<T> { | ||
| return Completable.create(schema, { ...schema._def, complete }); | ||
| } | ||
|  | ||
| // Not sure why this isn't exported from Zod: | ||
| // https://github.com/colinhacks/zod/blob/f7ad26147ba291cb3fb257545972a8e00e767470/src/types.ts#L130 | ||
| function processCreateParams(params: RawCreateParams): ProcessedCreateParams { | ||
| if (!params) return {}; | ||
| const { errorMap, invalid_type_error, required_error, description } = params; | ||
| if (errorMap && (invalid_type_error || required_error)) { | ||
| throw new Error( | ||
| `Can't use "invalid_type_error" or "required_error" in conjunction with custom error map.`, | ||
| ); | ||
| complete: CompleteCallback<T> | ||
| ): T & { | ||
| _def: (T extends { _def: infer D } ? D : unknown) & CompletableDef<T>; | ||
|          | ||
| } { | ||
| const target = schema as unknown as { _def?: Record<string, unknown> }; | ||
| const originalDef = (target._def ?? {}) as Record<string, unknown>; | ||
| // Only mutate the existing _def object to respect read-only property semantics | ||
| if ( | ||
| (originalDef as { typeName?: unknown }).typeName !== | ||
| McpZodTypeKind.Completable | ||
| ) { | ||
| (originalDef as { typeName?: McpZodTypeKind; type?: ZodTypeAny }).typeName = | ||
| McpZodTypeKind.Completable; | ||
| (originalDef as { typeName?: McpZodTypeKind; type?: ZodTypeAny }).type = | ||
| schema; | ||
| } | ||
| if (errorMap) return { errorMap: errorMap, description }; | ||
| const customMap: ZodErrorMap = (iss, ctx) => { | ||
| const { message } = params; | ||
|  | ||
| if (iss.code === "invalid_enum_value") { | ||
| return { message: message ?? ctx.defaultError }; | ||
| } | ||
| if (typeof ctx.data === "undefined") { | ||
| return { message: message ?? required_error ?? ctx.defaultError }; | ||
| } | ||
| if (iss.code !== "invalid_type") return { message: ctx.defaultError }; | ||
| return { message: message ?? invalid_type_error ?? ctx.defaultError }; | ||
| (originalDef as { complete?: CompleteCallback<T> }).complete = complete; | ||
| return schema as unknown as T & { | ||
| _def: (T extends { _def: infer D } ? D : unknown) & CompletableDef<T>; | ||
| }; | ||
| return { errorMap: customMap, description }; | ||
| } | ||
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.
Do we need this? This seems like an unintentional change.
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.
I left this in as I was seeing issues running the auth test suite. Adding this prevent the mocks from duplicating and was able to get my tests back running again. We can remove if perhaps it's just my local setup.