@frontmcp/adapters 0.5.1 → 0.6.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/package.json +4 -4
- package/src/openapi/README.md +473 -11
- package/src/openapi/openapi.adapter.d.ts +39 -1
- package/src/openapi/openapi.adapter.js +342 -10
- package/src/openapi/openapi.adapter.js.map +1 -1
- package/src/openapi/openapi.frontmcp-schema.d.ts +91 -0
- package/src/openapi/openapi.frontmcp-schema.js +358 -0
- package/src/openapi/openapi.frontmcp-schema.js.map +1 -0
- package/src/openapi/openapi.security.d.ts +7 -7
- package/src/openapi/openapi.security.js +98 -30
- package/src/openapi/openapi.security.js.map +1 -1
- package/src/openapi/openapi.tool.d.ts +3 -1
- package/src/openapi/openapi.tool.js +218 -32
- package/src/openapi/openapi.tool.js.map +1 -1
- package/src/openapi/openapi.types.d.ts +486 -15
- package/src/openapi/openapi.types.js +26 -0
- package/src/openapi/openapi.types.js.map +1 -1
- package/src/openapi/openapi.utils.d.ts +17 -1
- package/src/openapi/openapi.utils.js +133 -30
- package/src/openapi/openapi.utils.js.map +1 -1
|
@@ -5,20 +5,49 @@ const sdk_1 = require("@frontmcp/sdk");
|
|
|
5
5
|
const mcp_from_openapi_1 = require("mcp-from-openapi");
|
|
6
6
|
const openapi_tool_1 = require("./openapi.tool");
|
|
7
7
|
const openapi_security_1 = require("./openapi.security");
|
|
8
|
+
/** Reserved keys that cannot be used as inputKey (prototype pollution protection) */
|
|
9
|
+
const RESERVED_KEYS = ['__proto__', 'constructor', 'prototype'];
|
|
10
|
+
/**
|
|
11
|
+
* Creates a simple console-based logger for use outside the SDK context.
|
|
12
|
+
*/
|
|
13
|
+
function createConsoleLogger(prefix) {
|
|
14
|
+
const formatMessage = (level, msg) => `[${prefix}] ${level}: ${msg}`;
|
|
15
|
+
return {
|
|
16
|
+
verbose: (msg, ...args) => console.debug(formatMessage('VERBOSE', msg), ...args),
|
|
17
|
+
debug: (msg, ...args) => console.debug(formatMessage('DEBUG', msg), ...args),
|
|
18
|
+
info: (msg, ...args) => console.info(formatMessage('INFO', msg), ...args),
|
|
19
|
+
warn: (msg, ...args) => console.warn(formatMessage('WARN', msg), ...args),
|
|
20
|
+
error: (msg, ...args) => console.error(formatMessage('ERROR', msg), ...args),
|
|
21
|
+
child: (childPrefix) => createConsoleLogger(`${prefix}:${childPrefix}`),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
8
24
|
let OpenapiAdapter = class OpenapiAdapter extends sdk_1.DynamicAdapter {
|
|
9
25
|
generator;
|
|
26
|
+
logger;
|
|
10
27
|
options;
|
|
11
28
|
constructor(options) {
|
|
12
29
|
super();
|
|
13
30
|
this.options = options;
|
|
31
|
+
// Use provided logger or create console fallback
|
|
32
|
+
this.logger = options.logger ?? createConsoleLogger(`openapi:${options.name}`);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Receive the SDK logger. Called by the SDK before fetch().
|
|
36
|
+
*/
|
|
37
|
+
setLogger(logger) {
|
|
38
|
+
this.logger = logger;
|
|
14
39
|
}
|
|
15
40
|
async fetch() {
|
|
16
41
|
// Lazy load: Initialize generator on first fetch if not already initialized
|
|
17
42
|
if (!this.generator) {
|
|
18
43
|
this.generator = await this.initializeGenerator();
|
|
19
44
|
}
|
|
45
|
+
// Determine if we need security in input
|
|
46
|
+
// If securitySchemesInInput is set, we need all security in input first, then filter
|
|
47
|
+
const hasPerSchemeControl = this.options.securitySchemesInInput && this.options.securitySchemesInInput.length > 0;
|
|
48
|
+
const includeSecurityInInput = hasPerSchemeControl || (this.options.generateOptions?.includeSecurityInInput ?? false);
|
|
20
49
|
// Generate tools from OpenAPI spec
|
|
21
|
-
|
|
50
|
+
let openapiTools = await this.generator.generateTools({
|
|
22
51
|
includeOperations: this.options.generateOptions?.includeOperations,
|
|
23
52
|
excludeOperations: this.options.generateOptions?.excludeOperations,
|
|
24
53
|
filterFn: this.options.generateOptions?.filterFn,
|
|
@@ -26,20 +55,32 @@ let OpenapiAdapter = class OpenapiAdapter extends sdk_1.DynamicAdapter {
|
|
|
26
55
|
preferredStatusCodes: this.options.generateOptions?.preferredStatusCodes ?? [200, 201, 202, 204],
|
|
27
56
|
includeDeprecated: this.options.generateOptions?.includeDeprecated ?? false,
|
|
28
57
|
includeAllResponses: this.options.generateOptions?.includeAllResponses ?? true,
|
|
29
|
-
includeSecurityInInput:
|
|
58
|
+
includeSecurityInInput: includeSecurityInInput,
|
|
30
59
|
maxSchemaDepth: this.options.generateOptions?.maxSchemaDepth,
|
|
31
60
|
includeExamples: this.options.generateOptions?.includeExamples,
|
|
32
61
|
});
|
|
62
|
+
// If per-scheme control is enabled, filter security inputs
|
|
63
|
+
if (hasPerSchemeControl) {
|
|
64
|
+
openapiTools = openapiTools.map((tool) => this.filterSecuritySchemes(tool));
|
|
65
|
+
}
|
|
33
66
|
// Validate security configuration
|
|
34
67
|
const validation = (0, openapi_security_1.validateSecurityConfiguration)(openapiTools, this.options);
|
|
35
68
|
// Log security information
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
69
|
+
this.logger.info('Security Analysis:');
|
|
70
|
+
this.logger.info(` Security Risk Score: ${validation.securityRiskScore.toUpperCase()}`);
|
|
71
|
+
this.logger.info(` Valid Configuration: ${validation.valid ? 'YES' : 'NO'}`);
|
|
39
72
|
if (validation.warnings.length > 0) {
|
|
40
|
-
|
|
73
|
+
this.logger.info('Messages:');
|
|
41
74
|
validation.warnings.forEach((warning) => {
|
|
42
|
-
|
|
75
|
+
if (warning.startsWith('ERROR:')) {
|
|
76
|
+
this.logger.error(` - ${warning}`);
|
|
77
|
+
}
|
|
78
|
+
else if (warning.startsWith('SECURITY WARNING:')) {
|
|
79
|
+
this.logger.warn(` - ${warning}`);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
this.logger.info(` - ${warning}`);
|
|
83
|
+
}
|
|
43
84
|
});
|
|
44
85
|
}
|
|
45
86
|
// Fail if configuration is invalid and security is required
|
|
@@ -50,7 +91,9 @@ let OpenapiAdapter = class OpenapiAdapter extends sdk_1.DynamicAdapter {
|
|
|
50
91
|
`Add one of the following to your adapter configuration:\n\n` +
|
|
51
92
|
`1. authProviderMapper (recommended):\n` +
|
|
52
93
|
` authProviderMapper: {\n` +
|
|
53
|
-
validation.missingMappings
|
|
94
|
+
validation.missingMappings
|
|
95
|
+
.map((s) => ` '${s}': (authInfo) => authInfo.user?.${s.toLowerCase()}Token,`)
|
|
96
|
+
.join('\n') +
|
|
54
97
|
`\n }\n\n` +
|
|
55
98
|
`2. securityResolver:\n` +
|
|
56
99
|
` securityResolver: (tool, authInfo) => ({ jwt: authInfo.token })\n\n` +
|
|
@@ -59,9 +102,22 @@ let OpenapiAdapter = class OpenapiAdapter extends sdk_1.DynamicAdapter {
|
|
|
59
102
|
`4. Include security in input (NOT recommended for production):\n` +
|
|
60
103
|
` generateOptions: { includeSecurityInInput: true }`);
|
|
61
104
|
}
|
|
62
|
-
|
|
105
|
+
// Apply all transforms to tools
|
|
106
|
+
let transformedTools = openapiTools;
|
|
107
|
+
// 1. Apply description mode (generates description from summary/description)
|
|
108
|
+
if (this.options.descriptionMode && this.options.descriptionMode !== 'summaryOnly') {
|
|
109
|
+
transformedTools = transformedTools.map((tool) => this.applyDescriptionMode(tool));
|
|
110
|
+
}
|
|
111
|
+
// 2. Apply tool transforms (annotations, name, description overrides, etc.)
|
|
112
|
+
if (this.options.toolTransforms) {
|
|
113
|
+
transformedTools = transformedTools.map((tool) => this.applyToolTransforms(tool));
|
|
114
|
+
}
|
|
115
|
+
// 3. Apply input transforms (hide inputs, inject values at runtime)
|
|
116
|
+
if (this.options.inputTransforms) {
|
|
117
|
+
transformedTools = transformedTools.map((tool) => this.applyInputTransforms(tool));
|
|
118
|
+
}
|
|
63
119
|
// Convert OpenAPI tools to FrontMCP tools
|
|
64
|
-
const tools =
|
|
120
|
+
const tools = transformedTools.map((openapiTool) => (0, openapi_tool_1.createOpenApiTool)(openapiTool, this.options, this.logger));
|
|
65
121
|
return { tools };
|
|
66
122
|
}
|
|
67
123
|
/**
|
|
@@ -90,6 +146,282 @@ let OpenapiAdapter = class OpenapiAdapter extends sdk_1.DynamicAdapter {
|
|
|
90
146
|
throw new Error('Either url or spec must be provided in OpenApiAdapterOptions');
|
|
91
147
|
}
|
|
92
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
* Apply description mode to generate description from summary/description
|
|
151
|
+
* @private
|
|
152
|
+
*/
|
|
153
|
+
applyDescriptionMode(tool) {
|
|
154
|
+
const mode = this.options.descriptionMode || 'summaryOnly';
|
|
155
|
+
const metadata = tool.metadata;
|
|
156
|
+
const summary = metadata['operationSummary'];
|
|
157
|
+
const opDescription = metadata['operationDescription'];
|
|
158
|
+
const operationId = metadata['operationId'];
|
|
159
|
+
const method = metadata['method'];
|
|
160
|
+
const path = metadata['path'];
|
|
161
|
+
let description;
|
|
162
|
+
switch (mode) {
|
|
163
|
+
case 'descriptionOnly':
|
|
164
|
+
description = opDescription || summary || `${method.toUpperCase()} ${path}`;
|
|
165
|
+
break;
|
|
166
|
+
case 'combined':
|
|
167
|
+
if (summary && opDescription) {
|
|
168
|
+
description = `${summary}\n\n${opDescription}`;
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
description = summary || opDescription || `${method.toUpperCase()} ${path}`;
|
|
172
|
+
}
|
|
173
|
+
break;
|
|
174
|
+
case 'full': {
|
|
175
|
+
const parts = [];
|
|
176
|
+
if (summary)
|
|
177
|
+
parts.push(summary);
|
|
178
|
+
if (opDescription && opDescription !== summary)
|
|
179
|
+
parts.push(opDescription);
|
|
180
|
+
if (operationId)
|
|
181
|
+
parts.push(`Operation: ${operationId}`);
|
|
182
|
+
parts.push(`${method.toUpperCase()} ${path}`);
|
|
183
|
+
description = parts.join('\n\n');
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
default:
|
|
187
|
+
// 'summaryOnly' - use existing description
|
|
188
|
+
return tool;
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
...tool,
|
|
192
|
+
description,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Collect tool transforms for a specific tool
|
|
197
|
+
* @private
|
|
198
|
+
*/
|
|
199
|
+
collectToolTransforms(tool) {
|
|
200
|
+
const result = {};
|
|
201
|
+
const opts = this.options.toolTransforms;
|
|
202
|
+
if (!opts)
|
|
203
|
+
return result;
|
|
204
|
+
// 1. Apply global transforms
|
|
205
|
+
if (opts.global) {
|
|
206
|
+
Object.assign(result, opts.global);
|
|
207
|
+
if (opts.global.annotations) {
|
|
208
|
+
result.annotations = { ...opts.global.annotations };
|
|
209
|
+
}
|
|
210
|
+
if (opts.global.tags) {
|
|
211
|
+
result.tags = [...opts.global.tags];
|
|
212
|
+
}
|
|
213
|
+
if (opts.global.examples) {
|
|
214
|
+
result.examples = [...opts.global.examples];
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// 2. Apply per-tool transforms (override global)
|
|
218
|
+
if (opts.perTool?.[tool.name]) {
|
|
219
|
+
const perTool = opts.perTool[tool.name];
|
|
220
|
+
if (perTool.name)
|
|
221
|
+
result.name = perTool.name;
|
|
222
|
+
if (perTool.description)
|
|
223
|
+
result.description = perTool.description;
|
|
224
|
+
if (perTool.hideFromDiscovery !== undefined)
|
|
225
|
+
result.hideFromDiscovery = perTool.hideFromDiscovery;
|
|
226
|
+
if (perTool.ui)
|
|
227
|
+
result.ui = perTool.ui;
|
|
228
|
+
if (perTool.annotations) {
|
|
229
|
+
result.annotations = { ...result.annotations, ...perTool.annotations };
|
|
230
|
+
}
|
|
231
|
+
if (perTool.tags) {
|
|
232
|
+
result.tags = [...(result.tags || []), ...perTool.tags];
|
|
233
|
+
}
|
|
234
|
+
if (perTool.examples) {
|
|
235
|
+
result.examples = [...(result.examples || []), ...perTool.examples];
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// 3. Apply generator-produced transforms (override per-tool)
|
|
239
|
+
if (opts.generator) {
|
|
240
|
+
const generated = opts.generator(tool);
|
|
241
|
+
if (generated) {
|
|
242
|
+
if (generated.name)
|
|
243
|
+
result.name = generated.name;
|
|
244
|
+
if (generated.description)
|
|
245
|
+
result.description = generated.description;
|
|
246
|
+
if (generated.hideFromDiscovery !== undefined)
|
|
247
|
+
result.hideFromDiscovery = generated.hideFromDiscovery;
|
|
248
|
+
if (generated.ui)
|
|
249
|
+
result.ui = generated.ui;
|
|
250
|
+
if (generated.annotations) {
|
|
251
|
+
result.annotations = { ...result.annotations, ...generated.annotations };
|
|
252
|
+
}
|
|
253
|
+
if (generated.tags) {
|
|
254
|
+
result.tags = [...(result.tags || []), ...generated.tags];
|
|
255
|
+
}
|
|
256
|
+
if (generated.examples) {
|
|
257
|
+
result.examples = [...(result.examples || []), ...generated.examples];
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return result;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Apply tool transforms to an OpenAPI tool
|
|
265
|
+
* @private
|
|
266
|
+
*/
|
|
267
|
+
applyToolTransforms(tool) {
|
|
268
|
+
const transforms = this.collectToolTransforms(tool);
|
|
269
|
+
if (Object.keys(transforms).length === 0)
|
|
270
|
+
return tool;
|
|
271
|
+
let newName = tool.name;
|
|
272
|
+
let newDescription = tool.description;
|
|
273
|
+
// Apply name transform
|
|
274
|
+
if (transforms.name) {
|
|
275
|
+
newName = typeof transforms.name === 'function' ? transforms.name(tool.name, tool) : transforms.name;
|
|
276
|
+
}
|
|
277
|
+
// Apply description transform
|
|
278
|
+
if (transforms.description) {
|
|
279
|
+
newDescription =
|
|
280
|
+
typeof transforms.description === 'function'
|
|
281
|
+
? transforms.description(tool.description, tool)
|
|
282
|
+
: transforms.description;
|
|
283
|
+
}
|
|
284
|
+
this.logger.debug(`Applied tool transforms to '${tool.name}'`);
|
|
285
|
+
const metadataRecord = tool.metadata;
|
|
286
|
+
const existingAdapter = metadataRecord['adapter'];
|
|
287
|
+
return {
|
|
288
|
+
...tool,
|
|
289
|
+
name: newName,
|
|
290
|
+
description: newDescription,
|
|
291
|
+
metadata: {
|
|
292
|
+
...tool.metadata,
|
|
293
|
+
adapter: {
|
|
294
|
+
...(existingAdapter || {}),
|
|
295
|
+
toolTransform: transforms,
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Collect all input transforms for a specific tool
|
|
302
|
+
* @private
|
|
303
|
+
*/
|
|
304
|
+
collectTransformsForTool(tool) {
|
|
305
|
+
const transforms = [];
|
|
306
|
+
const opts = this.options.inputTransforms;
|
|
307
|
+
if (!opts)
|
|
308
|
+
return transforms;
|
|
309
|
+
// 1. Add global transforms
|
|
310
|
+
if (opts.global) {
|
|
311
|
+
transforms.push(...opts.global);
|
|
312
|
+
}
|
|
313
|
+
// 2. Add per-tool transforms
|
|
314
|
+
if (opts.perTool?.[tool.name]) {
|
|
315
|
+
transforms.push(...opts.perTool[tool.name]);
|
|
316
|
+
}
|
|
317
|
+
// 3. Add generator-produced transforms
|
|
318
|
+
if (opts.generator) {
|
|
319
|
+
transforms.push(...opts.generator(tool));
|
|
320
|
+
}
|
|
321
|
+
return transforms;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Apply input transforms to an OpenAPI tool
|
|
325
|
+
* - Removes transformed inputKeys from the inputSchema
|
|
326
|
+
* - Stores transform metadata for runtime injection
|
|
327
|
+
* @private
|
|
328
|
+
*/
|
|
329
|
+
applyInputTransforms(tool) {
|
|
330
|
+
const transforms = this.collectTransformsForTool(tool);
|
|
331
|
+
if (transforms.length === 0)
|
|
332
|
+
return tool;
|
|
333
|
+
// Validate input keys against reserved keys (prototype pollution protection)
|
|
334
|
+
for (const transform of transforms) {
|
|
335
|
+
if (RESERVED_KEYS.includes(transform.inputKey)) {
|
|
336
|
+
throw new Error(`Invalid inputKey '${transform.inputKey}' in tool '${tool.name}': ` +
|
|
337
|
+
`reserved keys (${RESERVED_KEYS.join(', ')}) cannot be used`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
const transformedInputKeys = new Set(transforms.map((t) => t.inputKey));
|
|
341
|
+
// Clone and modify inputSchema to remove transformed keys
|
|
342
|
+
const inputSchema = tool.inputSchema;
|
|
343
|
+
const properties = inputSchema?.['properties'] || {};
|
|
344
|
+
const required = inputSchema?.['required'] || [];
|
|
345
|
+
// Remove transformed keys from properties
|
|
346
|
+
const newProperties = { ...properties };
|
|
347
|
+
for (const key of transformedInputKeys) {
|
|
348
|
+
delete newProperties[key];
|
|
349
|
+
}
|
|
350
|
+
// Update required array to exclude transformed keys
|
|
351
|
+
const newRequired = required.filter((key) => !transformedInputKeys.has(key));
|
|
352
|
+
this.logger.debug(`Applied ${transforms.length} input transforms to tool '${tool.name}'`);
|
|
353
|
+
const metadataRecord = tool.metadata;
|
|
354
|
+
const existingAdapter = metadataRecord['adapter'];
|
|
355
|
+
return {
|
|
356
|
+
...tool,
|
|
357
|
+
inputSchema: {
|
|
358
|
+
...inputSchema,
|
|
359
|
+
properties: newProperties,
|
|
360
|
+
...(newRequired.length > 0 ? { required: newRequired } : {}),
|
|
361
|
+
},
|
|
362
|
+
// Store transforms in metadata for runtime use
|
|
363
|
+
metadata: {
|
|
364
|
+
...tool.metadata,
|
|
365
|
+
adapter: {
|
|
366
|
+
...(existingAdapter || {}),
|
|
367
|
+
inputTransforms: transforms,
|
|
368
|
+
},
|
|
369
|
+
},
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Filter security schemes in tool input based on securitySchemesInInput option.
|
|
374
|
+
* Removes security inputs that should be resolved from context instead of user input.
|
|
375
|
+
* @private
|
|
376
|
+
*/
|
|
377
|
+
filterSecuritySchemes(tool) {
|
|
378
|
+
const allowedSchemes = new Set(this.options.securitySchemesInInput || []);
|
|
379
|
+
if (allowedSchemes.size === 0)
|
|
380
|
+
return tool;
|
|
381
|
+
// Find security mappers that should NOT be in input (resolved from context)
|
|
382
|
+
const schemesToRemove = new Set();
|
|
383
|
+
const inputKeysToRemove = new Set();
|
|
384
|
+
for (const mapper of tool.mapper) {
|
|
385
|
+
if (mapper.security?.scheme && !allowedSchemes.has(mapper.security.scheme)) {
|
|
386
|
+
schemesToRemove.add(mapper.security.scheme);
|
|
387
|
+
inputKeysToRemove.add(mapper.inputKey);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
if (inputKeysToRemove.size === 0)
|
|
391
|
+
return tool;
|
|
392
|
+
// Remove security inputs from inputSchema
|
|
393
|
+
const inputSchema = tool.inputSchema;
|
|
394
|
+
const properties = inputSchema?.['properties'] || {};
|
|
395
|
+
const required = inputSchema?.['required'] || [];
|
|
396
|
+
const newProperties = { ...properties };
|
|
397
|
+
for (const key of inputKeysToRemove) {
|
|
398
|
+
delete newProperties[key];
|
|
399
|
+
}
|
|
400
|
+
const newRequired = required.filter((key) => !inputKeysToRemove.has(key));
|
|
401
|
+
this.logger.debug(`[${tool.name}] Filtered security schemes from input: ${Array.from(schemesToRemove).join(', ')}. ` +
|
|
402
|
+
`Kept in input: ${Array.from(allowedSchemes)
|
|
403
|
+
.filter((s) => !schemesToRemove.has(s))
|
|
404
|
+
.join(', ') || 'none'}`);
|
|
405
|
+
const metadataRecord = tool.metadata;
|
|
406
|
+
const existingAdapter = metadataRecord['adapter'];
|
|
407
|
+
return {
|
|
408
|
+
...tool,
|
|
409
|
+
inputSchema: {
|
|
410
|
+
...inputSchema,
|
|
411
|
+
properties: newProperties,
|
|
412
|
+
...(newRequired.length > 0 ? { required: newRequired } : {}),
|
|
413
|
+
},
|
|
414
|
+
// Store which security schemes are in input vs context for later resolution
|
|
415
|
+
metadata: {
|
|
416
|
+
...tool.metadata,
|
|
417
|
+
adapter: {
|
|
418
|
+
...(existingAdapter || {}),
|
|
419
|
+
securitySchemesInInput: Array.from(allowedSchemes),
|
|
420
|
+
securitySchemesFromContext: Array.from(schemesToRemove),
|
|
421
|
+
},
|
|
422
|
+
},
|
|
423
|
+
};
|
|
424
|
+
}
|
|
93
425
|
};
|
|
94
426
|
OpenapiAdapter = tslib_1.__decorate([
|
|
95
427
|
(0, sdk_1.Adapter)({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openapi.adapter.js","sourceRoot":"","sources":["../../../src/openapi/openapi.adapter.ts"],"names":[],"mappings":";;;AAAA,uCAAiF;AAEjF,uDAAwD;AACxD,iDAAmD;AACnD,yDAAmE;AAMpD,IAAM,cAAc,GAApB,MAAM,cAAe,SAAQ,oBAAqC;IACvE,SAAS,CAAwB;IAClC,OAAO,CAAwB;IAEtC,YAAY,OAA8B;QACxC,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,4EAA4E;QAC5E,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,IAAI,CAAC,SAAS,GAAG,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACpD,CAAC;QAED,mCAAmC;QACnC,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC;YACtD,iBAAiB,EAAE,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,iBAAiB;YAClE,iBAAiB,EAAE,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,iBAAiB;YAClE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,QAAQ;YAChD,cAAc,EAAE,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,cAAc;YAC5D,oBAAoB,EAAE,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,oBAAoB,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;YAChG,iBAAiB,EAAE,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,iBAAiB,IAAI,KAAK;YAC3E,mBAAmB,EAAE,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,mBAAmB,IAAI,IAAI;YAC9E,sBAAsB,EAAE,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,sBAAsB,IAAI,KAAK;YACrF,cAAc,EAAE,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,cAAc;YAC5D,eAAe,EAAE,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,eAAe;SAC/D,CAAC,CAAC;QAEH,kCAAkC;QAClC,MAAM,UAAU,GAAG,IAAA,gDAA6B,EAAC,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAE7E,2BAA2B;QAC3B,OAAO,CAAC,GAAG,CAAC,uBAAuB,IAAI,CAAC,OAAO,CAAC,IAAI,sBAAsB,CAAC,CAAC;QAC5E,OAAO,CAAC,GAAG,CAAC,0BAA0B,UAAU,CAAC,iBAAiB,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QACpF,OAAO,CAAC,GAAG,CAAC,0BAA0B,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAEzE,IAAI,UAAU,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;YAC7B,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;gBACtC,OAAO,CAAC,GAAG,CAAC,SAAS,OAAO,EAAE,CAAC,CAAC;YAClC,CAAC,CAAC,CAAC;QACL,CAAC;QAED,4DAA4D;QAC5D,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CACb,qBAAqB,IAAI,CAAC,OAAO,CAAC,IAAI,qCAAqC;gBACzE,wDAAwD,UAAU,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM;gBACnG,gGAAgG;gBAChG,6DAA6D;gBAC7D,wCAAwC;gBACxC,4BAA4B;gBAC5B,UAAU,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,mCAAmC,CAAC,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;gBACtH,YAAY;gBACZ,wBAAwB;gBACxB,wEAAwE;gBACxE,kBAAkB;gBAClB,mDAAmD;gBACnD,kEAAkE;gBAClE,sDAAsD,CACzD,CAAC;QACJ,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,6BAA6B;QAE9C,0CAA0C;QAC1C,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAC7C,IAAA,gCAAiB,EAAC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,CAC7C,CAAC;QAEF,OAAO,EAAE,KAAK,EAAE,CAAC;IACnB,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,mBAAmB;QAC/B,IAAI,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC1B,OAAO,MAAM,uCAAoB,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE;gBAC1D,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO;gBAC7B,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,QAAQ,IAAI,IAAI;gBACpD,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,WAAW,IAAI,IAAI;gBAC1D,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO;gBAC1C,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO;gBAC1C,eAAe,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,eAAe;aAC3D,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClC,OAAO,MAAM,uCAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE;gBAC5D,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO;gBAC7B,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,QAAQ,IAAI,IAAI;gBACpD,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,WAAW,IAAI,IAAI;aAC3D,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;QAClF,CAAC;IACH,CAAC;CACF,CAAA;AAlGoB,cAAc;IAJlC,IAAA,aAAO,EAAC;QACP,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,8FAA8F;KAC5G,CAAC;;GACmB,cAAc,CAkGlC;kBAlGoB,cAAc","sourcesContent":["import { Adapter, DynamicAdapter, FrontMcpAdapterResponse } from '@frontmcp/sdk';\nimport { OpenApiAdapterOptions } from './openapi.types';\nimport { OpenAPIToolGenerator } from 'mcp-from-openapi';\nimport { createOpenApiTool } from './openapi.tool';\nimport { validateSecurityConfiguration } from './openapi.security';\n\n@Adapter({\n name: 'openapi',\n description: 'OpenAPI adapter for FrontMCP - Automatically generates MCP tools from OpenAPI specifications',\n})\nexport default class OpenapiAdapter extends DynamicAdapter<OpenApiAdapterOptions> {\n private generator?: OpenAPIToolGenerator;\n public options: OpenApiAdapterOptions;\n\n constructor(options: OpenApiAdapterOptions) {\n super();\n this.options = options;\n }\n\n async fetch(): Promise<FrontMcpAdapterResponse> {\n // Lazy load: Initialize generator on first fetch if not already initialized\n if (!this.generator) {\n this.generator = await this.initializeGenerator();\n }\n\n // Generate tools from OpenAPI spec\n const openapiTools = await this.generator.generateTools({\n includeOperations: this.options.generateOptions?.includeOperations,\n excludeOperations: this.options.generateOptions?.excludeOperations,\n filterFn: this.options.generateOptions?.filterFn,\n namingStrategy: this.options.generateOptions?.namingStrategy,\n preferredStatusCodes: this.options.generateOptions?.preferredStatusCodes ?? [200, 201, 202, 204],\n includeDeprecated: this.options.generateOptions?.includeDeprecated ?? false,\n includeAllResponses: this.options.generateOptions?.includeAllResponses ?? true,\n includeSecurityInInput: this.options.generateOptions?.includeSecurityInInput ?? false,\n maxSchemaDepth: this.options.generateOptions?.maxSchemaDepth,\n includeExamples: this.options.generateOptions?.includeExamples,\n });\n\n // Validate security configuration\n const validation = validateSecurityConfiguration(openapiTools, this.options);\n\n // Log security information\n console.log(`\\n[OpenAPI Adapter: ${this.options.name}] Security Analysis:`);\n console.log(` Security Risk Score: ${validation.securityRiskScore.toUpperCase()}`);\n console.log(` Valid Configuration: ${validation.valid ? 'YES' : 'NO'}`);\n\n if (validation.warnings.length > 0) {\n console.log('\\n Messages:');\n validation.warnings.forEach((warning) => {\n console.log(` - ${warning}`);\n });\n }\n\n // Fail if configuration is invalid and security is required\n if (!validation.valid) {\n throw new Error(\n `[OpenAPI Adapter: ${this.options.name}] Invalid security configuration.\\n` +\n `Missing auth provider mappings for security schemes: ${validation.missingMappings.join(', ')}\\n\\n` +\n `Your OpenAPI spec requires these security schemes, but no auth configuration was provided.\\n\\n` +\n `Add one of the following to your adapter configuration:\\n\\n` +\n `1. authProviderMapper (recommended):\\n` +\n ` authProviderMapper: {\\n` +\n validation.missingMappings.map((s) => ` '${s}': (authInfo) => authInfo.user?.${s.toLowerCase()}Token,`).join('\\n') +\n `\\n }\\n\\n` +\n `2. securityResolver:\\n` +\n ` securityResolver: (tool, authInfo) => ({ jwt: authInfo.token })\\n\\n` +\n `3. staticAuth:\\n` +\n ` staticAuth: { jwt: process.env.API_TOKEN }\\n\\n` +\n `4. Include security in input (NOT recommended for production):\\n` +\n ` generateOptions: { includeSecurityInInput: true }`\n );\n }\n\n console.log(''); // Empty line for readability\n\n // Convert OpenAPI tools to FrontMCP tools\n const tools = openapiTools.map((openapiTool) =>\n createOpenApiTool(openapiTool, this.options)\n );\n\n return { tools };\n }\n\n /**\n * Initialize the OpenAPI tool generator from URL or spec\n * @private\n */\n private async initializeGenerator(): Promise<OpenAPIToolGenerator> {\n if ('url' in this.options) {\n return await OpenAPIToolGenerator.fromURL(this.options.url, {\n baseUrl: this.options.baseUrl,\n validate: this.options.loadOptions?.validate ?? true,\n dereference: this.options.loadOptions?.dereference ?? true,\n headers: this.options.loadOptions?.headers,\n timeout: this.options.loadOptions?.timeout,\n followRedirects: this.options.loadOptions?.followRedirects,\n });\n } else if ('spec' in this.options) {\n return await OpenAPIToolGenerator.fromJSON(this.options.spec, {\n baseUrl: this.options.baseUrl,\n validate: this.options.loadOptions?.validate ?? true,\n dereference: this.options.loadOptions?.dereference ?? true,\n });\n } else {\n throw new Error('Either url or spec must be provided in OpenApiAdapterOptions');\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"openapi.adapter.js","sourceRoot":"","sources":["../../../src/openapi/openapi.adapter.ts"],"names":[],"mappings":"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","sourcesContent":["import { Adapter, DynamicAdapter, FrontMcpAdapterResponse, FrontMcpLogger } from '@frontmcp/sdk';\nimport { OpenApiAdapterOptions, InputTransform, ToolTransform, ExtendedMcpOpenAPITool } from './openapi.types';\nimport { OpenAPIToolGenerator, McpOpenAPITool } from 'mcp-from-openapi';\nimport { createOpenApiTool } from './openapi.tool';\nimport { validateSecurityConfiguration } from './openapi.security';\n\n/** Reserved keys that cannot be used as inputKey (prototype pollution protection) */\nconst RESERVED_KEYS = ['__proto__', 'constructor', 'prototype'];\n\n/**\n * Creates a simple console-based logger for use outside the SDK context.\n */\nfunction createConsoleLogger(prefix: string): FrontMcpLogger {\n const formatMessage = (level: string, msg: string) => `[${prefix}] ${level}: ${msg}`;\n return {\n verbose: (msg: string, ...args: unknown[]) => console.debug(formatMessage('VERBOSE', msg), ...args),\n debug: (msg: string, ...args: unknown[]) => console.debug(formatMessage('DEBUG', msg), ...args),\n info: (msg: string, ...args: unknown[]) => console.info(formatMessage('INFO', msg), ...args),\n warn: (msg: string, ...args: unknown[]) => console.warn(formatMessage('WARN', msg), ...args),\n error: (msg: string, ...args: unknown[]) => console.error(formatMessage('ERROR', msg), ...args),\n child: (childPrefix: string) => createConsoleLogger(`${prefix}:${childPrefix}`),\n };\n}\n\n@Adapter({\n name: 'openapi',\n description: 'OpenAPI adapter for FrontMCP - Automatically generates MCP tools from OpenAPI specifications',\n})\nexport default class OpenapiAdapter extends DynamicAdapter<OpenApiAdapterOptions> {\n private generator?: OpenAPIToolGenerator;\n private logger: FrontMcpLogger;\n public options: OpenApiAdapterOptions;\n\n constructor(options: OpenApiAdapterOptions) {\n super();\n this.options = options;\n // Use provided logger or create console fallback\n this.logger = options.logger ?? createConsoleLogger(`openapi:${options.name}`);\n }\n\n /**\n * Receive the SDK logger. Called by the SDK before fetch().\n */\n setLogger(logger: FrontMcpLogger): void {\n this.logger = logger;\n }\n\n async fetch(): Promise<FrontMcpAdapterResponse> {\n // Lazy load: Initialize generator on first fetch if not already initialized\n if (!this.generator) {\n this.generator = await this.initializeGenerator();\n }\n\n // Determine if we need security in input\n // If securitySchemesInInput is set, we need all security in input first, then filter\n const hasPerSchemeControl = this.options.securitySchemesInInput && this.options.securitySchemesInInput.length > 0;\n const includeSecurityInInput =\n hasPerSchemeControl || (this.options.generateOptions?.includeSecurityInInput ?? false);\n\n // Generate tools from OpenAPI spec\n let openapiTools = await this.generator.generateTools({\n includeOperations: this.options.generateOptions?.includeOperations,\n excludeOperations: this.options.generateOptions?.excludeOperations,\n filterFn: this.options.generateOptions?.filterFn,\n namingStrategy: this.options.generateOptions?.namingStrategy,\n preferredStatusCodes: this.options.generateOptions?.preferredStatusCodes ?? [200, 201, 202, 204],\n includeDeprecated: this.options.generateOptions?.includeDeprecated ?? false,\n includeAllResponses: this.options.generateOptions?.includeAllResponses ?? true,\n includeSecurityInInput: includeSecurityInInput,\n maxSchemaDepth: this.options.generateOptions?.maxSchemaDepth,\n includeExamples: this.options.generateOptions?.includeExamples,\n });\n\n // If per-scheme control is enabled, filter security inputs\n if (hasPerSchemeControl) {\n openapiTools = openapiTools.map((tool) => this.filterSecuritySchemes(tool));\n }\n\n // Validate security configuration\n const validation = validateSecurityConfiguration(openapiTools, this.options);\n\n // Log security information\n this.logger.info('Security Analysis:');\n this.logger.info(` Security Risk Score: ${validation.securityRiskScore.toUpperCase()}`);\n this.logger.info(` Valid Configuration: ${validation.valid ? 'YES' : 'NO'}`);\n\n if (validation.warnings.length > 0) {\n this.logger.info('Messages:');\n validation.warnings.forEach((warning) => {\n if (warning.startsWith('ERROR:')) {\n this.logger.error(` - ${warning}`);\n } else if (warning.startsWith('SECURITY WARNING:')) {\n this.logger.warn(` - ${warning}`);\n } else {\n this.logger.info(` - ${warning}`);\n }\n });\n }\n\n // Fail if configuration is invalid and security is required\n if (!validation.valid) {\n throw new Error(\n `[OpenAPI Adapter: ${this.options.name}] Invalid security configuration.\\n` +\n `Missing auth provider mappings for security schemes: ${validation.missingMappings.join(', ')}\\n\\n` +\n `Your OpenAPI spec requires these security schemes, but no auth configuration was provided.\\n\\n` +\n `Add one of the following to your adapter configuration:\\n\\n` +\n `1. authProviderMapper (recommended):\\n` +\n ` authProviderMapper: {\\n` +\n validation.missingMappings\n .map((s) => ` '${s}': (authInfo) => authInfo.user?.${s.toLowerCase()}Token,`)\n .join('\\n') +\n `\\n }\\n\\n` +\n `2. securityResolver:\\n` +\n ` securityResolver: (tool, authInfo) => ({ jwt: authInfo.token })\\n\\n` +\n `3. staticAuth:\\n` +\n ` staticAuth: { jwt: process.env.API_TOKEN }\\n\\n` +\n `4. Include security in input (NOT recommended for production):\\n` +\n ` generateOptions: { includeSecurityInInput: true }`,\n );\n }\n\n // Apply all transforms to tools\n let transformedTools = openapiTools;\n\n // 1. Apply description mode (generates description from summary/description)\n if (this.options.descriptionMode && this.options.descriptionMode !== 'summaryOnly') {\n transformedTools = transformedTools.map((tool) => this.applyDescriptionMode(tool));\n }\n\n // 2. Apply tool transforms (annotations, name, description overrides, etc.)\n if (this.options.toolTransforms) {\n transformedTools = transformedTools.map((tool) => this.applyToolTransforms(tool));\n }\n\n // 3. Apply input transforms (hide inputs, inject values at runtime)\n if (this.options.inputTransforms) {\n transformedTools = transformedTools.map((tool) => this.applyInputTransforms(tool));\n }\n\n // Convert OpenAPI tools to FrontMCP tools\n const tools = transformedTools.map((openapiTool) => createOpenApiTool(openapiTool, this.options, this.logger));\n\n return { tools };\n }\n\n /**\n * Initialize the OpenAPI tool generator from URL or spec\n * @private\n */\n private async initializeGenerator(): Promise<OpenAPIToolGenerator> {\n if ('url' in this.options) {\n return await OpenAPIToolGenerator.fromURL(this.options.url, {\n baseUrl: this.options.baseUrl,\n validate: this.options.loadOptions?.validate ?? true,\n dereference: this.options.loadOptions?.dereference ?? true,\n headers: this.options.loadOptions?.headers,\n timeout: this.options.loadOptions?.timeout,\n followRedirects: this.options.loadOptions?.followRedirects,\n });\n } else if ('spec' in this.options) {\n return await OpenAPIToolGenerator.fromJSON(this.options.spec, {\n baseUrl: this.options.baseUrl,\n validate: this.options.loadOptions?.validate ?? true,\n dereference: this.options.loadOptions?.dereference ?? true,\n });\n } else {\n throw new Error('Either url or spec must be provided in OpenApiAdapterOptions');\n }\n }\n\n /**\n * Apply description mode to generate description from summary/description\n * @private\n */\n private applyDescriptionMode(tool: McpOpenAPITool): McpOpenAPITool {\n const mode = this.options.descriptionMode || 'summaryOnly';\n const metadata = tool.metadata as unknown as Record<string, unknown>;\n const summary = metadata['operationSummary'] as string | undefined;\n const opDescription = metadata['operationDescription'] as string | undefined;\n const operationId = metadata['operationId'] as string | undefined;\n const method = metadata['method'] as string;\n const path = metadata['path'] as string;\n\n let description: string;\n\n switch (mode) {\n case 'descriptionOnly':\n description = opDescription || summary || `${method.toUpperCase()} ${path}`;\n break;\n case 'combined':\n if (summary && opDescription) {\n description = `${summary}\\n\\n${opDescription}`;\n } else {\n description = summary || opDescription || `${method.toUpperCase()} ${path}`;\n }\n break;\n case 'full': {\n const parts: string[] = [];\n if (summary) parts.push(summary);\n if (opDescription && opDescription !== summary) parts.push(opDescription);\n if (operationId) parts.push(`Operation: ${operationId}`);\n parts.push(`${method.toUpperCase()} ${path}`);\n description = parts.join('\\n\\n');\n break;\n }\n default:\n // 'summaryOnly' - use existing description\n return tool;\n }\n\n return {\n ...tool,\n description,\n };\n }\n\n /**\n * Collect tool transforms for a specific tool\n * @private\n */\n private collectToolTransforms(tool: McpOpenAPITool): ToolTransform {\n const result: ToolTransform = {};\n const opts = this.options.toolTransforms;\n if (!opts) return result;\n\n // 1. Apply global transforms\n if (opts.global) {\n Object.assign(result, opts.global);\n if (opts.global.annotations) {\n result.annotations = { ...opts.global.annotations };\n }\n if (opts.global.tags) {\n result.tags = [...opts.global.tags];\n }\n if (opts.global.examples) {\n result.examples = [...opts.global.examples];\n }\n }\n\n // 2. Apply per-tool transforms (override global)\n if (opts.perTool?.[tool.name]) {\n const perTool = opts.perTool[tool.name];\n if (perTool.name) result.name = perTool.name;\n if (perTool.description) result.description = perTool.description;\n if (perTool.hideFromDiscovery !== undefined) result.hideFromDiscovery = perTool.hideFromDiscovery;\n if (perTool.ui) result.ui = perTool.ui;\n if (perTool.annotations) {\n result.annotations = { ...result.annotations, ...perTool.annotations };\n }\n if (perTool.tags) {\n result.tags = [...(result.tags || []), ...perTool.tags];\n }\n if (perTool.examples) {\n result.examples = [...(result.examples || []), ...perTool.examples];\n }\n }\n\n // 3. Apply generator-produced transforms (override per-tool)\n if (opts.generator) {\n const generated = opts.generator(tool);\n if (generated) {\n if (generated.name) result.name = generated.name;\n if (generated.description) result.description = generated.description;\n if (generated.hideFromDiscovery !== undefined) result.hideFromDiscovery = generated.hideFromDiscovery;\n if (generated.ui) result.ui = generated.ui;\n if (generated.annotations) {\n result.annotations = { ...result.annotations, ...generated.annotations };\n }\n if (generated.tags) {\n result.tags = [...(result.tags || []), ...generated.tags];\n }\n if (generated.examples) {\n result.examples = [...(result.examples || []), ...generated.examples];\n }\n }\n }\n\n return result;\n }\n\n /**\n * Apply tool transforms to an OpenAPI tool\n * @private\n */\n private applyToolTransforms(tool: McpOpenAPITool): McpOpenAPITool {\n const transforms = this.collectToolTransforms(tool);\n if (Object.keys(transforms).length === 0) return tool;\n\n let newName = tool.name;\n let newDescription = tool.description;\n\n // Apply name transform\n if (transforms.name) {\n newName = typeof transforms.name === 'function' ? transforms.name(tool.name, tool) : transforms.name;\n }\n\n // Apply description transform\n if (transforms.description) {\n newDescription =\n typeof transforms.description === 'function'\n ? transforms.description(tool.description, tool)\n : transforms.description;\n }\n\n this.logger.debug(`Applied tool transforms to '${tool.name}'`);\n\n const metadataRecord = tool.metadata as unknown as Record<string, unknown>;\n const existingAdapter = metadataRecord['adapter'] as Record<string, unknown> | undefined;\n return {\n ...tool,\n name: newName,\n description: newDescription,\n metadata: {\n ...tool.metadata,\n adapter: {\n ...(existingAdapter || {}),\n toolTransform: transforms,\n },\n },\n } as ExtendedMcpOpenAPITool;\n }\n\n /**\n * Collect all input transforms for a specific tool\n * @private\n */\n private collectTransformsForTool(tool: McpOpenAPITool): InputTransform[] {\n const transforms: InputTransform[] = [];\n const opts = this.options.inputTransforms;\n if (!opts) return transforms;\n\n // 1. Add global transforms\n if (opts.global) {\n transforms.push(...opts.global);\n }\n\n // 2. Add per-tool transforms\n if (opts.perTool?.[tool.name]) {\n transforms.push(...opts.perTool[tool.name]);\n }\n\n // 3. Add generator-produced transforms\n if (opts.generator) {\n transforms.push(...opts.generator(tool));\n }\n\n return transforms;\n }\n\n /**\n * Apply input transforms to an OpenAPI tool\n * - Removes transformed inputKeys from the inputSchema\n * - Stores transform metadata for runtime injection\n * @private\n */\n private applyInputTransforms(tool: McpOpenAPITool): McpOpenAPITool {\n const transforms = this.collectTransformsForTool(tool);\n if (transforms.length === 0) return tool;\n\n // Validate input keys against reserved keys (prototype pollution protection)\n for (const transform of transforms) {\n if (RESERVED_KEYS.includes(transform.inputKey)) {\n throw new Error(\n `Invalid inputKey '${transform.inputKey}' in tool '${tool.name}': ` +\n `reserved keys (${RESERVED_KEYS.join(', ')}) cannot be used`,\n );\n }\n }\n\n const transformedInputKeys = new Set(transforms.map((t) => t.inputKey));\n\n // Clone and modify inputSchema to remove transformed keys\n const inputSchema = tool.inputSchema as Record<string, unknown>;\n const properties = (inputSchema?.['properties'] as Record<string, unknown>) || {};\n const required = (inputSchema?.['required'] as string[]) || [];\n\n // Remove transformed keys from properties\n const newProperties = { ...properties };\n for (const key of transformedInputKeys) {\n delete newProperties[key];\n }\n\n // Update required array to exclude transformed keys\n const newRequired = required.filter((key) => !transformedInputKeys.has(key));\n\n this.logger.debug(`Applied ${transforms.length} input transforms to tool '${tool.name}'`);\n\n const metadataRecord = tool.metadata as unknown as Record<string, unknown>;\n const existingAdapter = metadataRecord['adapter'] as Record<string, unknown> | undefined;\n return {\n ...tool,\n inputSchema: {\n ...inputSchema,\n properties: newProperties,\n ...(newRequired.length > 0 ? { required: newRequired } : {}),\n },\n // Store transforms in metadata for runtime use\n metadata: {\n ...tool.metadata,\n adapter: {\n ...(existingAdapter || {}),\n inputTransforms: transforms,\n },\n },\n } as ExtendedMcpOpenAPITool;\n }\n\n /**\n * Filter security schemes in tool input based on securitySchemesInInput option.\n * Removes security inputs that should be resolved from context instead of user input.\n * @private\n */\n private filterSecuritySchemes(tool: McpOpenAPITool): McpOpenAPITool {\n const allowedSchemes = new Set(this.options.securitySchemesInInput || []);\n if (allowedSchemes.size === 0) return tool;\n\n // Find security mappers that should NOT be in input (resolved from context)\n const schemesToRemove = new Set<string>();\n const inputKeysToRemove = new Set<string>();\n\n for (const mapper of tool.mapper) {\n if (mapper.security?.scheme && !allowedSchemes.has(mapper.security.scheme)) {\n schemesToRemove.add(mapper.security.scheme);\n inputKeysToRemove.add(mapper.inputKey);\n }\n }\n\n if (inputKeysToRemove.size === 0) return tool;\n\n // Remove security inputs from inputSchema\n const inputSchema = tool.inputSchema as Record<string, unknown>;\n const properties = (inputSchema?.['properties'] as Record<string, unknown>) || {};\n const required = (inputSchema?.['required'] as string[]) || [];\n\n const newProperties = { ...properties };\n for (const key of inputKeysToRemove) {\n delete newProperties[key];\n }\n\n const newRequired = required.filter((key) => !inputKeysToRemove.has(key));\n\n this.logger.debug(\n `[${tool.name}] Filtered security schemes from input: ${Array.from(schemesToRemove).join(', ')}. ` +\n `Kept in input: ${\n Array.from(allowedSchemes)\n .filter((s) => !schemesToRemove.has(s))\n .join(', ') || 'none'\n }`,\n );\n\n const metadataRecord = tool.metadata as unknown as Record<string, unknown>;\n const existingAdapter = metadataRecord['adapter'] as Record<string, unknown> | undefined;\n return {\n ...tool,\n inputSchema: {\n ...inputSchema,\n properties: newProperties,\n ...(newRequired.length > 0 ? { required: newRequired } : {}),\n },\n // Store which security schemes are in input vs context for later resolution\n metadata: {\n ...tool.metadata,\n adapter: {\n ...(existingAdapter || {}),\n securitySchemesInInput: Array.from(allowedSchemes),\n securitySchemesFromContext: Array.from(schemesToRemove),\n },\n },\n } as ExtendedMcpOpenAPITool;\n }\n}\n"]}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod schemas for x-frontmcp OpenAPI extension validation.
|
|
3
|
+
*
|
|
4
|
+
* The x-frontmcp extension allows embedding FrontMCP-specific configuration
|
|
5
|
+
* directly in OpenAPI specs. This module provides versioned schema validation
|
|
6
|
+
* to ensure only valid data is used and invalid fields are warned about.
|
|
7
|
+
*/
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
import type { FrontMcpLogger } from '@frontmcp/sdk';
|
|
10
|
+
/**
|
|
11
|
+
* Current schema version for x-frontmcp extension.
|
|
12
|
+
* Increment when making breaking changes to the schema.
|
|
13
|
+
*/
|
|
14
|
+
export declare const FRONTMCP_SCHEMA_VERSION: "1.0";
|
|
15
|
+
/**
|
|
16
|
+
* Supported schema versions.
|
|
17
|
+
*/
|
|
18
|
+
export declare const SUPPORTED_VERSIONS: readonly ["1.0"];
|
|
19
|
+
export type FrontMcpSchemaVersion = (typeof SUPPORTED_VERSIONS)[number];
|
|
20
|
+
/**
|
|
21
|
+
* Tool annotations schema - hints about tool behavior for AI clients.
|
|
22
|
+
*/
|
|
23
|
+
export declare const FrontMcpAnnotationsSchema: z.ZodObject<{
|
|
24
|
+
title: z.ZodOptional<z.ZodString>;
|
|
25
|
+
readOnlyHint: z.ZodOptional<z.ZodBoolean>;
|
|
26
|
+
destructiveHint: z.ZodOptional<z.ZodBoolean>;
|
|
27
|
+
idempotentHint: z.ZodOptional<z.ZodBoolean>;
|
|
28
|
+
openWorldHint: z.ZodOptional<z.ZodBoolean>;
|
|
29
|
+
}, z.core.$strip>;
|
|
30
|
+
export type FrontMcpAnnotations = z.infer<typeof FrontMcpAnnotationsSchema>;
|
|
31
|
+
/**
|
|
32
|
+
* Cache configuration schema.
|
|
33
|
+
*/
|
|
34
|
+
export declare const FrontMcpCacheSchema: z.ZodObject<{
|
|
35
|
+
ttl: z.ZodOptional<z.ZodNumber>;
|
|
36
|
+
slideWindow: z.ZodOptional<z.ZodBoolean>;
|
|
37
|
+
}, z.core.$strip>;
|
|
38
|
+
export type FrontMcpCache = z.infer<typeof FrontMcpCacheSchema>;
|
|
39
|
+
/**
|
|
40
|
+
* CodeCall plugin configuration schema.
|
|
41
|
+
*/
|
|
42
|
+
export declare const FrontMcpCodeCallSchema: z.ZodObject<{
|
|
43
|
+
enabledInCodeCall: z.ZodOptional<z.ZodBoolean>;
|
|
44
|
+
visibleInListTools: z.ZodOptional<z.ZodBoolean>;
|
|
45
|
+
}, z.core.$strip>;
|
|
46
|
+
export type FrontMcpCodeCall = z.infer<typeof FrontMcpCodeCallSchema>;
|
|
47
|
+
/**
|
|
48
|
+
* Tool usage example schema.
|
|
49
|
+
*/
|
|
50
|
+
export declare const FrontMcpExampleSchema: z.ZodObject<{
|
|
51
|
+
description: z.ZodString;
|
|
52
|
+
input: z.ZodRecord<z.ZodString, z.ZodAny>;
|
|
53
|
+
output: z.ZodOptional<z.ZodAny>;
|
|
54
|
+
}, z.core.$strip>;
|
|
55
|
+
export type FrontMcpExample = z.infer<typeof FrontMcpExampleSchema>;
|
|
56
|
+
/**
|
|
57
|
+
* Validated x-frontmcp extension data.
|
|
58
|
+
* This is the output after schema validation.
|
|
59
|
+
*/
|
|
60
|
+
export interface ValidatedFrontMcpExtension {
|
|
61
|
+
version: FrontMcpSchemaVersion;
|
|
62
|
+
annotations?: FrontMcpAnnotations;
|
|
63
|
+
cache?: FrontMcpCache;
|
|
64
|
+
codecall?: FrontMcpCodeCall;
|
|
65
|
+
tags?: string[];
|
|
66
|
+
hideFromDiscovery?: boolean;
|
|
67
|
+
examples?: FrontMcpExample[];
|
|
68
|
+
}
|
|
69
|
+
export interface FrontMcpValidationResult {
|
|
70
|
+
/** Whether validation succeeded (may still have warnings) */
|
|
71
|
+
success: boolean;
|
|
72
|
+
/** Validated data (only valid fields) */
|
|
73
|
+
data: ValidatedFrontMcpExtension | null;
|
|
74
|
+
/** Validation warnings (invalid fields that were ignored) */
|
|
75
|
+
warnings: string[];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Validate and parse x-frontmcp extension data.
|
|
79
|
+
*
|
|
80
|
+
* This function:
|
|
81
|
+
* 1. Detects the schema version (defaults to current)
|
|
82
|
+
* 2. Validates each field against the appropriate schema
|
|
83
|
+
* 3. Returns only valid fields, ignoring invalid ones
|
|
84
|
+
* 4. Collects warnings for invalid/unknown fields
|
|
85
|
+
*
|
|
86
|
+
* @param rawData - Raw x-frontmcp data from OpenAPI spec
|
|
87
|
+
* @param toolName - Tool name for error context
|
|
88
|
+
* @param logger - Logger for warnings
|
|
89
|
+
* @returns Validation result with valid data and warnings
|
|
90
|
+
*/
|
|
91
|
+
export declare function validateFrontMcpExtension(rawData: unknown, toolName: string, logger: FrontMcpLogger): FrontMcpValidationResult;
|