mcp-from-openapi 2.1.0 → 2.1.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/esm/index.mjs ADDED
@@ -0,0 +1,1561 @@
1
+ // libs/mcp-from-openapi/src/generator.ts
2
+ import * as yaml from "yaml";
3
+ import * as fs from "fs/promises";
4
+ import * as path from "path";
5
+ import $RefParser from "@apidevtools/json-schema-ref-parser";
6
+
7
+ // libs/mcp-from-openapi/src/types.ts
8
+ function isReferenceObject(obj) {
9
+ return obj && typeof obj === "object" && "$ref" in obj;
10
+ }
11
+ function toJsonSchema(schema) {
12
+ if (isReferenceObject(schema)) {
13
+ return { $ref: schema.$ref };
14
+ }
15
+ const { exclusiveMaximum, exclusiveMinimum, maximum, minimum, ...rest } = schema;
16
+ const result = { ...rest };
17
+ if (typeof exclusiveMaximum === "boolean") {
18
+ if (exclusiveMaximum && maximum !== void 0) {
19
+ result["exclusiveMaximum"] = maximum;
20
+ } else if (maximum !== void 0) {
21
+ result["maximum"] = maximum;
22
+ }
23
+ } else if (exclusiveMaximum !== void 0) {
24
+ result["exclusiveMaximum"] = exclusiveMaximum;
25
+ if (maximum !== void 0) {
26
+ result["maximum"] = maximum;
27
+ }
28
+ } else if (maximum !== void 0) {
29
+ result["maximum"] = maximum;
30
+ }
31
+ if (typeof exclusiveMinimum === "boolean") {
32
+ if (exclusiveMinimum && minimum !== void 0) {
33
+ result["exclusiveMinimum"] = minimum;
34
+ } else if (minimum !== void 0) {
35
+ result["minimum"] = minimum;
36
+ }
37
+ } else if (exclusiveMinimum !== void 0) {
38
+ result["exclusiveMinimum"] = exclusiveMinimum;
39
+ if (minimum !== void 0) {
40
+ result["minimum"] = minimum;
41
+ }
42
+ } else if (minimum !== void 0) {
43
+ result["minimum"] = minimum;
44
+ }
45
+ if (result["properties"] && typeof result["properties"] === "object") {
46
+ const props = {};
47
+ for (const [key, value] of Object.entries(result["properties"])) {
48
+ props[key] = toJsonSchema(value);
49
+ }
50
+ result["properties"] = props;
51
+ }
52
+ if (result["items"]) {
53
+ if (Array.isArray(result["items"])) {
54
+ result["items"] = result["items"].map(toJsonSchema);
55
+ } else {
56
+ result["items"] = toJsonSchema(result["items"]);
57
+ }
58
+ }
59
+ if (result["additionalProperties"] && typeof result["additionalProperties"] === "object") {
60
+ result["additionalProperties"] = toJsonSchema(result["additionalProperties"]);
61
+ }
62
+ for (const key of ["allOf", "anyOf", "oneOf"]) {
63
+ if (result[key] && Array.isArray(result[key])) {
64
+ result[key] = result[key].map(toJsonSchema);
65
+ }
66
+ }
67
+ if (result["not"]) {
68
+ result["not"] = toJsonSchema(result["not"]);
69
+ }
70
+ return result;
71
+ }
72
+
73
+ // libs/mcp-from-openapi/src/parameter-resolver.ts
74
+ var ParameterResolver = class {
75
+ namingStrategy;
76
+ constructor(namingStrategy) {
77
+ this.namingStrategy = namingStrategy ?? {
78
+ conflictResolver: this.defaultConflictResolver
79
+ };
80
+ }
81
+ /**
82
+ * Default conflict resolver: prefix with location
83
+ */
84
+ defaultConflictResolver(paramName, location, index) {
85
+ const locationPrefix = {
86
+ path: "path",
87
+ query: "query",
88
+ header: "header",
89
+ cookie: "cookie",
90
+ body: "body"
91
+ }[location];
92
+ return `${locationPrefix}${paramName.charAt(0).toUpperCase()}${paramName.slice(1)}`;
93
+ }
94
+ /**
95
+ * Resolve all parameters for an operation
96
+ */
97
+ resolve(operation, pathParameters, securityRequirements, includeSecurityInInput) {
98
+ const allParameters = [...pathParameters ?? [], ...operation.parameters ?? []];
99
+ const requestBody = operation.requestBody;
100
+ const parametersByName = /* @__PURE__ */ new Map();
101
+ allParameters.forEach((param) => {
102
+ const info = {
103
+ name: param.name,
104
+ location: param.in,
105
+ required: param.required ?? param.in === "path",
106
+ schema: param.schema ?? { type: "string" },
107
+ description: param.description,
108
+ style: param.style,
109
+ explode: param.explode,
110
+ allowReserved: param.allowReserved,
111
+ deprecated: param.deprecated
112
+ };
113
+ if (!parametersByName.has(param.name)) {
114
+ parametersByName.set(param.name, []);
115
+ }
116
+ parametersByName.get(param.name).push(info);
117
+ });
118
+ if (requestBody?.content) {
119
+ const contentType = this.selectContentType(requestBody.content);
120
+ const mediaType = requestBody.content[contentType];
121
+ if (mediaType?.schema) {
122
+ this.extractBodyParameters(mediaType.schema, parametersByName, requestBody.required ?? false, contentType);
123
+ }
124
+ }
125
+ const properties = {};
126
+ const required = [];
127
+ const mapper = [];
128
+ for (const [originalName, params] of parametersByName.entries()) {
129
+ if (params.length === 1) {
130
+ const param = params[0];
131
+ const inputKey = originalName;
132
+ properties[inputKey] = this.buildParameterSchema(param);
133
+ if (param.required) {
134
+ required.push(inputKey);
135
+ }
136
+ mapper.push({
137
+ inputKey,
138
+ type: param.location,
139
+ key: originalName,
140
+ required: param.required,
141
+ style: param.style,
142
+ explode: param.explode,
143
+ serialization: param.serialization
144
+ });
145
+ } else {
146
+ params.forEach((param, index) => {
147
+ const inputKey = this.namingStrategy.conflictResolver(originalName, param.location, index);
148
+ properties[inputKey] = this.buildParameterSchema(param);
149
+ if (param.required) {
150
+ required.push(inputKey);
151
+ }
152
+ mapper.push({
153
+ inputKey,
154
+ type: param.location,
155
+ key: originalName,
156
+ required: param.required,
157
+ style: param.style,
158
+ explode: param.explode,
159
+ serialization: param.serialization
160
+ });
161
+ });
162
+ }
163
+ }
164
+ if (securityRequirements && securityRequirements.length > 0) {
165
+ this.processSecurityRequirements(
166
+ securityRequirements,
167
+ properties,
168
+ required,
169
+ mapper,
170
+ includeSecurityInInput ?? false
171
+ );
172
+ }
173
+ const inputSchema = {
174
+ type: "object",
175
+ properties,
176
+ ...required.length > 0 && { required },
177
+ additionalProperties: false
178
+ };
179
+ return { inputSchema, mapper };
180
+ }
181
+ /**
182
+ * Extract parameters from request body schema
183
+ */
184
+ extractBodyParameters(schema, parametersByName, required, contentType, prefix = "") {
185
+ if (!schema || typeof schema !== "object") return;
186
+ const jsonSchema = toJsonSchema(schema);
187
+ if (jsonSchema.type === "object" && jsonSchema.properties) {
188
+ const requiredFields = new Set(jsonSchema.required ?? []);
189
+ for (const [propName, propSchema] of Object.entries(jsonSchema.properties)) {
190
+ const fullName = prefix ? `${prefix}.${propName}` : propName;
191
+ const isRequired = required && requiredFields.has(propName);
192
+ if (typeof propSchema === "object") {
193
+ const info = {
194
+ name: fullName,
195
+ location: "body",
196
+ required: isRequired,
197
+ schema: propSchema,
198
+ description: propSchema.description,
199
+ serialization: {
200
+ contentType
201
+ }
202
+ };
203
+ if (!parametersByName.has(fullName)) {
204
+ parametersByName.set(fullName, []);
205
+ }
206
+ parametersByName.get(fullName).push(info);
207
+ }
208
+ }
209
+ } else {
210
+ const bodyParamName = prefix || "body";
211
+ const info = {
212
+ name: bodyParamName,
213
+ location: "body",
214
+ required,
215
+ schema,
216
+ serialization: {
217
+ contentType
218
+ }
219
+ };
220
+ if (!parametersByName.has(bodyParamName)) {
221
+ parametersByName.set(bodyParamName, []);
222
+ }
223
+ parametersByName.get(bodyParamName).push(info);
224
+ }
225
+ }
226
+ /**
227
+ * Build JSON Schema for a parameter
228
+ */
229
+ buildParameterSchema(param) {
230
+ const schema = toJsonSchema(param.schema);
231
+ if (param.description) {
232
+ schema.description = param.description;
233
+ }
234
+ if (param.deprecated) {
235
+ schema["deprecated"] = true;
236
+ }
237
+ schema["x-parameter-location"] = param.location;
238
+ if (param.style) {
239
+ schema["x-parameter-style"] = param.style;
240
+ }
241
+ if (param.explode !== void 0) {
242
+ schema["x-parameter-explode"] = param.explode;
243
+ }
244
+ return schema;
245
+ }
246
+ /**
247
+ * Select the most appropriate content type
248
+ */
249
+ selectContentType(content) {
250
+ const preferences = [
251
+ "application/json",
252
+ "application/x-www-form-urlencoded",
253
+ "multipart/form-data",
254
+ "application/xml",
255
+ "text/plain"
256
+ ];
257
+ for (const pref of preferences) {
258
+ if (content[pref]) return pref;
259
+ }
260
+ const firstKey = Object.keys(content)[0];
261
+ if (!firstKey) {
262
+ throw new Error("No content type available in request body");
263
+ }
264
+ return firstKey;
265
+ }
266
+ /**
267
+ * Process security requirements and add to mapper/inputSchema
268
+ */
269
+ processSecurityRequirements(securityRequirements, properties, required, mapper, includeInInput) {
270
+ for (const secReq of securityRequirements) {
271
+ const { scheme, type, name: apiKeyName, in: apiKeyIn, scopes } = secReq;
272
+ const securityInfo = {
273
+ scheme,
274
+ type,
275
+ scopes
276
+ };
277
+ let inputKey;
278
+ let headerKey;
279
+ let paramLocation;
280
+ let description;
281
+ let schema;
282
+ if (type === "http") {
283
+ inputKey = scheme;
284
+ headerKey = "Authorization";
285
+ paramLocation = "header";
286
+ const httpScheme = "httpScheme" in secReq && secReq.httpScheme ? secReq.httpScheme : "bearer";
287
+ const bearerFormat = "bearerFormat" in secReq ? secReq.bearerFormat : void 0;
288
+ securityInfo.httpScheme = httpScheme;
289
+ if (bearerFormat) {
290
+ securityInfo.bearerFormat = bearerFormat;
291
+ }
292
+ description = `${httpScheme.charAt(0).toUpperCase()}${httpScheme.slice(1)} authentication token`;
293
+ if (bearerFormat) {
294
+ description += ` (${bearerFormat})`;
295
+ }
296
+ schema = {
297
+ type: "string",
298
+ description
299
+ };
300
+ } else if (type === "apiKey") {
301
+ inputKey = scheme;
302
+ headerKey = apiKeyName || "X-API-Key";
303
+ paramLocation = apiKeyIn || "header";
304
+ securityInfo.apiKeyName = apiKeyName;
305
+ securityInfo.apiKeyIn = apiKeyIn;
306
+ description = `API key for ${scheme}`;
307
+ schema = {
308
+ type: "string",
309
+ description
310
+ };
311
+ } else if (type === "oauth2" || type === "openIdConnect") {
312
+ inputKey = scheme;
313
+ headerKey = "Authorization";
314
+ paramLocation = "header";
315
+ description = `OAuth2 access token${scopes && scopes.length > 0 ? ` (scopes: ${scopes.join(", ")})` : ""}`;
316
+ schema = {
317
+ type: "string",
318
+ description
319
+ };
320
+ } else {
321
+ continue;
322
+ }
323
+ mapper.push({
324
+ inputKey,
325
+ type: paramLocation,
326
+ key: headerKey,
327
+ required: true,
328
+ security: securityInfo
329
+ });
330
+ if (includeInInput) {
331
+ properties[inputKey] = schema;
332
+ required.push(inputKey);
333
+ }
334
+ }
335
+ }
336
+ };
337
+
338
+ // libs/mcp-from-openapi/src/response-builder.ts
339
+ var ResponseBuilder = class {
340
+ preferredStatusCodes;
341
+ includeAllResponses;
342
+ constructor(options = {}) {
343
+ this.preferredStatusCodes = options.preferredStatusCodes ?? [200, 201, 204, 202, 203, 206];
344
+ this.includeAllResponses = options.includeAllResponses ?? true;
345
+ }
346
+ /**
347
+ * Build output schema from responses
348
+ */
349
+ build(responses) {
350
+ if (!responses || Object.keys(responses).length === 0) {
351
+ return void 0;
352
+ }
353
+ const schemas = this.extractResponseSchemas(responses);
354
+ if (schemas.length === 0) {
355
+ return void 0;
356
+ }
357
+ if (schemas.length === 1) {
358
+ return schemas[0].schema;
359
+ }
360
+ if (this.includeAllResponses) {
361
+ return {
362
+ oneOf: schemas.map((s) => s.schema),
363
+ description: "Response can be one of multiple status codes"
364
+ };
365
+ } else {
366
+ const preferred = this.selectPreferredSchema(schemas);
367
+ return preferred.schema;
368
+ }
369
+ }
370
+ /**
371
+ * Extract schemas from all responses
372
+ */
373
+ extractResponseSchemas(responses) {
374
+ const schemas = [];
375
+ for (const [statusCode, response] of Object.entries(responses)) {
376
+ if (isReferenceObject(response)) continue;
377
+ if (statusCode === "default") continue;
378
+ const code = parseInt(statusCode, 10);
379
+ if (isNaN(code)) continue;
380
+ const schema = this.extractResponseSchema(response, code);
381
+ if (schema) {
382
+ schemas.push(schema);
383
+ }
384
+ }
385
+ if (schemas.length === 0 && responses["default"]) {
386
+ const defaultResponse = responses["default"];
387
+ if (!isReferenceObject(defaultResponse)) {
388
+ const schema = this.extractResponseSchema(defaultResponse, 0);
389
+ if (schema) {
390
+ schemas.push(schema);
391
+ }
392
+ }
393
+ }
394
+ return schemas;
395
+ }
396
+ /**
397
+ * Extract schema from a single response
398
+ */
399
+ extractResponseSchema(response, statusCode) {
400
+ if (!response.content) {
401
+ return {
402
+ statusCode,
403
+ schema: {
404
+ type: "null",
405
+ description: response.description,
406
+ "x-status-code": statusCode
407
+ }
408
+ };
409
+ }
410
+ const contentType = this.selectContentType(response.content);
411
+ const mediaType = response.content[contentType];
412
+ if (!mediaType?.schema) {
413
+ return null;
414
+ }
415
+ const schema = {
416
+ ...toJsonSchema(mediaType.schema),
417
+ "x-status-code": statusCode
418
+ };
419
+ if (!schema.description && response.description) {
420
+ schema.description = response.description;
421
+ }
422
+ schema["x-content-type"] = contentType;
423
+ return { statusCode, schema };
424
+ }
425
+ /**
426
+ * Select the most appropriate content type
427
+ */
428
+ selectContentType(content) {
429
+ const preferences = [
430
+ "application/json",
431
+ "application/hal+json",
432
+ "application/problem+json",
433
+ "application/xml",
434
+ "text/plain",
435
+ "text/html"
436
+ ];
437
+ for (const pref of preferences) {
438
+ if (content[pref]) return pref;
439
+ }
440
+ return Object.keys(content)[0];
441
+ }
442
+ /**
443
+ * Select the preferred schema based on status code preferences
444
+ */
445
+ selectPreferredSchema(schemas) {
446
+ for (const preferredCode of this.preferredStatusCodes) {
447
+ const found = schemas.find((s) => s.statusCode === preferredCode);
448
+ if (found) return found;
449
+ }
450
+ const success = schemas.find((s) => s.statusCode >= 200 && s.statusCode < 300);
451
+ if (success) return success;
452
+ const redirect = schemas.find((s) => s.statusCode >= 300 && s.statusCode < 400);
453
+ if (redirect) return redirect;
454
+ return schemas[0];
455
+ }
456
+ };
457
+
458
+ // libs/mcp-from-openapi/src/validator.ts
459
+ var Validator = class {
460
+ /**
461
+ * Validate an OpenAPI document
462
+ */
463
+ async validate(document) {
464
+ const errors = [];
465
+ const warnings = [];
466
+ if (!document.openapi) {
467
+ errors.push({
468
+ message: "Missing required field: openapi",
469
+ path: "/openapi",
470
+ code: "MISSING_OPENAPI_VERSION"
471
+ });
472
+ } else if (!this.isValidOpenAPIVersion(document.openapi)) {
473
+ errors.push({
474
+ message: `Unsupported OpenAPI version: ${document.openapi}. Expected 3.0.x or 3.1.x`,
475
+ path: "/openapi",
476
+ code: "INVALID_OPENAPI_VERSION"
477
+ });
478
+ }
479
+ if (!document.info) {
480
+ errors.push({
481
+ message: "Missing required field: info",
482
+ path: "/info",
483
+ code: "MISSING_INFO"
484
+ });
485
+ } else {
486
+ if (!document.info.title) {
487
+ errors.push({
488
+ message: "Missing required field: info.title",
489
+ path: "/info/title",
490
+ code: "MISSING_TITLE"
491
+ });
492
+ }
493
+ if (!document.info.version) {
494
+ errors.push({
495
+ message: "Missing required field: info.version",
496
+ path: "/info/version",
497
+ code: "MISSING_VERSION"
498
+ });
499
+ }
500
+ }
501
+ if (!document.paths || Object.keys(document.paths).length === 0) {
502
+ warnings.push({
503
+ message: "No paths defined in OpenAPI document",
504
+ path: "/paths",
505
+ code: "NO_PATHS"
506
+ });
507
+ } else {
508
+ this.validatePaths(document.paths, errors, warnings);
509
+ }
510
+ if (!document.servers || document.servers.length === 0) {
511
+ warnings.push({
512
+ message: "No servers defined. You may need to provide a baseUrl option.",
513
+ path: "/servers",
514
+ code: "NO_SERVERS"
515
+ });
516
+ }
517
+ if (document.security && !document.components?.securitySchemes) {
518
+ warnings.push({
519
+ message: "Security requirements defined but no security schemes found",
520
+ path: "/security",
521
+ code: "NO_SECURITY_SCHEMES"
522
+ });
523
+ }
524
+ return {
525
+ valid: errors.length === 0,
526
+ errors: errors.length > 0 ? errors : void 0,
527
+ warnings: warnings.length > 0 ? warnings : void 0
528
+ };
529
+ }
530
+ /**
531
+ * Check if OpenAPI version is valid
532
+ */
533
+ isValidOpenAPIVersion(version) {
534
+ return /^3\.[01]\.\d+$/.test(version);
535
+ }
536
+ /**
537
+ * Validate paths
538
+ */
539
+ validatePaths(paths, errors, warnings) {
540
+ for (const [path2, pathItem] of Object.entries(paths)) {
541
+ if (!pathItem) continue;
542
+ if (!path2.startsWith("/")) {
543
+ errors.push({
544
+ message: `Path must start with '/': ${path2}`,
545
+ path: `/paths/${path2}`,
546
+ code: "INVALID_PATH_FORMAT"
547
+ });
548
+ }
549
+ const methods = ["get", "post", "put", "patch", "delete", "head", "options", "trace"];
550
+ let hasOperations = false;
551
+ for (const method of methods) {
552
+ const operation = pathItem[method];
553
+ if (operation) {
554
+ hasOperations = true;
555
+ this.validateOperation(operation, path2, method, errors, warnings);
556
+ }
557
+ }
558
+ if (!hasOperations && !pathItem.$ref) {
559
+ warnings.push({
560
+ message: `Path has no operations: ${path2}`,
561
+ path: `/paths/${path2}`,
562
+ code: "NO_OPERATIONS"
563
+ });
564
+ }
565
+ }
566
+ }
567
+ /**
568
+ * Validate an operation
569
+ */
570
+ validateOperation(operation, path2, method, errors, warnings) {
571
+ const basePath = `/paths/${path2}/${method}`;
572
+ if (!operation.operationId) {
573
+ warnings.push({
574
+ message: `Operation missing operationId: ${method.toUpperCase()} ${path2}`,
575
+ path: `${basePath}/operationId`,
576
+ code: "NO_OPERATION_ID"
577
+ });
578
+ }
579
+ if (!operation.responses || Object.keys(operation.responses).length === 0) {
580
+ errors.push({
581
+ message: `Operation missing responses: ${method.toUpperCase()} ${path2}`,
582
+ path: `${basePath}/responses`,
583
+ code: "NO_RESPONSES"
584
+ });
585
+ }
586
+ if (operation.parameters) {
587
+ this.validateParameters(operation.parameters, path2, method, errors, warnings);
588
+ }
589
+ const pathParams = path2.match(/\{([^}]+)\}/g)?.map((p) => p.slice(1, -1)) ?? [];
590
+ const definedPathParams = new Set(
591
+ operation.parameters?.filter((p) => p.in === "path").map((p) => p.name) ?? []
592
+ );
593
+ for (const param of pathParams) {
594
+ if (!definedPathParams.has(param)) {
595
+ errors.push({
596
+ message: `Path parameter '${param}' not defined in parameters: ${method.toUpperCase()} ${path2}`,
597
+ path: `${basePath}/parameters`,
598
+ code: "MISSING_PATH_PARAMETER"
599
+ });
600
+ }
601
+ }
602
+ }
603
+ /**
604
+ * Validate parameters
605
+ */
606
+ validateParameters(parameters, path2, method, errors, warnings) {
607
+ const basePath = `/paths/${path2}/${method}/parameters`;
608
+ for (let i = 0; i < parameters.length; i++) {
609
+ const param = parameters[i];
610
+ const paramPath = `${basePath}/${i}`;
611
+ if (!param.name) {
612
+ errors.push({
613
+ message: "Parameter missing name",
614
+ path: `${paramPath}/name`,
615
+ code: "MISSING_PARAMETER_NAME"
616
+ });
617
+ }
618
+ if (!param.in) {
619
+ errors.push({
620
+ message: 'Parameter missing "in" field',
621
+ path: `${paramPath}/in`,
622
+ code: "MISSING_PARAMETER_IN"
623
+ });
624
+ } else if (!["path", "query", "header", "cookie"].includes(param.in)) {
625
+ errors.push({
626
+ message: `Invalid parameter location: ${param.in}`,
627
+ path: `${paramPath}/in`,
628
+ code: "INVALID_PARAMETER_IN"
629
+ });
630
+ }
631
+ if (param.in === "path" && !param.required) {
632
+ errors.push({
633
+ message: `Path parameter '${param.name}' must be required`,
634
+ path: `${paramPath}/required`,
635
+ code: "PATH_PARAMETER_NOT_REQUIRED"
636
+ });
637
+ }
638
+ if (!param.schema && !param.content) {
639
+ errors.push({
640
+ message: `Parameter '${param.name}' missing schema or content`,
641
+ path: `${paramPath}`,
642
+ code: "MISSING_PARAMETER_SCHEMA"
643
+ });
644
+ }
645
+ }
646
+ }
647
+ };
648
+
649
+ // libs/mcp-from-openapi/src/errors.ts
650
+ var OpenAPIToolError = class extends Error {
651
+ context;
652
+ constructor(message, context) {
653
+ super(message);
654
+ this.name = this.constructor.name;
655
+ this.context = context;
656
+ if (Error.captureStackTrace) {
657
+ Error.captureStackTrace(this, this.constructor);
658
+ }
659
+ }
660
+ };
661
+ var LoadError = class extends OpenAPIToolError {
662
+ constructor(message, context) {
663
+ super(message, context);
664
+ }
665
+ };
666
+ var ParseError = class extends OpenAPIToolError {
667
+ constructor(message, context) {
668
+ super(message, context);
669
+ }
670
+ };
671
+ var ValidationError = class extends OpenAPIToolError {
672
+ errors;
673
+ constructor(message, context) {
674
+ super(message, context);
675
+ this.errors = context?.["errors"];
676
+ }
677
+ };
678
+ var GenerationError = class extends OpenAPIToolError {
679
+ constructor(message, context) {
680
+ super(message, context);
681
+ }
682
+ };
683
+ var SchemaError = class extends OpenAPIToolError {
684
+ constructor(message, context) {
685
+ super(message, context);
686
+ }
687
+ };
688
+
689
+ // libs/mcp-from-openapi/src/generator.ts
690
+ var OpenAPIToolGenerator = class _OpenAPIToolGenerator {
691
+ document;
692
+ dereferencedDocument;
693
+ options;
694
+ /**
695
+ * Private constructor - use static factory methods to create instances
696
+ */
697
+ constructor(document, options = {}) {
698
+ this.document = document;
699
+ this.options = {
700
+ dereference: options.dereference ?? true,
701
+ baseUrl: options.baseUrl ?? "",
702
+ headers: options.headers ?? {},
703
+ timeout: options.timeout ?? 3e4,
704
+ validate: options.validate ?? true,
705
+ followRedirects: options.followRedirects ?? true
706
+ };
707
+ }
708
+ /**
709
+ * Create generator from a URL
710
+ */
711
+ static async fromURL(url, options = {}) {
712
+ try {
713
+ const controller = new AbortController();
714
+ const timeout = setTimeout(() => controller.abort(), options.timeout ?? 3e4);
715
+ const response = await fetch(url, {
716
+ headers: options.headers,
717
+ signal: controller.signal,
718
+ redirect: options.followRedirects ?? true ? "follow" : "manual"
719
+ });
720
+ clearTimeout(timeout);
721
+ if (!response.ok) {
722
+ throw new LoadError(`Failed to fetch OpenAPI spec from URL: ${response.status} ${response.statusText}`, {
723
+ url,
724
+ status: response.status
725
+ });
726
+ }
727
+ const contentType = response.headers.get("content-type") || "";
728
+ const text = await response.text();
729
+ let document;
730
+ if (contentType.includes("yaml") || contentType.includes("yml") || url.match(/\.ya?ml$/i)) {
731
+ document = yaml.parse(text);
732
+ } else {
733
+ document = JSON.parse(text);
734
+ }
735
+ return new _OpenAPIToolGenerator(document, options);
736
+ } catch (error) {
737
+ if (error instanceof LoadError) {
738
+ throw error;
739
+ }
740
+ const errorMessage = error instanceof Error ? error.message : String(error);
741
+ throw new LoadError(`Failed to load OpenAPI spec from URL: ${errorMessage}`, {
742
+ url,
743
+ originalError: error
744
+ });
745
+ }
746
+ }
747
+ /**
748
+ * Create generator from a file path
749
+ */
750
+ static async fromFile(filePath, options = {}) {
751
+ try {
752
+ const absolutePath = path.isAbsolute(filePath) ? filePath : path.resolve(process.cwd(), filePath);
753
+ const content = await fs.readFile(absolutePath, "utf-8");
754
+ const ext = path.extname(filePath).toLowerCase();
755
+ let document;
756
+ if (ext === ".yaml" || ext === ".yml") {
757
+ document = yaml.parse(content);
758
+ } else if (ext === ".json") {
759
+ document = JSON.parse(content);
760
+ } else {
761
+ try {
762
+ document = JSON.parse(content);
763
+ } catch {
764
+ document = yaml.parse(content);
765
+ }
766
+ }
767
+ return new _OpenAPIToolGenerator(document, options);
768
+ } catch (error) {
769
+ const errorMessage = error instanceof Error ? error.message : String(error);
770
+ throw new LoadError(`Failed to load OpenAPI spec from file: ${errorMessage}`, {
771
+ filePath,
772
+ originalError: error
773
+ });
774
+ }
775
+ }
776
+ /**
777
+ * Create generator from a YAML string
778
+ */
779
+ static async fromYAML(yamlString, options = {}) {
780
+ try {
781
+ const document = yaml.parse(yamlString);
782
+ return new _OpenAPIToolGenerator(document, options);
783
+ } catch (error) {
784
+ const errorMessage = error instanceof Error ? error.message : String(error);
785
+ throw new ParseError(`Failed to parse YAML: ${errorMessage}`, {
786
+ originalError: error
787
+ });
788
+ }
789
+ }
790
+ /**
791
+ * Create generator from a JSON object
792
+ */
793
+ static async fromJSON(json, options = {}) {
794
+ const document = JSON.parse(JSON.stringify(json));
795
+ return new _OpenAPIToolGenerator(document, options);
796
+ }
797
+ /**
798
+ * Get the OpenAPI document
799
+ */
800
+ getDocument() {
801
+ return this.dereferencedDocument ?? this.document;
802
+ }
803
+ /**
804
+ * Validate the OpenAPI document
805
+ */
806
+ async validate() {
807
+ const validator = new Validator();
808
+ return validator.validate(this.document);
809
+ }
810
+ /**
811
+ * Initialize the generator (dereference if needed)
812
+ */
813
+ async initialize() {
814
+ if (this.options.validate) {
815
+ const result = await this.validate();
816
+ if (!result.valid) {
817
+ throw new ParseError("Invalid OpenAPI document", { errors: result.errors });
818
+ }
819
+ }
820
+ if (this.options.dereference && !this.dereferencedDocument) {
821
+ try {
822
+ this.dereferencedDocument = await $RefParser.dereference(
823
+ JSON.parse(JSON.stringify(this.document))
824
+ );
825
+ } catch (error) {
826
+ const errorMessage = error instanceof Error ? error.message : String(error);
827
+ throw new ParseError(`Failed to dereference OpenAPI document: ${errorMessage}`, {
828
+ originalError: error
829
+ });
830
+ }
831
+ }
832
+ }
833
+ /**
834
+ * Generate all tools from the OpenAPI specification
835
+ */
836
+ async generateTools(options = {}) {
837
+ await this.initialize();
838
+ const document = this.getDocument();
839
+ const tools = [];
840
+ if (!document.paths) {
841
+ return tools;
842
+ }
843
+ for (const [pathStr, pathItem] of Object.entries(document.paths)) {
844
+ if (!pathItem || "$ref" in pathItem) continue;
845
+ const methods = ["get", "post", "put", "patch", "delete", "head", "options", "trace"];
846
+ for (const method of methods) {
847
+ const operation = pathItem[method];
848
+ if (!operation) continue;
849
+ if (!this.shouldIncludeOperation(operation, pathStr, method, options)) {
850
+ continue;
851
+ }
852
+ try {
853
+ const tool = await this.generateTool(pathStr, method, options);
854
+ tools.push(tool);
855
+ } catch (error) {
856
+ const errorMessage = error instanceof Error ? error.message : String(error);
857
+ console.warn(`Failed to generate tool for ${method.toUpperCase()} ${pathStr}:`, errorMessage);
858
+ }
859
+ }
860
+ }
861
+ return tools;
862
+ }
863
+ /**
864
+ * Generate a specific tool for a path and method
865
+ */
866
+ async generateTool(pathStr, method, options = {}) {
867
+ await this.initialize();
868
+ const document = this.getDocument();
869
+ if (!document.paths) {
870
+ throw new Error("No paths defined in OpenAPI document");
871
+ }
872
+ const pathItem = document.paths[pathStr];
873
+ const operation = pathItem?.[method.toLowerCase()];
874
+ if (!operation) {
875
+ throw new Error(`Operation not found: ${method.toUpperCase()} ${pathStr}`);
876
+ }
877
+ const parameterResolver = new ParameterResolver(options.namingStrategy);
878
+ let pathParameters = void 0;
879
+ if (pathItem.parameters) {
880
+ pathParameters = pathItem.parameters.filter(
881
+ (p) => !isReferenceObject(p)
882
+ );
883
+ }
884
+ let securityRequirements = void 0;
885
+ const securitySpec = operation.security ?? document.security;
886
+ if (securitySpec) {
887
+ securityRequirements = this.extractSecurityRequirements(securitySpec, document);
888
+ }
889
+ const { inputSchema, mapper } = parameterResolver.resolve(
890
+ operation,
891
+ pathParameters,
892
+ securityRequirements,
893
+ options.includeSecurityInInput
894
+ );
895
+ const responseBuilder = new ResponseBuilder(options);
896
+ const outputSchema = responseBuilder.build(operation.responses);
897
+ const name = this.generateToolName(pathStr, method, operation.operationId, options);
898
+ const description = operation.summary || operation.description || `${method.toUpperCase()} ${pathStr}`;
899
+ const metadata = this.extractMetadata(pathStr, method, operation, document, outputSchema);
900
+ return {
901
+ name,
902
+ description,
903
+ inputSchema,
904
+ outputSchema,
905
+ mapper,
906
+ metadata
907
+ };
908
+ }
909
+ /**
910
+ * Check if an operation should be included
911
+ */
912
+ shouldIncludeOperation(operation, path2, method, options) {
913
+ if (operation.deprecated && !options.includeDeprecated) {
914
+ return false;
915
+ }
916
+ if (options.includeOperations && operation.operationId) {
917
+ if (!options.includeOperations.includes(operation.operationId)) {
918
+ return false;
919
+ }
920
+ }
921
+ if (options.excludeOperations && operation.operationId) {
922
+ if (options.excludeOperations.includes(operation.operationId)) {
923
+ return false;
924
+ }
925
+ }
926
+ if (options.filterFn) {
927
+ return options.filterFn({
928
+ ...operation,
929
+ path: path2,
930
+ method
931
+ });
932
+ }
933
+ return true;
934
+ }
935
+ /**
936
+ * Generate a tool name
937
+ */
938
+ generateToolName(path2, method, operationId, options = {}) {
939
+ if (options.namingStrategy?.toolNameGenerator) {
940
+ return options.namingStrategy.toolNameGenerator(path2, method, operationId);
941
+ }
942
+ if (operationId) {
943
+ return operationId;
944
+ }
945
+ const sanitized = path2.replace(/\{([^}]+)\}/g, "By_$1").replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
946
+ return `${method}_${sanitized}`;
947
+ }
948
+ /**
949
+ * Extract metadata from operation
950
+ */
951
+ extractMetadata(path2, method, operation, document, outputSchema) {
952
+ const metadata = {
953
+ path: path2,
954
+ method,
955
+ operationId: operation.operationId,
956
+ operationSummary: operation.summary,
957
+ operationDescription: operation.description,
958
+ tags: operation.tags,
959
+ deprecated: operation.deprecated
960
+ };
961
+ if (operation.security || document.security) {
962
+ metadata.security = this.extractSecurityRequirements(
963
+ operation.security ?? document.security,
964
+ document
965
+ );
966
+ }
967
+ const servers = operation.servers ?? document.servers;
968
+ if (servers) {
969
+ metadata.servers = servers.map((server) => ({
970
+ url: this.options.baseUrl || server.url,
971
+ description: server.description,
972
+ variables: server.variables
973
+ }));
974
+ } else if (this.options.baseUrl) {
975
+ metadata.servers = [{ url: this.options.baseUrl }];
976
+ }
977
+ const schemaObj = outputSchema;
978
+ if (schemaObj && Array.isArray(schemaObj["oneOf"])) {
979
+ const codes = schemaObj["oneOf"].map((schema) => schema["x-status-code"]).filter((code) => code !== void 0 && code !== null);
980
+ if (codes.length > 0) {
981
+ metadata.responseStatusCodes = codes;
982
+ }
983
+ } else if (schemaObj && schemaObj["x-status-code"] !== void 0 && schemaObj["x-status-code"] !== null) {
984
+ metadata.responseStatusCodes = [schemaObj["x-status-code"]];
985
+ }
986
+ if (operation.externalDocs) {
987
+ metadata.externalDocs = operation.externalDocs;
988
+ }
989
+ const operationWithExt = operation;
990
+ if (operationWithExt["x-frontmcp"]) {
991
+ metadata.frontmcp = operationWithExt["x-frontmcp"];
992
+ }
993
+ return metadata;
994
+ }
995
+ /**
996
+ * Extract security requirements
997
+ */
998
+ extractSecurityRequirements(security, document) {
999
+ if (!security || !document.components?.securitySchemes) {
1000
+ return [];
1001
+ }
1002
+ return security.flatMap(
1003
+ (req) => Object.entries(req).map(([scheme, scopes]) => {
1004
+ const securityScheme = document.components.securitySchemes[scheme];
1005
+ if (isReferenceObject(securityScheme)) {
1006
+ return { scheme, type: "http", scopes };
1007
+ }
1008
+ const apiKeyIn = "in" in securityScheme ? securityScheme.in : void 0;
1009
+ const result = {
1010
+ scheme,
1011
+ type: securityScheme.type,
1012
+ scopes,
1013
+ name: "name" in securityScheme ? securityScheme.name : void 0,
1014
+ in: apiKeyIn && (apiKeyIn === "query" || apiKeyIn === "header" || apiKeyIn === "cookie") ? apiKeyIn : void 0
1015
+ };
1016
+ if (securityScheme.type === "http") {
1017
+ result.httpScheme = "scheme" in securityScheme ? securityScheme.scheme : void 0;
1018
+ result.bearerFormat = "bearerFormat" in securityScheme ? securityScheme.bearerFormat : void 0;
1019
+ }
1020
+ result.description = "description" in securityScheme ? securityScheme.description : void 0;
1021
+ return result;
1022
+ })
1023
+ );
1024
+ }
1025
+ };
1026
+
1027
+ // libs/mcp-from-openapi/src/schema-builder.ts
1028
+ var SchemaBuilder = class {
1029
+ /**
1030
+ * Merge multiple schemas into one
1031
+ */
1032
+ static merge(schemas) {
1033
+ if (schemas.length === 0) {
1034
+ return { type: "object" };
1035
+ }
1036
+ if (schemas.length === 1) {
1037
+ return schemas[0];
1038
+ }
1039
+ const merged = {
1040
+ type: "object",
1041
+ properties: {},
1042
+ required: []
1043
+ };
1044
+ const allRequired = /* @__PURE__ */ new Set();
1045
+ for (const schema of schemas) {
1046
+ if (schema.properties) {
1047
+ merged.properties = {
1048
+ ...merged.properties,
1049
+ ...schema.properties
1050
+ };
1051
+ }
1052
+ if (schema.required) {
1053
+ schema.required.forEach((field) => allRequired.add(field));
1054
+ }
1055
+ }
1056
+ if (allRequired.size > 0) {
1057
+ merged.required = Array.from(allRequired);
1058
+ }
1059
+ return merged;
1060
+ }
1061
+ /**
1062
+ * Create a union schema (oneOf)
1063
+ */
1064
+ static union(schemas) {
1065
+ if (schemas.length === 0) {
1066
+ return {};
1067
+ }
1068
+ if (schemas.length === 1) {
1069
+ return schemas[0];
1070
+ }
1071
+ return {
1072
+ oneOf: schemas
1073
+ };
1074
+ }
1075
+ /**
1076
+ * Deep clone a schema
1077
+ */
1078
+ static clone(schema) {
1079
+ return JSON.parse(JSON.stringify(schema));
1080
+ }
1081
+ /**
1082
+ * Remove $ref from schema (assumes already dereferenced)
1083
+ */
1084
+ static removeRefs(schema) {
1085
+ const cloned = this.clone(schema);
1086
+ this.removeRefsRecursive(cloned);
1087
+ return cloned;
1088
+ }
1089
+ static removeRefsRecursive(obj) {
1090
+ if (!obj || typeof obj !== "object") return;
1091
+ if (obj.$ref) {
1092
+ delete obj.$ref;
1093
+ }
1094
+ for (const key in obj) {
1095
+ if (key in obj) {
1096
+ const value = obj[key];
1097
+ if (value && typeof value === "object") {
1098
+ this.removeRefsRecursive(value);
1099
+ }
1100
+ }
1101
+ }
1102
+ }
1103
+ /**
1104
+ * Add description to schema
1105
+ */
1106
+ static withDescription(schema, description) {
1107
+ return {
1108
+ ...schema,
1109
+ description
1110
+ };
1111
+ }
1112
+ /**
1113
+ * Add example to schema
1114
+ */
1115
+ static withExample(schema, example) {
1116
+ const existingExamples = Array.isArray(schema.examples) ? schema.examples : [];
1117
+ return {
1118
+ ...schema,
1119
+ examples: [...existingExamples, example]
1120
+ };
1121
+ }
1122
+ /**
1123
+ * Add default value to schema
1124
+ */
1125
+ static withDefault(schema, defaultValue) {
1126
+ return {
1127
+ ...schema,
1128
+ default: defaultValue
1129
+ };
1130
+ }
1131
+ /**
1132
+ * Add format to schema
1133
+ */
1134
+ static withFormat(schema, format) {
1135
+ return {
1136
+ ...schema,
1137
+ format
1138
+ };
1139
+ }
1140
+ /**
1141
+ * Add pattern to schema
1142
+ */
1143
+ static withPattern(schema, pattern) {
1144
+ return {
1145
+ ...schema,
1146
+ pattern
1147
+ };
1148
+ }
1149
+ /**
1150
+ * Add enum to schema
1151
+ */
1152
+ static withEnum(schema, values) {
1153
+ return {
1154
+ ...schema,
1155
+ enum: values
1156
+ };
1157
+ }
1158
+ /**
1159
+ * Add minimum/maximum constraints
1160
+ */
1161
+ static withRange(schema, min, max, options = {}) {
1162
+ const result = { ...schema };
1163
+ if (min !== void 0) {
1164
+ if (options.exclusive) {
1165
+ result.exclusiveMinimum = min;
1166
+ } else {
1167
+ result.minimum = min;
1168
+ }
1169
+ }
1170
+ if (max !== void 0) {
1171
+ if (options.exclusive) {
1172
+ result.exclusiveMaximum = max;
1173
+ } else {
1174
+ result.maximum = max;
1175
+ }
1176
+ }
1177
+ return result;
1178
+ }
1179
+ /**
1180
+ * Add minLength/maxLength constraints
1181
+ */
1182
+ static withLength(schema, minLength, maxLength) {
1183
+ const result = { ...schema };
1184
+ if (minLength !== void 0) {
1185
+ result.minLength = minLength;
1186
+ }
1187
+ if (maxLength !== void 0) {
1188
+ result.maxLength = maxLength;
1189
+ }
1190
+ return result;
1191
+ }
1192
+ /**
1193
+ * Create object schema
1194
+ */
1195
+ static object(properties, required) {
1196
+ return {
1197
+ type: "object",
1198
+ properties,
1199
+ ...required && required.length > 0 && { required },
1200
+ additionalProperties: false
1201
+ };
1202
+ }
1203
+ /**
1204
+ * Create array schema
1205
+ */
1206
+ static array(items, constraints) {
1207
+ return {
1208
+ type: "array",
1209
+ items,
1210
+ ...constraints
1211
+ };
1212
+ }
1213
+ /**
1214
+ * Create string schema
1215
+ */
1216
+ static string(constraints) {
1217
+ return {
1218
+ type: "string",
1219
+ ...constraints
1220
+ };
1221
+ }
1222
+ /**
1223
+ * Create number schema
1224
+ */
1225
+ static number(constraints) {
1226
+ return {
1227
+ type: "number",
1228
+ ...constraints
1229
+ };
1230
+ }
1231
+ /**
1232
+ * Create integer schema
1233
+ */
1234
+ static integer(constraints) {
1235
+ return {
1236
+ type: "integer",
1237
+ ...constraints
1238
+ };
1239
+ }
1240
+ /**
1241
+ * Create boolean schema
1242
+ */
1243
+ static boolean() {
1244
+ return {
1245
+ type: "boolean"
1246
+ };
1247
+ }
1248
+ /**
1249
+ * Create null schema
1250
+ */
1251
+ static null() {
1252
+ return {
1253
+ type: "null"
1254
+ };
1255
+ }
1256
+ /**
1257
+ * Flatten nested oneOf/anyOf/allOf schemas
1258
+ */
1259
+ static flatten(schema, maxDepth = 10) {
1260
+ if (maxDepth <= 0) return schema;
1261
+ const cloned = this.clone(schema);
1262
+ if (cloned.oneOf) {
1263
+ const flattened = cloned.oneOf.flatMap((s) => {
1264
+ const sub = this.flatten(s, maxDepth - 1);
1265
+ return sub.oneOf ? sub.oneOf : [sub];
1266
+ });
1267
+ cloned.oneOf = flattened;
1268
+ }
1269
+ if (cloned.anyOf) {
1270
+ const flattened = cloned.anyOf.flatMap((s) => {
1271
+ const sub = this.flatten(s, maxDepth - 1);
1272
+ return sub.anyOf ? sub.anyOf : [sub];
1273
+ });
1274
+ cloned.anyOf = flattened;
1275
+ }
1276
+ if (cloned.allOf) {
1277
+ const flattened = cloned.allOf.flatMap((s) => {
1278
+ const sub = this.flatten(s, maxDepth - 1);
1279
+ return sub.allOf ? sub.allOf : [sub];
1280
+ });
1281
+ cloned.allOf = flattened;
1282
+ }
1283
+ return cloned;
1284
+ }
1285
+ /**
1286
+ * Simplify schema by removing unnecessary fields
1287
+ */
1288
+ static simplify(schema) {
1289
+ const cloned = this.clone(schema);
1290
+ if (Array.isArray(cloned.required) && cloned.required.length === 0) {
1291
+ delete cloned.required;
1292
+ }
1293
+ if (cloned.properties && Object.keys(cloned.properties).length === 0) {
1294
+ delete cloned.properties;
1295
+ }
1296
+ if (Array.isArray(cloned.examples) && cloned.examples.length === 0) {
1297
+ delete cloned.examples;
1298
+ }
1299
+ if (cloned.title && cloned.description && cloned.title === cloned.description) {
1300
+ delete cloned.title;
1301
+ }
1302
+ return cloned;
1303
+ }
1304
+ };
1305
+
1306
+ // libs/mcp-from-openapi/src/security-resolver.ts
1307
+ var SecurityResolver = class {
1308
+ /**
1309
+ * Resolve security parameters from mapper entries
1310
+ *
1311
+ * @param mappers - Parameter mappers from the tool definition
1312
+ * @param context - Security context with auth values or custom resolver
1313
+ * @returns Resolved headers, query params, and cookies with auth applied
1314
+ */
1315
+ async resolve(mappers, context) {
1316
+ const resolved = {
1317
+ headers: {},
1318
+ query: {},
1319
+ cookies: {}
1320
+ };
1321
+ if (context.clientCertificate) {
1322
+ resolved.clientCertificate = context.clientCertificate;
1323
+ }
1324
+ let requiresSignature = false;
1325
+ let signatureScheme;
1326
+ for (const mapper of mappers) {
1327
+ if (!mapper.security) {
1328
+ continue;
1329
+ }
1330
+ if (this.isSignatureBasedAuth(mapper.security)) {
1331
+ requiresSignature = true;
1332
+ signatureScheme = mapper.security.scheme;
1333
+ continue;
1334
+ }
1335
+ const authValue = await this.resolveAuthValue(mapper.security, context);
1336
+ if (!authValue) {
1337
+ continue;
1338
+ }
1339
+ const headerName = mapper.key;
1340
+ if (mapper.type === "header") {
1341
+ resolved.headers[headerName] = authValue;
1342
+ } else if (mapper.type === "query") {
1343
+ resolved.query[headerName] = authValue;
1344
+ } else if (mapper.type === "cookie") {
1345
+ resolved.cookies[headerName] = authValue;
1346
+ }
1347
+ }
1348
+ if (context.cookies) {
1349
+ resolved.cookies = { ...resolved.cookies, ...context.cookies };
1350
+ }
1351
+ if (requiresSignature) {
1352
+ resolved.requiresSignature = true;
1353
+ resolved.signatureInfo = {
1354
+ scheme: signatureScheme || "unknown"
1355
+ };
1356
+ }
1357
+ return resolved;
1358
+ }
1359
+ /**
1360
+ * Check if security scheme requires request signing
1361
+ */
1362
+ isSignatureBasedAuth(security) {
1363
+ const signatureSchemes = ["aws4", "hmac", "signature", "hawk", "custom-signature"];
1364
+ return signatureSchemes.some(
1365
+ (scheme) => security.scheme.toLowerCase().includes(scheme)
1366
+ );
1367
+ }
1368
+ /**
1369
+ * Resolve the actual auth value based on security type
1370
+ */
1371
+ async resolveAuthValue(security, context) {
1372
+ if (context.customResolver) {
1373
+ const customValue = await context.customResolver(security);
1374
+ if (customValue !== void 0) {
1375
+ return customValue;
1376
+ }
1377
+ }
1378
+ if (security.type === "http") {
1379
+ return this.resolveHttpAuth(security, context);
1380
+ } else if (security.type === "apiKey") {
1381
+ return this.resolveApiKey(security, context);
1382
+ } else if (security.type === "oauth2" || security.type === "openIdConnect") {
1383
+ return this.resolveOAuth2(security, context);
1384
+ }
1385
+ return void 0;
1386
+ }
1387
+ /**
1388
+ * Resolve HTTP authentication (bearer, basic, digest, etc.)
1389
+ */
1390
+ resolveHttpAuth(security, context) {
1391
+ const scheme = security.httpScheme?.toLowerCase() || "bearer";
1392
+ switch (scheme) {
1393
+ case "bearer":
1394
+ return this.resolveBearerAuth(context);
1395
+ case "basic":
1396
+ return this.resolveBasicAuth(context);
1397
+ case "digest":
1398
+ return this.resolveDigestAuth(context);
1399
+ case "hoba":
1400
+ case "mutual":
1401
+ case "negotiate":
1402
+ case "vapid":
1403
+ case "scram":
1404
+ return this.resolveCustomHttpScheme(scheme, security, context);
1405
+ default:
1406
+ return void 0;
1407
+ }
1408
+ }
1409
+ /**
1410
+ * Resolve Bearer token authentication
1411
+ */
1412
+ resolveBearerAuth(context) {
1413
+ const token = context.jwt;
1414
+ if (!token) return void 0;
1415
+ return `Bearer ${token}`;
1416
+ }
1417
+ /**
1418
+ * Resolve Basic authentication
1419
+ */
1420
+ resolveBasicAuth(context) {
1421
+ const credentials = context.basic;
1422
+ if (!credentials) return void 0;
1423
+ return `Basic ${credentials}`;
1424
+ }
1425
+ /**
1426
+ * Resolve Digest authentication
1427
+ */
1428
+ resolveDigestAuth(context) {
1429
+ const digest = context.digest;
1430
+ if (!digest) return void 0;
1431
+ const parts = [
1432
+ `username="${digest.username}"`,
1433
+ digest.realm ? `realm="${digest.realm}"` : "",
1434
+ digest.nonce ? `nonce="${digest.nonce}"` : "",
1435
+ digest.uri ? `uri="${digest.uri}"` : "",
1436
+ digest.response ? `response="${digest.response}"` : "",
1437
+ digest.opaque ? `opaque="${digest.opaque}"` : "",
1438
+ digest.qop ? `qop=${digest.qop}` : "",
1439
+ digest.nc ? `nc=${digest.nc}` : "",
1440
+ digest.cnonce ? `cnonce="${digest.cnonce}"` : ""
1441
+ ].filter(Boolean);
1442
+ return `Digest ${parts.join(", ")}`;
1443
+ }
1444
+ /**
1445
+ * Resolve custom HTTP authentication schemes
1446
+ */
1447
+ resolveCustomHttpScheme(scheme, security, context) {
1448
+ const headerKey = security.apiKeyName || `X-${scheme.toUpperCase()}`;
1449
+ if (context.customHeaders?.[headerKey]) {
1450
+ return context.customHeaders[headerKey];
1451
+ }
1452
+ return void 0;
1453
+ }
1454
+ /**
1455
+ * Resolve API key authentication
1456
+ */
1457
+ resolveApiKey(security, context) {
1458
+ if (context.apiKeys && security.apiKeyName) {
1459
+ const key = context.apiKeys[security.apiKeyName];
1460
+ if (key) return key;
1461
+ }
1462
+ if (context.customHeaders && security.apiKeyName) {
1463
+ const header = context.customHeaders[security.apiKeyName];
1464
+ if (header) return header;
1465
+ }
1466
+ return context.apiKey;
1467
+ }
1468
+ /**
1469
+ * Resolve OAuth2/OpenID Connect authentication
1470
+ */
1471
+ resolveOAuth2(security, context) {
1472
+ const token = context.oauth2Token;
1473
+ if (!token) return void 0;
1474
+ return `Bearer ${token}`;
1475
+ }
1476
+ /**
1477
+ * Check if any security requirements are missing from context
1478
+ *
1479
+ * @param mappers - Parameter mappers from the tool definition
1480
+ * @param context - Security context with auth values
1481
+ * @returns Array of missing security scheme names
1482
+ */
1483
+ async checkMissingSecurity(mappers, context) {
1484
+ const missing = [];
1485
+ for (const mapper of mappers) {
1486
+ if (!mapper.security) continue;
1487
+ const authValue = await this.resolveAuthValue(mapper.security, context);
1488
+ if (!authValue) {
1489
+ missing.push(mapper.security.scheme);
1490
+ }
1491
+ }
1492
+ return missing;
1493
+ }
1494
+ /**
1495
+ * Sign a request for signature-based authentication
1496
+ *
1497
+ * Use this when resolved.requiresSignature is true.
1498
+ * This method will call the signatureGenerator from context to sign the request.
1499
+ *
1500
+ * @param mappers - Parameter mappers from the tool definition
1501
+ * @param signatureData - Request data to sign
1502
+ * @param context - Security context with signature generator
1503
+ * @returns Headers with signature added
1504
+ *
1505
+ * @example
1506
+ * ```typescript
1507
+ * const resolved = resolver.resolve(tool.mapper, context);
1508
+ * if (resolved.requiresSignature) {
1509
+ * const signedHeaders = await resolver.signRequest(
1510
+ * tool.mapper,
1511
+ * { method: 'GET', url: 'https://api.example.com/data', headers: resolved.headers },
1512
+ * context
1513
+ * );
1514
+ * // Use signedHeaders in request
1515
+ * }
1516
+ * ```
1517
+ */
1518
+ async signRequest(mappers, signatureData, context) {
1519
+ const headers = { ...signatureData.headers };
1520
+ if (!context.signatureGenerator) {
1521
+ throw new Error("Signature-based auth required but no signatureGenerator provided");
1522
+ }
1523
+ for (const mapper of mappers) {
1524
+ if (!mapper.security || !this.isSignatureBasedAuth(mapper.security)) {
1525
+ continue;
1526
+ }
1527
+ const signature = await context.signatureGenerator(signatureData, mapper.security);
1528
+ if (mapper.type === "header") {
1529
+ headers[mapper.key] = signature;
1530
+ }
1531
+ }
1532
+ return headers;
1533
+ }
1534
+ };
1535
+ function createSecurityContext(auth) {
1536
+ return {
1537
+ ...auth,
1538
+ jwt: auth.jwt,
1539
+ basic: auth.basic,
1540
+ apiKey: auth.apiKey,
1541
+ oauth2Token: auth.oauth2Token,
1542
+ customResolver: auth.customResolver
1543
+ };
1544
+ }
1545
+ export {
1546
+ GenerationError,
1547
+ LoadError,
1548
+ OpenAPIToolError,
1549
+ OpenAPIToolGenerator,
1550
+ ParameterResolver,
1551
+ ParseError,
1552
+ ResponseBuilder,
1553
+ SchemaBuilder,
1554
+ SchemaError,
1555
+ SecurityResolver,
1556
+ ValidationError,
1557
+ Validator,
1558
+ createSecurityContext,
1559
+ isReferenceObject,
1560
+ toJsonSchema
1561
+ };