1- import { ZodTypeAny , ZodTypeDef , ZodType , ParseInput , ParseReturnType , RawCreateParams , ZodErrorMap , ProcessedCreateParams } from 'zod' ;
1+ import { ZodTypeAny } from 'zod' ;
22
33export enum McpZodTypeKind {
44 Completable = 'McpCompletable'
@@ -11,69 +11,56 @@ export type CompleteCallback<T extends ZodTypeAny = ZodTypeAny> = (
1111 }
1212) => T [ '_input' ] [ ] | Promise < T [ '_input' ] [ ] > ;
1313
14- export interface CompletableDef < T extends ZodTypeAny = ZodTypeAny > extends ZodTypeDef {
14+ export interface CompletableDef < T extends ZodTypeAny = ZodTypeAny > {
1515 type : T ;
1616 complete : CompleteCallback < T > ;
1717 typeName : McpZodTypeKind . Completable ;
1818}
1919
20- export class Completable < T extends ZodTypeAny > extends ZodType < T [ '_output' ] , CompletableDef < T > , T [ '_input' ] > {
21- _parse ( input : ParseInput ) : ParseReturnType < this[ '_output' ] > {
22- const { ctx } = this . _processInputParams ( input ) ;
23- const data = ctx . data ;
24- return this . _def . type . _parse ( {
25- data,
26- path : ctx . path ,
27- parent : ctx
28- } ) ;
29- }
30-
31- unwrap ( ) {
32- return this . _def . type ;
33- }
34-
35- static create = < T extends ZodTypeAny > (
36- type : T ,
37- params : RawCreateParams & {
38- complete : CompleteCallback < T > ;
39- }
40- ) : Completable < T > => {
41- return new Completable ( {
42- type,
43- typeName : McpZodTypeKind . Completable ,
44- complete : params . complete ,
45- ...processCreateParams ( params )
46- } ) ;
47- } ;
48- }
49-
5020/**
5121 * Wraps a Zod type to provide autocompletion capabilities. Useful for, e.g., prompt arguments in MCP.
22+ *
23+ * Uses an immutable wrapper approach that creates a new schema object with completion metadata
24+ * while preserving all validation behavior of the underlying schema.
5225 */
53- export function completable < T extends ZodTypeAny > ( schema : T , complete : CompleteCallback < T > ) : Completable < T > {
54- return Completable . create ( schema , { ...schema . _def , complete } ) ;
55- }
26+ export function completable < T extends ZodTypeAny > (
27+ schema : T ,
28+ complete : CompleteCallback < T >
29+ ) : T & { _def : T [ '_def' ] & CompletableDef < T > } {
30+ // Create new schema object inheriting from original
31+ const wrapped = Object . create ( Object . getPrototypeOf ( schema ) ) ;
5632
57- // Not sure why this isn't exported from Zod:
58- // https://github.com/colinhacks/zod/blob/f7ad26147ba291cb3fb257545972a8e00e767470/src/types.ts#L130
59- function processCreateParams ( params : RawCreateParams ) : ProcessedCreateParams {
60- if ( ! params ) return { } ;
61- const { errorMap, invalid_type_error, required_error, description } = params ;
62- if ( errorMap && ( invalid_type_error || required_error ) ) {
63- throw new Error ( `Can't use "invalid_type_error" or "required_error" in conjunction with custom error map.` ) ;
64- }
65- if ( errorMap ) return { errorMap : errorMap , description } ;
66- const customMap : ZodErrorMap = ( iss , ctx ) => {
67- const { message } = params ;
68-
69- if ( iss . code === 'invalid_enum_value' ) {
70- return { message : message ?? ctx . defaultError } ;
33+ // Copy all properties including getters/setters (except _def and _zod which we'll redefine)
34+ Object . getOwnPropertyNames ( schema ) . forEach ( key => {
35+ if ( key !== '_def' && key !== '_zod' ) {
36+ const descriptor = Object . getOwnPropertyDescriptor ( schema , key ) ;
37+ if ( descriptor ) {
38+ Object . defineProperty ( wrapped , key , descriptor ) ;
39+ }
7140 }
72- if ( typeof ctx . data === 'undefined' ) {
73- return { message : message ?? required_error ?? ctx . defaultError } ;
74- }
75- if ( iss . code !== 'invalid_type' ) return { message : ctx . defaultError } ;
76- return { message : message ?? invalid_type_error ?? ctx . defaultError } ;
41+ } ) ;
42+
43+ // Create new def with added completion metadata
44+ const newDef = {
45+ ...schema . _def ,
46+ typeName : McpZodTypeKind . Completable ,
47+ type : schema ,
48+ complete
7749 } ;
78- return { errorMap : customMap , description } ;
50+
51+ // Set _def as read-only property (matching Zod's design)
52+ Object . defineProperty ( wrapped , '_def' , {
53+ value : newDef ,
54+ writable : false ,
55+ enumerable : false ,
56+ configurable : false
57+ } ) ;
58+
59+ // Update _zod to maintain _def === _zod.def invariant
60+ wrapped . _zod = {
61+ ...schema . _zod ,
62+ def : newDef
63+ } ;
64+
65+ return wrapped as T & { _def : T [ '_def' ] & CompletableDef < T > } ;
7966}
0 commit comments