mcp-from-openapi 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,666 @@
1
+ # mcp-from-openapi
2
+
3
+ > Production-ready TypeScript library for converting OpenAPI specifications into MCP (Model Context Protocol) tool
4
+ > definitions
5
+
6
+ [![npm version](https://badge.fury.io/js/mcp-from-openapi.svg)](https://www.npmjs.com/package/mcp-from-openapi)
7
+ [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-yellow.svg)](https://opensource.org/license/apache-2-0)
8
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.3-blue.svg)](https://www.typescriptlang.org/)
9
+
10
+ ## What This Solves
11
+
12
+ When converting OpenAPI specs to MCP tools, you encounter **parameter conflicts** - the same parameter name appears in
13
+ different locations (path, query, body). This library automatically resolves these conflicts and provides an **explicit
14
+ mapper** that tells you exactly how to construct HTTP requests.
15
+
16
+ **The Problem:**
17
+
18
+ ```yaml
19
+ # OpenAPI spec
20
+ paths:
21
+ /users/{id}:
22
+ post:
23
+ parameters:
24
+ - name: id # id in PATH
25
+ in: path
26
+ requestBody:
27
+ content:
28
+ application/json:
29
+ schema:
30
+ properties:
31
+ id: # id in BODY - CONFLICT!
32
+ type: string
33
+ ```
34
+
35
+ **The Solution:**
36
+
37
+ ```typescript
38
+ {
39
+ inputSchema: {
40
+ properties: {
41
+ pathId: { type: "string" }, // Automatically renamed!
42
+ bodyId: { type: "string" } // Automatically renamed!
43
+ }
44
+ },
45
+ mapper: [
46
+ { inputKey: "pathId", type: "path", key: "id" },
47
+ { inputKey: "bodyId", type: "body", key: "id" }
48
+ ]
49
+ }
50
+ ```
51
+
52
+ Now you know **exactly** how to build the HTTP request!
53
+
54
+ ## Features
55
+
56
+ - 🎯 **Smart Parameter Handling** - Automatic conflict detection and resolution
57
+ - 📦 **Complete Schemas** - Input schema combines all parameters, output schema from responses
58
+ - 🔐 **Rich Metadata** - Authentication, servers, tags, deprecation status
59
+ - 🔧 **Multiple Input Sources** - Load from URL, file, YAML string, or JSON object
60
+ - ✅ **Production Ready** - Full TypeScript, validation, error handling, 80%+ test coverage
61
+ - 🧩 **Zod Compatible** - Schemas ready for json-schema-to-zod conversion
62
+ - 🚀 **MCP Native** - Designed specifically for Model Context Protocol integration
63
+
64
+ ## Installation
65
+
66
+ ```bash
67
+ npm install mcp-from-openapi
68
+ # or
69
+ yarn add mcp-from-openapi
70
+ # or
71
+ pnpm add mcp-from-openapi
72
+ ```
73
+
74
+ ## Quick Start
75
+
76
+ ### Basic Usage
77
+
78
+ ```typescript
79
+ import { OpenAPIToolGenerator } from 'mcp-from-openapi';
80
+
81
+ // 1. Load OpenAPI spec
82
+ const generator = await OpenAPIToolGenerator.fromURL('https://api.example.com/openapi.json');
83
+
84
+ // 2. Generate tools
85
+ const tools = await generator.generateTools();
86
+
87
+ // 3. Each tool has everything you need:
88
+ tools.forEach((tool) => {
89
+ console.log(tool.name); // "createUser"
90
+ console.log(tool.inputSchema); // Combined schema for all params
91
+ console.log(tool.outputSchema); // Response schema
92
+ console.log(tool.mapper); // How to build the HTTP request
93
+ console.log(tool.metadata); // Auth, servers, tags, etc.
94
+ });
95
+ ```
96
+
97
+ ### Loading from Different Sources
98
+
99
+ ```typescript
100
+ // From URL
101
+ const generator = await OpenAPIToolGenerator.fromURL('https://api.example.com/openapi.json');
102
+
103
+ // From file
104
+ const generator = await OpenAPIToolGenerator.fromFile('./openapi.yaml');
105
+
106
+ // From YAML string
107
+ const yamlString = `
108
+ openapi: 3.0.0
109
+ info:
110
+ title: My API
111
+ version: 1.0.0
112
+ paths:
113
+ /users:
114
+ get:
115
+ responses:
116
+ '200':
117
+ description: Success
118
+ `;
119
+ const generator = await OpenAPIToolGenerator.fromYAML(yamlString);
120
+
121
+ // From JSON object
122
+ const openApiSpec = { openapi: '3.0.0' /* ... */ };
123
+ const generator = await OpenAPIToolGenerator.fromJSON(openApiSpec);
124
+ ```
125
+
126
+ ### Understanding the Output
127
+
128
+ Each generated tool includes:
129
+
130
+ ```typescript
131
+ interface McpOpenAPITool {
132
+ name: string; // Operation ID or generated name
133
+ description: string; // From operation summary/description
134
+ inputSchema: JSONSchema7; // Combined input schema (all params)
135
+ outputSchema?: JSONSchema7; // Response schema (can be union)
136
+ mapper: ParameterMapper[]; // Input → Request mapping
137
+ metadata: ToolMetadata; // Auth, servers, etc.
138
+ }
139
+ ```
140
+
141
+ ### Using the Mapper
142
+
143
+ The mapper tells you how to convert tool input into an HTTP request:
144
+
145
+ ```typescript
146
+ function buildRequest(tool: McpOpenAPITool, input: any) {
147
+ let path = tool.metadata.path;
148
+ const query = new URLSearchParams();
149
+ const headers: Record<string, string> = {};
150
+ let body: any;
151
+
152
+ tool.mapper.forEach((m) => {
153
+ const value = input[m.inputKey];
154
+ if (!value) return;
155
+
156
+ switch (m.type) {
157
+ case 'path':
158
+ path = path.replace(`{${m.key}}`, encodeURIComponent(value));
159
+ break;
160
+ case 'query':
161
+ query.set(m.key, value);
162
+ break;
163
+ case 'header':
164
+ headers[m.key] = value;
165
+ break;
166
+ case 'body':
167
+ if (!body) body = {};
168
+ body[m.key] = value;
169
+ break;
170
+ }
171
+ });
172
+
173
+ return {
174
+ url: `${tool.metadata.servers[0].url}${path}?${query}`,
175
+ method: tool.metadata.method,
176
+ headers,
177
+ body: body ? JSON.stringify(body) : undefined,
178
+ };
179
+ }
180
+
181
+ // Example usage
182
+ const request = buildRequest(tool, {
183
+ pathId: 'user-123',
184
+ bodyName: 'John Doe',
185
+ bodyEmail: 'john@example.com',
186
+ });
187
+
188
+ const response = await fetch(request.url, {
189
+ method: request.method,
190
+ headers: request.headers,
191
+ body: request.body,
192
+ });
193
+ ```
194
+
195
+ ### Handling Parameter Conflicts
196
+
197
+ When the same parameter name appears in different locations, the library automatically renames them:
198
+
199
+ ```typescript
200
+ // OpenAPI with conflicts:
201
+ // - id in path
202
+ // - id in query
203
+ // - id in body
204
+
205
+ const tool = await generator.generateTool('/users/{id}', 'post');
206
+
207
+ // Generated input schema:
208
+ {
209
+ properties: {
210
+ pathId: { type: "string" }, // Renamed!
211
+ queryId: { type: "string" }, // Renamed!
212
+ bodyId: { type: "string" } // Renamed!
213
+ }
214
+ }
215
+
216
+ // Your input should use the renamed keys:
217
+ const input = {
218
+ pathId: "user-123", // Not "id"
219
+ queryId: "track-456",
220
+ bodyId: "internal-789"
221
+ };
222
+ ```
223
+
224
+ ## Common Use Cases
225
+
226
+ ### 1. Build an MCP Server
227
+
228
+ ```typescript
229
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
230
+ import { OpenAPIToolGenerator } from 'mcp-from-openapi';
231
+
232
+ const server = new Server(/* ... */);
233
+
234
+ // Load tools from OpenAPI
235
+ const generator = await OpenAPIToolGenerator.fromURL('https://api.example.com/openapi.json');
236
+ const tools = await generator.generateTools();
237
+
238
+ // Register each tool
239
+ tools.forEach((tool) => {
240
+ server.setRequestHandler(tool.name, async (request) => {
241
+ const httpRequest = buildRequest(tool, request.params);
242
+ const response = await fetch(httpRequest.url, httpRequest);
243
+ return response.json();
244
+ });
245
+ });
246
+ ```
247
+
248
+ ### 2. Filter Operations
249
+
250
+ ```typescript
251
+ // Only GET operations
252
+ const tools = await generator.generateTools({
253
+ filterFn: (op) => op.method === 'get', // op has path and method properties
254
+ });
255
+
256
+ // Specific operations by ID
257
+ const tools = await generator.generateTools({
258
+ includeOperations: ['getUser', 'createUser'],
259
+ });
260
+
261
+ // Exclude deprecated
262
+ const tools = await generator.generateTools({
263
+ includeDeprecated: false,
264
+ });
265
+ ```
266
+
267
+ ### 3. Handle Multiple Response Codes
268
+
269
+ ```typescript
270
+ // Include all response status codes
271
+ const tools = await generator.generateTools({
272
+ includeAllResponses: true, // Creates oneOf union
273
+ });
274
+
275
+ // Or prefer specific codes only
276
+ const tools = await generator.generateTools({
277
+ preferredStatusCodes: [200, 201],
278
+ includeAllResponses: false,
279
+ });
280
+ ```
281
+
282
+ ### 4. Custom Base URL
283
+
284
+ ```typescript
285
+ const generator = await OpenAPIToolGenerator.fromURL(url, {
286
+ baseUrl: 'https://staging.api.example.com',
287
+ });
288
+ ```
289
+
290
+ ### 5. Validate Before Generating
291
+
292
+ ```typescript
293
+ const generator = await OpenAPIToolGenerator.fromFile('./openapi.yaml');
294
+
295
+ const validation = await generator.validate();
296
+ if (!validation.valid) {
297
+ console.error('Validation errors:', validation.errors);
298
+ throw new Error('Invalid OpenAPI spec');
299
+ }
300
+
301
+ const tools = await generator.generateTools();
302
+ ```
303
+
304
+ ### 6. Custom Naming Strategy
305
+
306
+ ```typescript
307
+ const tool = await generator.generateTool('/users/{id}', 'post', {
308
+ namingStrategy: {
309
+ conflictResolver: (paramName, location, index) => {
310
+ // Custom naming logic
311
+ return `${location.toUpperCase()}_${paramName}`;
312
+ },
313
+ },
314
+ });
315
+ ```
316
+
317
+ ### 7. Integration with Zod
318
+
319
+ ```typescript
320
+ import { zodSchema } from 'json-schema-to-zod';
321
+
322
+ const tools = await generator.generateTools();
323
+
324
+ const validatedTools = tools.map((tool) => ({
325
+ ...tool,
326
+ validateInput: zodSchema(tool.inputSchema),
327
+ validateOutput: tool.outputSchema ? zodSchema(tool.outputSchema) : null,
328
+ }));
329
+
330
+ // Use validators
331
+ const validatedInput = validatedTools[0].validateInput.parse(userInput);
332
+ ```
333
+
334
+ ## API Reference
335
+
336
+ ### OpenAPIToolGenerator
337
+
338
+ #### Static Factory Methods
339
+
340
+ ```typescript
341
+ // Load from URL
342
+ static async fromURL(url: string, options?: LoadOptions): Promise<OpenAPIToolGenerator>
343
+
344
+ // Load from file path
345
+ static async fromFile(filePath: string, options?: LoadOptions): Promise<OpenAPIToolGenerator>
346
+
347
+ // Load from YAML string
348
+ static async fromYAML(yaml: string, options?: LoadOptions): Promise<OpenAPIToolGenerator>
349
+
350
+ // Load from JSON object
351
+ static async fromJSON(json: object, options?: LoadOptions): Promise<OpenAPIToolGenerator>
352
+ ```
353
+
354
+ #### Instance Methods
355
+
356
+ ```typescript
357
+ // Generate all tools
358
+ async generateTools(options?: GenerateOptions): Promise<McpOpenAPITool[]>
359
+
360
+ // Generate a specific tool
361
+ async generateTool(path: string, method: string, options?: GenerateOptions): Promise<McpOpenAPITool>
362
+
363
+ // Get OpenAPI document
364
+ getDocument(): OpenAPIDocument
365
+
366
+ // Validate OpenAPI document
367
+ async validate(): Promise<ValidationResult>
368
+ ```
369
+
370
+ ### Configuration Options
371
+
372
+ #### LoadOptions
373
+
374
+ ```typescript
375
+ interface LoadOptions {
376
+ dereference?: boolean; // Resolve $refs (default: true)
377
+ baseUrl?: string; // Override base URL
378
+ headers?: Record<string, string>; // Custom headers for URL loading
379
+ timeout?: number; // Request timeout (default: 30000ms)
380
+ validate?: boolean; // Validate document (default: true)
381
+ followRedirects?: boolean; // Follow redirects (default: true)
382
+ }
383
+ ```
384
+
385
+ #### GenerateOptions
386
+
387
+ ```typescript
388
+ interface GenerateOptions {
389
+ includeOperations?: string[]; // Include only these operation IDs
390
+ excludeOperations?: string[]; // Exclude these operation IDs
391
+ filterFn?: (op: OperationWithContext) => boolean; // Custom filter (op has path and method)
392
+ namingStrategy?: NamingStrategy; // Custom naming for conflicts
393
+ preferredStatusCodes?: number[]; // Preferred response codes
394
+ includeDeprecated?: boolean; // Include deprecated ops (default: false)
395
+ includeAllResponses?: boolean; // Include all status codes (default: true)
396
+ maxSchemaDepth?: number; // Max depth for schemas (default: 10)
397
+ }
398
+
399
+ // OperationWithContext extends OperationObject with:
400
+ interface OperationWithContext extends OperationObject {
401
+ path: string; // The API path
402
+ method: string; // The HTTP method (get, post, etc.)
403
+ }
404
+ }
405
+ ```
406
+
407
+ #### NamingStrategy
408
+
409
+ ```typescript
410
+ interface NamingStrategy {
411
+ conflictResolver: (paramName: string, location: ParameterLocation, index: number) => string;
412
+
413
+ toolNameGenerator?: (path: string, method: HTTPMethod, operationId?: string) => string;
414
+ }
415
+ ```
416
+
417
+ ### Types
418
+
419
+ #### McpOpenAPITool
420
+
421
+ ```typescript
422
+ interface McpOpenAPITool {
423
+ name: string;
424
+ description: string;
425
+ inputSchema: JSONSchema7;
426
+ outputSchema?: JSONSchema7;
427
+ mapper: ParameterMapper[];
428
+ metadata: ToolMetadata;
429
+ }
430
+ ```
431
+
432
+ #### ParameterMapper
433
+
434
+ ```typescript
435
+ interface ParameterMapper {
436
+ inputKey: string; // Property name in input schema
437
+ type: ParameterLocation; // 'path' | 'query' | 'header' | 'cookie' | 'body'
438
+ key: string; // Original parameter name
439
+ required?: boolean;
440
+ style?: string;
441
+ explode?: boolean;
442
+ serialization?: SerializationInfo;
443
+ }
444
+ ```
445
+
446
+ #### ToolMetadata
447
+
448
+ ```typescript
449
+ interface ToolMetadata {
450
+ path: string;
451
+ method: HTTPMethod;
452
+ operationId?: string;
453
+ tags?: string[];
454
+ deprecated?: boolean;
455
+ security?: SecurityRequirement[];
456
+ servers?: ServerInfo[];
457
+ responseStatusCodes?: number[];
458
+ externalDocs?: ExternalDocumentation;
459
+ }
460
+ ```
461
+
462
+ ## Error Handling
463
+
464
+ ```typescript
465
+ import { LoadError, ParseError, ValidationError, GenerationError } from 'mcp-from-openapi';
466
+
467
+ try {
468
+ const generator = await OpenAPIToolGenerator.fromURL(url);
469
+ const tools = await generator.generateTools();
470
+ } catch (error) {
471
+ if (error instanceof LoadError) {
472
+ console.error('Failed to load:', error.message);
473
+ } else if (error instanceof ParseError) {
474
+ console.error('Failed to parse:', error.message);
475
+ } else if (error instanceof ValidationError) {
476
+ console.error('Invalid spec:', error.errors);
477
+ } else if (error instanceof GenerationError) {
478
+ console.error('Generation failed:', error.message);
479
+ }
480
+ }
481
+ ```
482
+
483
+ ## Architecture
484
+
485
+ ### System Overview
486
+
487
+ The library follows a modular architecture with clear separation of concerns:
488
+
489
+ ```
490
+ OpenAPIToolGenerator (Main Entry Point)
491
+ ├── Validator → OpenAPI document validation
492
+ ├── ParameterResolver → Parameter conflict resolution & mapping
493
+ ├── ResponseBuilder → Output schema generation
494
+ └── SchemaBuilder → Schema manipulation utilities
495
+ ```
496
+
497
+ ### Data Flow
498
+
499
+ ```
500
+ User Input (URL/File/String/Object)
501
+ ↓
502
+ Load & Parse
503
+ ↓
504
+ OpenAPI Document
505
+ ↓
506
+ Validate (optional)
507
+ ↓
508
+ Dereference $refs (optional)
509
+ ↓
510
+ For Each Operation:
511
+ ├── ParameterResolver → inputSchema + mapper
512
+ ├── ResponseBuilder → outputSchema
513
+ └── Metadata Extractor → metadata
514
+ ↓
515
+ McpOpenAPITool[]
516
+ ```
517
+
518
+ ### Core Components
519
+
520
+ #### 1. OpenAPIToolGenerator
521
+
522
+ - **Responsibility**: Entry point, orchestration, document management
523
+ - **Key Methods**: Factory methods, generateTools(), validate()
524
+
525
+ #### 2. ParameterResolver
526
+
527
+ - **Responsibility**: Collect parameters, detect conflicts, generate mapper
528
+ - **Algorithm**:
529
+ 1. Collect all parameters by name from all sources
530
+ 2. Detect naming conflicts
531
+ 3. Apply naming strategy to resolve conflicts
532
+ 4. Build combined input schema
533
+ 5. Create mapper entries
534
+
535
+ #### 3. ResponseBuilder
536
+
537
+ - **Responsibility**: Extract response schemas, handle multiple status codes
538
+ - **Features**:
539
+ - Prefer specific status codes
540
+ - Generate union types (oneOf) for multiple responses
541
+ - Add metadata (status code, content type)
542
+
543
+ #### 4. Validator
544
+
545
+ - **Responsibility**: Validate OpenAPI document structure
546
+ - **Checks**:
547
+ - OpenAPI version (3.0.x or 3.1.x)
548
+ - Required fields (info, paths, etc.)
549
+ - Path parameters defined
550
+ - Operation structure
551
+
552
+ ### Design Patterns
553
+
554
+ 1. **Factory Pattern** - For creating generator instances
555
+ 2. **Strategy Pattern** - For parameter naming customization
556
+ 3. **Builder Pattern** - For schema construction
557
+ 4. **Template Method** - For tool generation workflow
558
+
559
+ ### Extension Points
560
+
561
+ 1. **Custom Naming Strategies** - Implement `NamingStrategy` interface
562
+ 2. **Custom Filters** - Use `filterFn` in `GenerateOptions`
563
+ 3. **Custom Validators** - Extend `Validator` class
564
+ 4. **Schema Transformations** - Use `SchemaBuilder` utilities
565
+
566
+ ## Best Practices
567
+
568
+ ### 1. Always Dereference in Production
569
+
570
+ ```typescript
571
+ const generator = await OpenAPIToolGenerator.fromURL(url, {
572
+ dereference: true, // Resolve all $refs for easier consumption
573
+ });
574
+ ```
575
+
576
+ ### 2. Validate Before Generating
577
+
578
+ ```typescript
579
+ const validation = await generator.validate();
580
+ if (!validation.valid) {
581
+ throw new Error('Invalid OpenAPI spec');
582
+ }
583
+ ```
584
+
585
+ ### 3. Cache Generated Tools
586
+
587
+ ```typescript
588
+ class ToolCache {
589
+ private cache = new Map<string, McpOpenAPITool[]>();
590
+
591
+ async getTools(apiUrl: string): Promise<McpOpenAPITool[]> {
592
+ if (this.cache.has(apiUrl)) {
593
+ return this.cache.get(apiUrl)!;
594
+ }
595
+
596
+ const generator = await OpenAPIToolGenerator.fromURL(apiUrl);
597
+ const tools = await generator.generateTools();
598
+ this.cache.set(apiUrl, tools);
599
+
600
+ return tools;
601
+ }
602
+ }
603
+ ```
604
+
605
+ ### 4. Use TypeScript
606
+
607
+ ```typescript
608
+ import type { McpOpenAPITool, LoadOptions } from 'mcp-from-openapi';
609
+
610
+ const options: LoadOptions = {
611
+ dereference: true,
612
+ validate: true,
613
+ };
614
+ ```
615
+
616
+ ### 5. Handle Errors Properly
617
+
618
+ ```typescript
619
+ try {
620
+ const tools = await generator.generateTools();
621
+ } catch (error) {
622
+ if (error instanceof ValidationError) {
623
+ console.error('Validation errors:', error.errors);
624
+ }
625
+ // Handle appropriately
626
+ }
627
+ ```
628
+
629
+ ## Examples
630
+
631
+ Check the `examples/` directory for comprehensive examples including:
632
+
633
+ 1. Basic usage
634
+ 2. Parameter conflict resolution
635
+ 3. Custom naming strategies
636
+ 4. Multiple response handling
637
+ 5. Authentication handling
638
+ 6. Operation filtering
639
+ 7. Zod integration
640
+ 8. Request mapping
641
+
642
+ ## Requirements
643
+
644
+ - Node.js >= 18.0.0
645
+ - TypeScript >= 5.0 (for TypeScript users)
646
+
647
+ ## Dependencies
648
+
649
+ - `@apidevtools/json-schema-ref-parser` - $ref dereferencing
650
+ - `yaml` - YAML parsing
651
+ - `undici` - Modern HTTP client
652
+ - `json-schema` - Type definitions
653
+
654
+ ## Contributing
655
+
656
+ Contributions are welcome! Please see our contributing guidelines.
657
+
658
+ ## Related Projects
659
+
660
+ - [Model Context Protocol](https://modelcontextprotocol.io/)
661
+ - [OpenAPI Specification](https://www.openapis.org/)
662
+ - [JSON Schema](https://json-schema.org/)
663
+
664
+ ---
665
+
666
+ **Made with ❤️ for the MCP community**
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "mcp-from-openapi",
3
+ "version": "0.0.1",
4
+ "description": "Production-ready library for converting OpenAPI specifications into MCP tool definitions",
5
+ "author": "AgentFront <info@agentfront.dev>",
6
+ "license": "Apache-2.0",
7
+ "keywords": [
8
+ "mcp",
9
+ "model-context-protocol",
10
+ "openapi",
11
+ "swagger",
12
+ "api",
13
+ "rest",
14
+ "schema",
15
+ "json-schema",
16
+ "typescript",
17
+ "tool-generator",
18
+ "anthropic",
19
+ "claude"
20
+ ],
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/agentfront/frontmcp.git"
24
+ },
25
+ "bugs": {
26
+ "url": "https://github.com/agentfront/frontmcp/issues"
27
+ },
28
+ "homepage": "https://github.com/agentfront/frontmcp/blob/main/libs/mcp-from-openapi/README.md",
29
+ "main": "./src/index.js",
30
+ "types": "./src/index.d.ts",
31
+ "exports": {
32
+ "./package.json": "./package.json",
33
+ ".": {
34
+ "types": "./src/index.d.ts",
35
+ "import": "./src/index.js",
36
+ "default": "./src/index.js"
37
+ }
38
+ },
39
+ "dependencies": {
40
+ "@apidevtools/json-schema-ref-parser": "^11.5.4",
41
+ "json-schema": "^0.4.0",
42
+ "openapi-types": "^12.1.3",
43
+ "yaml": "^2.8.1"
44
+ },
45
+ "devDependencies": {
46
+ "@types/node": "^22.0.0",
47
+ "typescript": "^5.0.0",
48
+ "zod": "^3.23.8"
49
+ },
50
+ "type": "commonjs"
51
+ }