@@ -46,155 +46,6 @@ import { UriTemplate, Variables } from "../shared/uriTemplate.js";
46
46
import { RequestHandlerExtra } from "../shared/protocol.js" ;
47
47
import { Transport } from "../shared/transport.js" ;
48
48
49
- // Minimal JSON Schema generation for Zod v4
50
- type JsonSchema = {
51
- type : "object" | "string" | "number" | "boolean" | "integer" ;
52
- properties ?: Record < string , JsonSchema | { enum : string [ ] ; type ?: "string" } > ;
53
- required ?: string [ ] ;
54
- enum ?: string [ ] ;
55
- } ;
56
-
57
- function zodToJsonSchema ( schema : ZodObject < ZodRawShape > ) : JsonSchema {
58
- const shape = schema . shape ;
59
- const properties : NonNullable < JsonSchema [ "properties" ] > = { } ;
60
- const required : string [ ] = [ ] ;
61
-
62
- for ( const [ key , value ] of Object . entries ( shape ) ) {
63
- const [ unwrapped , isOptional ] = unwrapOptional ( value as ZodType ) ;
64
- const propSchema = toJsonForAny ( unwrapped ) ;
65
- if ( propSchema ) {
66
- properties [ key ] = propSchema ;
67
- } else {
68
- // Fallback to empty object schema for unsupported types
69
- properties [ key ] = { } as unknown as JsonSchema ;
70
- }
71
- if ( ! isOptional ) required . push ( key ) ;
72
- }
73
-
74
- const result : JsonSchema = { type : "object" , properties } ;
75
- if ( required . length > 0 ) result . required = required ;
76
- return result ;
77
- }
78
-
79
- function unwrapOptional ( s : ZodType ) : [ ZodType , boolean ] {
80
- // Zod v4 Optional has unwrap(); fall back to heuristic if unavailable
81
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
82
- const anySchema = s as any ;
83
- if ( typeof anySchema . isOptional === "function" && anySchema . isOptional ( ) ) {
84
- if ( typeof anySchema . unwrap === "function" ) {
85
- return [ anySchema . unwrap ( ) , true ] ;
86
- }
87
- // Best-effort: try _def.innerType if present
88
- if ( anySchema . _def ?. innerType ) {
89
- return [ anySchema . _def . innerType as ZodType , true ] ;
90
- }
91
- return [ s , true ] ;
92
- }
93
- return [ s , false ] ;
94
- }
95
-
96
- function toJsonForAny (
97
- s : ZodType ,
98
- ) : JsonSchema | { enum : string [ ] ; type ?: "string" } | undefined {
99
- // Prefer Zod v4 built-in conversion when available, then normalize
100
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
101
- const anySchema = s as any ;
102
- if ( typeof anySchema . toJsonSchema === "function" ) {
103
- try {
104
- const js = anySchema . toJsonSchema ( ) ;
105
- const normalized = normalizeJsonFragment ( js ) ;
106
- if ( normalized ) return normalized ;
107
- } catch {
108
- // fall through to manual mapping
109
- }
110
- }
111
-
112
- // Manual mapping for common primitives and objects
113
- if ( isInstanceOf ( anySchema , z . ZodString ) ) return { type : "string" } ;
114
- if ( isInstanceOf ( anySchema , z . ZodBoolean ) ) return { type : "boolean" } ;
115
- if ( isInstanceOf ( anySchema , z . ZodNumber ) ) return { type : "number" } ;
116
- if ( isInstanceOf ( anySchema , z . ZodObject ) )
117
- return zodToJsonSchema ( anySchema as ZodObject < ZodRawShape > ) ;
118
- // Enums
119
- if ( isInstanceOf ( anySchema , z . ZodEnum ) ) {
120
- const values = extractEnumValues ( anySchema ) ;
121
- if ( values ) return { type : "string" , enum : values } ;
122
- }
123
- return undefined ;
124
- }
125
-
126
- function extractEnumValues ( s : unknown ) : string [ ] | undefined {
127
- // Try well-known locations across Zod versions
128
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
129
- const anySchema = s as any ;
130
- if ( Array . isArray ( anySchema . options ) ) return anySchema . options as string [ ] ;
131
- if ( Array . isArray ( anySchema . values ) ) return anySchema . values as string [ ] ;
132
- if ( Array . isArray ( anySchema . _def ?. values ) )
133
- return anySchema . _def . values as string [ ] ;
134
- return undefined ;
135
- }
136
-
137
- // Avoid `any` in constructor typing for linter compliance
138
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
139
- function isInstanceOf < T > (
140
- value : unknown ,
141
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
142
- ctor : new ( ...args : any [ ] ) => T ,
143
- ) : value is T {
144
- // Avoid crashes across dual bundles by checking name and prototype
145
- return (
146
- typeof value === "object" &&
147
- value !== null &&
148
- ( value as object ) instanceof ctor
149
- ) ;
150
- }
151
-
152
- function normalizeJsonFragment (
153
- js : unknown ,
154
- ) : JsonSchema | { enum : string [ ] ; type ?: "string" } | undefined {
155
- if ( ! js || typeof js !== "object" ) return undefined ;
156
- // If this already looks like a primitive schema
157
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
158
- const frag = js as any ;
159
- if (
160
- frag . type === "string" ||
161
- frag . type === "number" ||
162
- frag . type === "boolean" ||
163
- frag . type === "integer"
164
- ) {
165
- const res : JsonSchema = { type : frag . type } ;
166
- if ( Array . isArray ( frag . enum ) ) res . enum = frag . enum ;
167
- return res ;
168
- }
169
- if ( Array . isArray ( frag . enum ) ) {
170
- return {
171
- type : typeof frag . type === "string" ? frag . type : "string" ,
172
- enum : frag . enum ,
173
- } ;
174
- }
175
- if (
176
- frag . type === "object" &&
177
- frag . properties &&
178
- typeof frag . properties === "object"
179
- ) {
180
- const properties : Record <
181
- string ,
182
- JsonSchema | { enum : string [ ] ; type ?: "string" }
183
- > = { } ;
184
- for ( const [ k , v ] of Object . entries (
185
- frag . properties as Record < string , unknown > ,
186
- ) ) {
187
- const nv = normalizeJsonFragment ( v ) ;
188
- if ( nv ) properties [ k ] = nv ;
189
- else properties [ k ] = { } as unknown as JsonSchema ;
190
- }
191
- const out : JsonSchema = { type : "object" , properties } ;
192
- if ( Array . isArray ( frag . required ) && frag . required . length > 0 )
193
- out . required = frag . required . slice ( ) ;
194
- return out ;
195
- }
196
- return undefined ;
197
- }
198
49
199
50
/**
200
51
* High-level MCP server that provides a simpler API for working with resources, tools, and prompts.
@@ -265,13 +116,13 @@ export class McpServer {
265
116
title : tool . title ,
266
117
description : tool . description ,
267
118
inputSchema : tool . inputSchema
268
- ? ( zodToJsonSchema ( tool . inputSchema ) as Tool [ "inputSchema" ] )
119
+ ? z . toJSONSchema ( tool . inputSchema ) as Tool [ "inputSchema" ]
269
120
: EMPTY_OBJECT_JSON_SCHEMA ,
270
121
annotations : tool . annotations ,
271
122
} ;
272
123
273
124
if ( tool . outputSchema ) {
274
- toolDefinition . outputSchema = zodToJsonSchema (
125
+ toolDefinition . outputSchema = z . toJSONSchema (
275
126
tool . outputSchema ,
276
127
) as Tool [ "outputSchema" ] ;
277
128
}
0 commit comments