@frontmcp/adapters 1.9.1 → 1.9.2
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 +121 -23
- package/esm/openapi/index.mjs +121 -23
- package/esm/package.json +6 -6
- package/esm/skills/index.mjs +5 -1
- package/index.js +116 -21
- package/openapi/index.js +116 -21
- package/openapi/openapi.adapter.d.ts +6 -0
- package/openapi/openapi.adapter.d.ts.map +1 -1
- package/openapi/openapi.tool.d.ts.map +1 -1
- package/package.json +6 -6
- package/skills/index.js +5 -1
- package/skills/sources/saas-pull.source.d.ts +2 -0
- package/skills/sources/saas-pull.source.d.ts.map +1 -1
package/esm/index.mjs
CHANGED
|
@@ -10,7 +10,10 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
// libs/adapters/src/openapi/openapi.adapter.ts
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
normalizeSsrfOptions as normalizeSsrfOptions2,
|
|
15
|
+
OpenAPIToolGenerator
|
|
16
|
+
} from "mcp-from-openapi";
|
|
14
17
|
import { Adapter, DynamicAdapter } from "@frontmcp/sdk";
|
|
15
18
|
|
|
16
19
|
// libs/adapters/src/openapi/openapi-spec-poller.ts
|
|
@@ -605,7 +608,7 @@ async function resolveInputSecurity(tool2, input, options, securityResolver) {
|
|
|
605
608
|
|
|
606
609
|
// libs/adapters/src/openapi/openapi.tool.ts
|
|
607
610
|
import { z as z2 } from "@frontmcp/lazy-zod";
|
|
608
|
-
import { tool } from "@frontmcp/sdk";
|
|
611
|
+
import { InvalidInputError, tool } from "@frontmcp/sdk";
|
|
609
612
|
import { isRedirectResponse } from "@frontmcp/utils";
|
|
610
613
|
|
|
611
614
|
// libs/adapters/src/openapi/openapi.frontmcp-schema.ts
|
|
@@ -1005,6 +1008,7 @@ function createOpenApiTool(openapiTool, options, logger) {
|
|
|
1005
1008
|
const frontmcpValidation = validateFrontMcpExtension(metadata.frontmcp, openapiTool.name, logger);
|
|
1006
1009
|
const frontmcpExt = frontmcpValidation.data;
|
|
1007
1010
|
const schemaResult = getZodSchemaFromJsonSchema(openapiTool.inputSchema, openapiTool.name, logger);
|
|
1011
|
+
const argumentCheck = schemaResult.conversionFailed ? void 0 : getZodSchemaFromJsonSchema(toArgumentJsonSchema(openapiTool), openapiTool.name, logger);
|
|
1008
1012
|
let wrappedOutputSchema;
|
|
1009
1013
|
if (openapiTool.outputSchema !== void 0) {
|
|
1010
1014
|
const baseOutputSchema = openapiTool.outputSchema ?? { type: "string" };
|
|
@@ -1022,11 +1026,15 @@ function createOpenApiTool(openapiTool, options, logger) {
|
|
|
1022
1026
|
const toolMetadata = {
|
|
1023
1027
|
id: openapiTool.name,
|
|
1024
1028
|
name: openapiTool.name,
|
|
1029
|
+
...openapiTool.title && { title: openapiTool.title },
|
|
1025
1030
|
description: openapiTool.description,
|
|
1026
1031
|
inputSchema: schemaResult.schema.shape || {},
|
|
1027
1032
|
rawInputSchema: openapiTool.inputSchema,
|
|
1028
1033
|
// Add output schema for tool/list to expose (only if not moved to description)
|
|
1029
|
-
...wrappedOutputSchema && { rawOutputSchema: wrappedOutputSchema }
|
|
1034
|
+
...wrappedOutputSchema && { rawOutputSchema: wrappedOutputSchema },
|
|
1035
|
+
...openapiTool.annotations && { annotations: { ...openapiTool.annotations } },
|
|
1036
|
+
...openapiTool.icons?.length && { icons: openapiTool.icons.map((icon) => ({ ...icon })) },
|
|
1037
|
+
...openapiTool._meta && { _meta: { ...openapiTool._meta } }
|
|
1030
1038
|
};
|
|
1031
1039
|
if (schemaResult.conversionFailed) {
|
|
1032
1040
|
toolMetadata["_schemaConversionFailed"] = true;
|
|
@@ -1034,7 +1042,10 @@ function createOpenApiTool(openapiTool, options, logger) {
|
|
|
1034
1042
|
}
|
|
1035
1043
|
if (frontmcpExt) {
|
|
1036
1044
|
if (frontmcpExt.annotations) {
|
|
1037
|
-
toolMetadata["annotations"] = {
|
|
1045
|
+
toolMetadata["annotations"] = {
|
|
1046
|
+
...toolMetadata["annotations"] || {},
|
|
1047
|
+
...frontmcpExt.annotations
|
|
1048
|
+
};
|
|
1038
1049
|
}
|
|
1039
1050
|
if (frontmcpExt.tags) {
|
|
1040
1051
|
toolMetadata["tags"] = [...frontmcpExt.tags];
|
|
@@ -1074,6 +1085,13 @@ function createOpenApiTool(openapiTool, options, logger) {
|
|
|
1074
1085
|
}
|
|
1075
1086
|
return tool(toolMetadata)(async (input, toolCtx) => {
|
|
1076
1087
|
const ctx = toolCtx.context;
|
|
1088
|
+
if (argumentCheck && !argumentCheck.conversionFailed) {
|
|
1089
|
+
const validation = argumentCheck.schema.safeParse(input);
|
|
1090
|
+
if (!validation.success) {
|
|
1091
|
+
const problems = validation.error.issues.map((issue) => `${issue.path.join(".") || "input"}: ${issue.message}`);
|
|
1092
|
+
throw new InvalidInputError(`Invalid arguments for tool '${openapiTool.name}': ${problems.join("; ")}`);
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1077
1095
|
const transformContext = {
|
|
1078
1096
|
ctx,
|
|
1079
1097
|
env: process.env,
|
|
@@ -1287,6 +1305,64 @@ async function injectTransformedValues(input, transforms, ctx) {
|
|
|
1287
1305
|
}
|
|
1288
1306
|
return result;
|
|
1289
1307
|
}
|
|
1308
|
+
var SUBSCHEMA_KEYWORDS = [
|
|
1309
|
+
"items",
|
|
1310
|
+
"additionalProperties",
|
|
1311
|
+
"not",
|
|
1312
|
+
"if",
|
|
1313
|
+
"then",
|
|
1314
|
+
"else",
|
|
1315
|
+
"contains",
|
|
1316
|
+
"propertyNames",
|
|
1317
|
+
"unevaluatedItems",
|
|
1318
|
+
"unevaluatedProperties"
|
|
1319
|
+
];
|
|
1320
|
+
var SUBSCHEMA_LIST_KEYWORDS = ["allOf", "anyOf", "prefixItems"];
|
|
1321
|
+
var SUBSCHEMA_MAP_KEYWORDS = ["properties", "patternProperties", "dependentSchemas", "$defs", "definitions"];
|
|
1322
|
+
function toArgumentJsonSchema(openapiTool) {
|
|
1323
|
+
const argumentSchema = relaxSchema(openapiTool.inputSchema);
|
|
1324
|
+
const credentialKeys = new Set(
|
|
1325
|
+
openapiTool.mapper.filter((mapper) => mapper.security).map((mapper) => mapper.inputKey)
|
|
1326
|
+
);
|
|
1327
|
+
const required = argumentSchema["required"];
|
|
1328
|
+
if (Array.isArray(required)) {
|
|
1329
|
+
argumentSchema["required"] = required.filter((key) => !credentialKeys.has(key));
|
|
1330
|
+
}
|
|
1331
|
+
return argumentSchema;
|
|
1332
|
+
}
|
|
1333
|
+
function relaxSchema(schema) {
|
|
1334
|
+
if (Array.isArray(schema)) return schema.map(relaxSchema);
|
|
1335
|
+
if (typeof schema !== "object" || schema === null) return schema;
|
|
1336
|
+
const relaxed = { ...schema };
|
|
1337
|
+
delete relaxed["format"];
|
|
1338
|
+
for (const keyword of SUBSCHEMA_KEYWORDS) {
|
|
1339
|
+
if (keyword in relaxed) relaxed[keyword] = relaxSchema(relaxed[keyword]);
|
|
1340
|
+
}
|
|
1341
|
+
for (const keyword of SUBSCHEMA_LIST_KEYWORDS) {
|
|
1342
|
+
const subschemas = relaxed[keyword];
|
|
1343
|
+
if (Array.isArray(subschemas)) relaxed[keyword] = subschemas.map(relaxSchema);
|
|
1344
|
+
}
|
|
1345
|
+
for (const keyword of SUBSCHEMA_MAP_KEYWORDS) {
|
|
1346
|
+
const subschemasByName = relaxed[keyword];
|
|
1347
|
+
if (typeof subschemasByName === "object" && subschemasByName !== null) {
|
|
1348
|
+
relaxed[keyword] = Object.fromEntries(
|
|
1349
|
+
Object.entries(subschemasByName).map(([name, subschema]) => [name, relaxSchema(subschema)])
|
|
1350
|
+
);
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
const exclusiveBranches = relaxed["oneOf"];
|
|
1354
|
+
if (Array.isArray(exclusiveBranches)) {
|
|
1355
|
+
delete relaxed["oneOf"];
|
|
1356
|
+
const branches = exclusiveBranches.map(relaxSchema);
|
|
1357
|
+
if (Array.isArray(relaxed["anyOf"])) {
|
|
1358
|
+
const allOf = Array.isArray(relaxed["allOf"]) ? relaxed["allOf"] : [];
|
|
1359
|
+
relaxed["allOf"] = [...allOf, { anyOf: branches }];
|
|
1360
|
+
} else {
|
|
1361
|
+
relaxed["anyOf"] = branches;
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
return relaxed;
|
|
1365
|
+
}
|
|
1290
1366
|
function getZodSchemaFromJsonSchema(jsonSchema, toolName, logger) {
|
|
1291
1367
|
if (typeof jsonSchema !== "object" || jsonSchema === null) {
|
|
1292
1368
|
logger.warn(`[${toolName}] No valid JSON schema provided, using permissive schema`);
|
|
@@ -1314,6 +1390,18 @@ function getZodSchemaFromJsonSchema(jsonSchema, toolName, logger) {
|
|
|
1314
1390
|
|
|
1315
1391
|
// libs/adapters/src/openapi/openapi.adapter.ts
|
|
1316
1392
|
var RESERVED_KEYS2 = ["__proto__", "constructor", "prototype"];
|
|
1393
|
+
var HTTP_METHODS = ["get", "post", "put", "patch", "delete", "head", "options", "trace"];
|
|
1394
|
+
function normalizeMethods(adapterName, optionName, methods) {
|
|
1395
|
+
return methods?.map((method) => {
|
|
1396
|
+
const lowerMethod = method.toLowerCase();
|
|
1397
|
+
if (!HTTP_METHODS.includes(lowerMethod)) {
|
|
1398
|
+
throw new Error(
|
|
1399
|
+
`[OpenAPI Adapter: ${adapterName}] generateOptions.${optionName} lists "${method}", which is not an HTTP method; use one of ${HTTP_METHODS.join(", ")}.`
|
|
1400
|
+
);
|
|
1401
|
+
}
|
|
1402
|
+
return lowerMethod;
|
|
1403
|
+
});
|
|
1404
|
+
}
|
|
1317
1405
|
function createConsoleLogger(prefix) {
|
|
1318
1406
|
const formatMessage = (level, msg) => `[${prefix}] ${level}: ${msg}`;
|
|
1319
1407
|
return {
|
|
@@ -1332,9 +1420,14 @@ var OpenapiAdapter = class extends DynamicAdapter {
|
|
|
1332
1420
|
poller = null;
|
|
1333
1421
|
updateCallbacks = /* @__PURE__ */ new Set();
|
|
1334
1422
|
rebuildChain = Promise.resolve();
|
|
1423
|
+
methodFilters;
|
|
1335
1424
|
constructor(options) {
|
|
1336
1425
|
super();
|
|
1337
1426
|
this.options = options;
|
|
1427
|
+
this.methodFilters = {
|
|
1428
|
+
includeMethods: normalizeMethods(options.name, "includeMethods", options.generateOptions?.includeMethods),
|
|
1429
|
+
excludeMethods: normalizeMethods(options.name, "excludeMethods", options.generateOptions?.excludeMethods)
|
|
1430
|
+
};
|
|
1338
1431
|
this.logger = options.logger ?? createConsoleLogger(`openapi:${options.name}`);
|
|
1339
1432
|
if (options.polling?.enabled && !("url" in options)) {
|
|
1340
1433
|
throw new Error(
|
|
@@ -1358,6 +1451,8 @@ var OpenapiAdapter = class extends DynamicAdapter {
|
|
|
1358
1451
|
const generateOptions = this.options.generateOptions;
|
|
1359
1452
|
let openapiTools = await this.generator.generateTools({
|
|
1360
1453
|
...generateOptions,
|
|
1454
|
+
...this.methodFilters,
|
|
1455
|
+
filterFn: this.operationFilter(),
|
|
1361
1456
|
preferredStatusCodes: generateOptions?.preferredStatusCodes ?? [200, 201, 202, 204],
|
|
1362
1457
|
includeDeprecated: generateOptions?.includeDeprecated ?? false,
|
|
1363
1458
|
includeAllResponses: generateOptions?.includeAllResponses ?? true,
|
|
@@ -1443,28 +1538,31 @@ var OpenapiAdapter = class extends DynamicAdapter {
|
|
|
1443
1538
|
resolveRefResolution() {
|
|
1444
1539
|
return this.options.loadOptions?.refResolution ?? { allowedProtocols: [] };
|
|
1445
1540
|
}
|
|
1541
|
+
/**
|
|
1542
|
+
* `generateOptions.filterFn`, and with `includeOperations` set, only the operations it names: the
|
|
1543
|
+
* generator lets an operation with no `operationId` through that list.
|
|
1544
|
+
*/
|
|
1545
|
+
operationFilter() {
|
|
1546
|
+
const { includeOperations, filterFn } = this.options.generateOptions ?? {};
|
|
1547
|
+
if (!includeOperations) return filterFn;
|
|
1548
|
+
return (operation) => operation.operationId !== void 0 && includeOperations.includes(operation.operationId) && (filterFn?.(operation) ?? true);
|
|
1549
|
+
}
|
|
1446
1550
|
async initializeGenerator() {
|
|
1447
|
-
const
|
|
1551
|
+
const loadOptions = {
|
|
1552
|
+
...this.options.loadOptions,
|
|
1553
|
+
baseUrl: this.options.baseUrl,
|
|
1554
|
+
validate: this.options.loadOptions?.validate ?? true,
|
|
1555
|
+
dereference: this.options.loadOptions?.dereference ?? true,
|
|
1556
|
+
// SECURITY: do not follow spec-URL redirects by default — a 3xx to an
|
|
1557
|
+
// internal target would otherwise be fetched. With mcp-from-openapi
|
|
1558
|
+
// ≥ 2.5.0 each hop is re-validated; opt in with loadOptions.followRedirects.
|
|
1559
|
+
followRedirects: this.options.loadOptions?.followRedirects ?? false,
|
|
1560
|
+
refResolution: this.resolveRefResolution()
|
|
1561
|
+
};
|
|
1448
1562
|
if ("url" in this.options) {
|
|
1449
|
-
return await OpenAPIToolGenerator.fromURL(this.options.url,
|
|
1450
|
-
baseUrl: this.options.baseUrl,
|
|
1451
|
-
validate: this.options.loadOptions?.validate ?? true,
|
|
1452
|
-
dereference: this.options.loadOptions?.dereference ?? true,
|
|
1453
|
-
headers: this.options.loadOptions?.headers,
|
|
1454
|
-
timeout: this.options.loadOptions?.timeout,
|
|
1455
|
-
// SECURITY: do not follow spec-URL redirects by default — a 3xx to an
|
|
1456
|
-
// internal target would otherwise be fetched. With mcp-from-openapi
|
|
1457
|
-
// ≥ 2.5.0 each hop is re-validated; opt in with loadOptions.followRedirects.
|
|
1458
|
-
followRedirects: this.options.loadOptions?.followRedirects ?? false,
|
|
1459
|
-
refResolution
|
|
1460
|
-
});
|
|
1563
|
+
return await OpenAPIToolGenerator.fromURL(this.options.url, loadOptions);
|
|
1461
1564
|
} else if ("spec" in this.options) {
|
|
1462
|
-
return await OpenAPIToolGenerator.fromJSON(this.options.spec,
|
|
1463
|
-
baseUrl: this.options.baseUrl,
|
|
1464
|
-
validate: this.options.loadOptions?.validate ?? true,
|
|
1465
|
-
dereference: this.options.loadOptions?.dereference ?? true,
|
|
1466
|
-
refResolution
|
|
1467
|
-
});
|
|
1565
|
+
return await OpenAPIToolGenerator.fromJSON(this.options.spec, loadOptions);
|
|
1468
1566
|
} else {
|
|
1469
1567
|
throw new Error("Either url or spec must be provided in OpenApiAdapterOptions");
|
|
1470
1568
|
}
|
package/esm/openapi/index.mjs
CHANGED
|
@@ -10,7 +10,10 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
// libs/adapters/src/openapi/openapi.adapter.ts
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
normalizeSsrfOptions as normalizeSsrfOptions2,
|
|
15
|
+
OpenAPIToolGenerator
|
|
16
|
+
} from "mcp-from-openapi";
|
|
14
17
|
import { Adapter, DynamicAdapter } from "@frontmcp/sdk";
|
|
15
18
|
|
|
16
19
|
// libs/adapters/src/openapi/openapi-spec-poller.ts
|
|
@@ -605,7 +608,7 @@ async function resolveInputSecurity(tool2, input, options, securityResolver) {
|
|
|
605
608
|
|
|
606
609
|
// libs/adapters/src/openapi/openapi.tool.ts
|
|
607
610
|
import { z as z2 } from "@frontmcp/lazy-zod";
|
|
608
|
-
import { tool } from "@frontmcp/sdk";
|
|
611
|
+
import { InvalidInputError, tool } from "@frontmcp/sdk";
|
|
609
612
|
import { isRedirectResponse } from "@frontmcp/utils";
|
|
610
613
|
|
|
611
614
|
// libs/adapters/src/openapi/openapi.frontmcp-schema.ts
|
|
@@ -1005,6 +1008,7 @@ function createOpenApiTool(openapiTool, options, logger) {
|
|
|
1005
1008
|
const frontmcpValidation = validateFrontMcpExtension(metadata.frontmcp, openapiTool.name, logger);
|
|
1006
1009
|
const frontmcpExt = frontmcpValidation.data;
|
|
1007
1010
|
const schemaResult = getZodSchemaFromJsonSchema(openapiTool.inputSchema, openapiTool.name, logger);
|
|
1011
|
+
const argumentCheck = schemaResult.conversionFailed ? void 0 : getZodSchemaFromJsonSchema(toArgumentJsonSchema(openapiTool), openapiTool.name, logger);
|
|
1008
1012
|
let wrappedOutputSchema;
|
|
1009
1013
|
if (openapiTool.outputSchema !== void 0) {
|
|
1010
1014
|
const baseOutputSchema = openapiTool.outputSchema ?? { type: "string" };
|
|
@@ -1022,11 +1026,15 @@ function createOpenApiTool(openapiTool, options, logger) {
|
|
|
1022
1026
|
const toolMetadata = {
|
|
1023
1027
|
id: openapiTool.name,
|
|
1024
1028
|
name: openapiTool.name,
|
|
1029
|
+
...openapiTool.title && { title: openapiTool.title },
|
|
1025
1030
|
description: openapiTool.description,
|
|
1026
1031
|
inputSchema: schemaResult.schema.shape || {},
|
|
1027
1032
|
rawInputSchema: openapiTool.inputSchema,
|
|
1028
1033
|
// Add output schema for tool/list to expose (only if not moved to description)
|
|
1029
|
-
...wrappedOutputSchema && { rawOutputSchema: wrappedOutputSchema }
|
|
1034
|
+
...wrappedOutputSchema && { rawOutputSchema: wrappedOutputSchema },
|
|
1035
|
+
...openapiTool.annotations && { annotations: { ...openapiTool.annotations } },
|
|
1036
|
+
...openapiTool.icons?.length && { icons: openapiTool.icons.map((icon) => ({ ...icon })) },
|
|
1037
|
+
...openapiTool._meta && { _meta: { ...openapiTool._meta } }
|
|
1030
1038
|
};
|
|
1031
1039
|
if (schemaResult.conversionFailed) {
|
|
1032
1040
|
toolMetadata["_schemaConversionFailed"] = true;
|
|
@@ -1034,7 +1042,10 @@ function createOpenApiTool(openapiTool, options, logger) {
|
|
|
1034
1042
|
}
|
|
1035
1043
|
if (frontmcpExt) {
|
|
1036
1044
|
if (frontmcpExt.annotations) {
|
|
1037
|
-
toolMetadata["annotations"] = {
|
|
1045
|
+
toolMetadata["annotations"] = {
|
|
1046
|
+
...toolMetadata["annotations"] || {},
|
|
1047
|
+
...frontmcpExt.annotations
|
|
1048
|
+
};
|
|
1038
1049
|
}
|
|
1039
1050
|
if (frontmcpExt.tags) {
|
|
1040
1051
|
toolMetadata["tags"] = [...frontmcpExt.tags];
|
|
@@ -1074,6 +1085,13 @@ function createOpenApiTool(openapiTool, options, logger) {
|
|
|
1074
1085
|
}
|
|
1075
1086
|
return tool(toolMetadata)(async (input, toolCtx) => {
|
|
1076
1087
|
const ctx = toolCtx.context;
|
|
1088
|
+
if (argumentCheck && !argumentCheck.conversionFailed) {
|
|
1089
|
+
const validation = argumentCheck.schema.safeParse(input);
|
|
1090
|
+
if (!validation.success) {
|
|
1091
|
+
const problems = validation.error.issues.map((issue) => `${issue.path.join(".") || "input"}: ${issue.message}`);
|
|
1092
|
+
throw new InvalidInputError(`Invalid arguments for tool '${openapiTool.name}': ${problems.join("; ")}`);
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1077
1095
|
const transformContext = {
|
|
1078
1096
|
ctx,
|
|
1079
1097
|
env: process.env,
|
|
@@ -1287,6 +1305,64 @@ async function injectTransformedValues(input, transforms, ctx) {
|
|
|
1287
1305
|
}
|
|
1288
1306
|
return result;
|
|
1289
1307
|
}
|
|
1308
|
+
var SUBSCHEMA_KEYWORDS = [
|
|
1309
|
+
"items",
|
|
1310
|
+
"additionalProperties",
|
|
1311
|
+
"not",
|
|
1312
|
+
"if",
|
|
1313
|
+
"then",
|
|
1314
|
+
"else",
|
|
1315
|
+
"contains",
|
|
1316
|
+
"propertyNames",
|
|
1317
|
+
"unevaluatedItems",
|
|
1318
|
+
"unevaluatedProperties"
|
|
1319
|
+
];
|
|
1320
|
+
var SUBSCHEMA_LIST_KEYWORDS = ["allOf", "anyOf", "prefixItems"];
|
|
1321
|
+
var SUBSCHEMA_MAP_KEYWORDS = ["properties", "patternProperties", "dependentSchemas", "$defs", "definitions"];
|
|
1322
|
+
function toArgumentJsonSchema(openapiTool) {
|
|
1323
|
+
const argumentSchema = relaxSchema(openapiTool.inputSchema);
|
|
1324
|
+
const credentialKeys = new Set(
|
|
1325
|
+
openapiTool.mapper.filter((mapper) => mapper.security).map((mapper) => mapper.inputKey)
|
|
1326
|
+
);
|
|
1327
|
+
const required = argumentSchema["required"];
|
|
1328
|
+
if (Array.isArray(required)) {
|
|
1329
|
+
argumentSchema["required"] = required.filter((key) => !credentialKeys.has(key));
|
|
1330
|
+
}
|
|
1331
|
+
return argumentSchema;
|
|
1332
|
+
}
|
|
1333
|
+
function relaxSchema(schema) {
|
|
1334
|
+
if (Array.isArray(schema)) return schema.map(relaxSchema);
|
|
1335
|
+
if (typeof schema !== "object" || schema === null) return schema;
|
|
1336
|
+
const relaxed = { ...schema };
|
|
1337
|
+
delete relaxed["format"];
|
|
1338
|
+
for (const keyword of SUBSCHEMA_KEYWORDS) {
|
|
1339
|
+
if (keyword in relaxed) relaxed[keyword] = relaxSchema(relaxed[keyword]);
|
|
1340
|
+
}
|
|
1341
|
+
for (const keyword of SUBSCHEMA_LIST_KEYWORDS) {
|
|
1342
|
+
const subschemas = relaxed[keyword];
|
|
1343
|
+
if (Array.isArray(subschemas)) relaxed[keyword] = subschemas.map(relaxSchema);
|
|
1344
|
+
}
|
|
1345
|
+
for (const keyword of SUBSCHEMA_MAP_KEYWORDS) {
|
|
1346
|
+
const subschemasByName = relaxed[keyword];
|
|
1347
|
+
if (typeof subschemasByName === "object" && subschemasByName !== null) {
|
|
1348
|
+
relaxed[keyword] = Object.fromEntries(
|
|
1349
|
+
Object.entries(subschemasByName).map(([name, subschema]) => [name, relaxSchema(subschema)])
|
|
1350
|
+
);
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
const exclusiveBranches = relaxed["oneOf"];
|
|
1354
|
+
if (Array.isArray(exclusiveBranches)) {
|
|
1355
|
+
delete relaxed["oneOf"];
|
|
1356
|
+
const branches = exclusiveBranches.map(relaxSchema);
|
|
1357
|
+
if (Array.isArray(relaxed["anyOf"])) {
|
|
1358
|
+
const allOf = Array.isArray(relaxed["allOf"]) ? relaxed["allOf"] : [];
|
|
1359
|
+
relaxed["allOf"] = [...allOf, { anyOf: branches }];
|
|
1360
|
+
} else {
|
|
1361
|
+
relaxed["anyOf"] = branches;
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
return relaxed;
|
|
1365
|
+
}
|
|
1290
1366
|
function getZodSchemaFromJsonSchema(jsonSchema, toolName, logger) {
|
|
1291
1367
|
if (typeof jsonSchema !== "object" || jsonSchema === null) {
|
|
1292
1368
|
logger.warn(`[${toolName}] No valid JSON schema provided, using permissive schema`);
|
|
@@ -1314,6 +1390,18 @@ function getZodSchemaFromJsonSchema(jsonSchema, toolName, logger) {
|
|
|
1314
1390
|
|
|
1315
1391
|
// libs/adapters/src/openapi/openapi.adapter.ts
|
|
1316
1392
|
var RESERVED_KEYS2 = ["__proto__", "constructor", "prototype"];
|
|
1393
|
+
var HTTP_METHODS = ["get", "post", "put", "patch", "delete", "head", "options", "trace"];
|
|
1394
|
+
function normalizeMethods(adapterName, optionName, methods) {
|
|
1395
|
+
return methods?.map((method) => {
|
|
1396
|
+
const lowerMethod = method.toLowerCase();
|
|
1397
|
+
if (!HTTP_METHODS.includes(lowerMethod)) {
|
|
1398
|
+
throw new Error(
|
|
1399
|
+
`[OpenAPI Adapter: ${adapterName}] generateOptions.${optionName} lists "${method}", which is not an HTTP method; use one of ${HTTP_METHODS.join(", ")}.`
|
|
1400
|
+
);
|
|
1401
|
+
}
|
|
1402
|
+
return lowerMethod;
|
|
1403
|
+
});
|
|
1404
|
+
}
|
|
1317
1405
|
function createConsoleLogger(prefix) {
|
|
1318
1406
|
const formatMessage = (level, msg) => `[${prefix}] ${level}: ${msg}`;
|
|
1319
1407
|
return {
|
|
@@ -1332,9 +1420,14 @@ var OpenapiAdapter = class extends DynamicAdapter {
|
|
|
1332
1420
|
poller = null;
|
|
1333
1421
|
updateCallbacks = /* @__PURE__ */ new Set();
|
|
1334
1422
|
rebuildChain = Promise.resolve();
|
|
1423
|
+
methodFilters;
|
|
1335
1424
|
constructor(options) {
|
|
1336
1425
|
super();
|
|
1337
1426
|
this.options = options;
|
|
1427
|
+
this.methodFilters = {
|
|
1428
|
+
includeMethods: normalizeMethods(options.name, "includeMethods", options.generateOptions?.includeMethods),
|
|
1429
|
+
excludeMethods: normalizeMethods(options.name, "excludeMethods", options.generateOptions?.excludeMethods)
|
|
1430
|
+
};
|
|
1338
1431
|
this.logger = options.logger ?? createConsoleLogger(`openapi:${options.name}`);
|
|
1339
1432
|
if (options.polling?.enabled && !("url" in options)) {
|
|
1340
1433
|
throw new Error(
|
|
@@ -1358,6 +1451,8 @@ var OpenapiAdapter = class extends DynamicAdapter {
|
|
|
1358
1451
|
const generateOptions = this.options.generateOptions;
|
|
1359
1452
|
let openapiTools = await this.generator.generateTools({
|
|
1360
1453
|
...generateOptions,
|
|
1454
|
+
...this.methodFilters,
|
|
1455
|
+
filterFn: this.operationFilter(),
|
|
1361
1456
|
preferredStatusCodes: generateOptions?.preferredStatusCodes ?? [200, 201, 202, 204],
|
|
1362
1457
|
includeDeprecated: generateOptions?.includeDeprecated ?? false,
|
|
1363
1458
|
includeAllResponses: generateOptions?.includeAllResponses ?? true,
|
|
@@ -1443,28 +1538,31 @@ var OpenapiAdapter = class extends DynamicAdapter {
|
|
|
1443
1538
|
resolveRefResolution() {
|
|
1444
1539
|
return this.options.loadOptions?.refResolution ?? { allowedProtocols: [] };
|
|
1445
1540
|
}
|
|
1541
|
+
/**
|
|
1542
|
+
* `generateOptions.filterFn`, and with `includeOperations` set, only the operations it names: the
|
|
1543
|
+
* generator lets an operation with no `operationId` through that list.
|
|
1544
|
+
*/
|
|
1545
|
+
operationFilter() {
|
|
1546
|
+
const { includeOperations, filterFn } = this.options.generateOptions ?? {};
|
|
1547
|
+
if (!includeOperations) return filterFn;
|
|
1548
|
+
return (operation) => operation.operationId !== void 0 && includeOperations.includes(operation.operationId) && (filterFn?.(operation) ?? true);
|
|
1549
|
+
}
|
|
1446
1550
|
async initializeGenerator() {
|
|
1447
|
-
const
|
|
1551
|
+
const loadOptions = {
|
|
1552
|
+
...this.options.loadOptions,
|
|
1553
|
+
baseUrl: this.options.baseUrl,
|
|
1554
|
+
validate: this.options.loadOptions?.validate ?? true,
|
|
1555
|
+
dereference: this.options.loadOptions?.dereference ?? true,
|
|
1556
|
+
// SECURITY: do not follow spec-URL redirects by default — a 3xx to an
|
|
1557
|
+
// internal target would otherwise be fetched. With mcp-from-openapi
|
|
1558
|
+
// ≥ 2.5.0 each hop is re-validated; opt in with loadOptions.followRedirects.
|
|
1559
|
+
followRedirects: this.options.loadOptions?.followRedirects ?? false,
|
|
1560
|
+
refResolution: this.resolveRefResolution()
|
|
1561
|
+
};
|
|
1448
1562
|
if ("url" in this.options) {
|
|
1449
|
-
return await OpenAPIToolGenerator.fromURL(this.options.url,
|
|
1450
|
-
baseUrl: this.options.baseUrl,
|
|
1451
|
-
validate: this.options.loadOptions?.validate ?? true,
|
|
1452
|
-
dereference: this.options.loadOptions?.dereference ?? true,
|
|
1453
|
-
headers: this.options.loadOptions?.headers,
|
|
1454
|
-
timeout: this.options.loadOptions?.timeout,
|
|
1455
|
-
// SECURITY: do not follow spec-URL redirects by default — a 3xx to an
|
|
1456
|
-
// internal target would otherwise be fetched. With mcp-from-openapi
|
|
1457
|
-
// ≥ 2.5.0 each hop is re-validated; opt in with loadOptions.followRedirects.
|
|
1458
|
-
followRedirects: this.options.loadOptions?.followRedirects ?? false,
|
|
1459
|
-
refResolution
|
|
1460
|
-
});
|
|
1563
|
+
return await OpenAPIToolGenerator.fromURL(this.options.url, loadOptions);
|
|
1461
1564
|
} else if ("spec" in this.options) {
|
|
1462
|
-
return await OpenAPIToolGenerator.fromJSON(this.options.spec,
|
|
1463
|
-
baseUrl: this.options.baseUrl,
|
|
1464
|
-
validate: this.options.loadOptions?.validate ?? true,
|
|
1465
|
-
dereference: this.options.loadOptions?.dereference ?? true,
|
|
1466
|
-
refResolution
|
|
1467
|
-
});
|
|
1565
|
+
return await OpenAPIToolGenerator.fromJSON(this.options.spec, loadOptions);
|
|
1468
1566
|
} else {
|
|
1469
1567
|
throw new Error("Either url or spec must be provided in OpenApiAdapterOptions");
|
|
1470
1568
|
}
|
package/esm/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/adapters",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.2",
|
|
4
4
|
"description": "Adapters for the FrontMCP framework",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"homepage": "https://docs.agentfront.dev",
|
|
@@ -64,15 +64,15 @@
|
|
|
64
64
|
"node": ">=24.0.0"
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@frontmcp/auth": "1.9.
|
|
68
|
-
"@frontmcp/di": "1.9.
|
|
69
|
-
"@frontmcp/sdk": "1.9.
|
|
70
|
-
"@frontmcp/utils": "1.9.
|
|
67
|
+
"@frontmcp/auth": "1.9.2",
|
|
68
|
+
"@frontmcp/di": "1.9.2",
|
|
69
|
+
"@frontmcp/sdk": "1.9.2",
|
|
70
|
+
"@frontmcp/utils": "1.9.2",
|
|
71
71
|
"js-yaml": "^4.1.0",
|
|
72
72
|
"mcp-from-openapi": "2.8.0",
|
|
73
73
|
"openapi-types": "^12.1.3"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
|
-
"@frontmcp/lazy-zod": "1.9.
|
|
76
|
+
"@frontmcp/lazy-zod": "1.9.2"
|
|
77
77
|
}
|
|
78
78
|
}
|
package/esm/skills/index.mjs
CHANGED
|
@@ -843,7 +843,7 @@ var SaasPullSource = class {
|
|
|
843
843
|
bundle = await this.loadCache();
|
|
844
844
|
if (!bundle) {
|
|
845
845
|
throw new Error(
|
|
846
|
-
`[saas-source] initial pull failed and no cached bundle is available
|
|
846
|
+
`[saas-source] initial pull failed and no cached bundle is available ${this.cacheLocation()}: ${e.message}`,
|
|
847
847
|
{ cause: e }
|
|
848
848
|
);
|
|
849
849
|
}
|
|
@@ -989,6 +989,10 @@ var SaasPullSource = class {
|
|
|
989
989
|
trimmed.startsWith("{") || trimmed.startsWith("[") ? { kind: "json", content: body } : { kind: "yaml", content: body }
|
|
990
990
|
);
|
|
991
991
|
}
|
|
992
|
+
/** Where the last-good bundle is kept, for messages: an injected store (a Worker's KV) has no file path. */
|
|
993
|
+
cacheLocation() {
|
|
994
|
+
return this.deps.cache ? "in the injected bundle cache" : `at ${this.cachePath()}`;
|
|
995
|
+
}
|
|
992
996
|
cachePath() {
|
|
993
997
|
const dir = this.cacheDir ?? DEFAULT_CACHE_DIR;
|
|
994
998
|
return pathResolve(dir, `${this.options.expectedAudience.replace(/[^a-zA-Z0-9_.-]/g, "_")}.json`);
|
package/index.js
CHANGED
|
@@ -1037,6 +1037,7 @@ function createOpenApiTool(openapiTool, options, logger) {
|
|
|
1037
1037
|
const frontmcpValidation = validateFrontMcpExtension(metadata.frontmcp, openapiTool.name, logger);
|
|
1038
1038
|
const frontmcpExt = frontmcpValidation.data;
|
|
1039
1039
|
const schemaResult = getZodSchemaFromJsonSchema(openapiTool.inputSchema, openapiTool.name, logger);
|
|
1040
|
+
const argumentCheck = schemaResult.conversionFailed ? void 0 : getZodSchemaFromJsonSchema(toArgumentJsonSchema(openapiTool), openapiTool.name, logger);
|
|
1040
1041
|
let wrappedOutputSchema;
|
|
1041
1042
|
if (openapiTool.outputSchema !== void 0) {
|
|
1042
1043
|
const baseOutputSchema = openapiTool.outputSchema ?? { type: "string" };
|
|
@@ -1054,11 +1055,15 @@ function createOpenApiTool(openapiTool, options, logger) {
|
|
|
1054
1055
|
const toolMetadata = {
|
|
1055
1056
|
id: openapiTool.name,
|
|
1056
1057
|
name: openapiTool.name,
|
|
1058
|
+
...openapiTool.title && { title: openapiTool.title },
|
|
1057
1059
|
description: openapiTool.description,
|
|
1058
1060
|
inputSchema: schemaResult.schema.shape || {},
|
|
1059
1061
|
rawInputSchema: openapiTool.inputSchema,
|
|
1060
1062
|
// Add output schema for tool/list to expose (only if not moved to description)
|
|
1061
|
-
...wrappedOutputSchema && { rawOutputSchema: wrappedOutputSchema }
|
|
1063
|
+
...wrappedOutputSchema && { rawOutputSchema: wrappedOutputSchema },
|
|
1064
|
+
...openapiTool.annotations && { annotations: { ...openapiTool.annotations } },
|
|
1065
|
+
...openapiTool.icons?.length && { icons: openapiTool.icons.map((icon) => ({ ...icon })) },
|
|
1066
|
+
...openapiTool._meta && { _meta: { ...openapiTool._meta } }
|
|
1062
1067
|
};
|
|
1063
1068
|
if (schemaResult.conversionFailed) {
|
|
1064
1069
|
toolMetadata["_schemaConversionFailed"] = true;
|
|
@@ -1066,7 +1071,10 @@ function createOpenApiTool(openapiTool, options, logger) {
|
|
|
1066
1071
|
}
|
|
1067
1072
|
if (frontmcpExt) {
|
|
1068
1073
|
if (frontmcpExt.annotations) {
|
|
1069
|
-
toolMetadata["annotations"] = {
|
|
1074
|
+
toolMetadata["annotations"] = {
|
|
1075
|
+
...toolMetadata["annotations"] || {},
|
|
1076
|
+
...frontmcpExt.annotations
|
|
1077
|
+
};
|
|
1070
1078
|
}
|
|
1071
1079
|
if (frontmcpExt.tags) {
|
|
1072
1080
|
toolMetadata["tags"] = [...frontmcpExt.tags];
|
|
@@ -1106,6 +1114,13 @@ function createOpenApiTool(openapiTool, options, logger) {
|
|
|
1106
1114
|
}
|
|
1107
1115
|
return (0, import_sdk4.tool)(toolMetadata)(async (input, toolCtx) => {
|
|
1108
1116
|
const ctx = toolCtx.context;
|
|
1117
|
+
if (argumentCheck && !argumentCheck.conversionFailed) {
|
|
1118
|
+
const validation = argumentCheck.schema.safeParse(input);
|
|
1119
|
+
if (!validation.success) {
|
|
1120
|
+
const problems = validation.error.issues.map((issue) => `${issue.path.join(".") || "input"}: ${issue.message}`);
|
|
1121
|
+
throw new import_sdk4.InvalidInputError(`Invalid arguments for tool '${openapiTool.name}': ${problems.join("; ")}`);
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1109
1124
|
const transformContext = {
|
|
1110
1125
|
ctx,
|
|
1111
1126
|
env: process.env,
|
|
@@ -1319,6 +1334,64 @@ async function injectTransformedValues(input, transforms, ctx) {
|
|
|
1319
1334
|
}
|
|
1320
1335
|
return result;
|
|
1321
1336
|
}
|
|
1337
|
+
var SUBSCHEMA_KEYWORDS = [
|
|
1338
|
+
"items",
|
|
1339
|
+
"additionalProperties",
|
|
1340
|
+
"not",
|
|
1341
|
+
"if",
|
|
1342
|
+
"then",
|
|
1343
|
+
"else",
|
|
1344
|
+
"contains",
|
|
1345
|
+
"propertyNames",
|
|
1346
|
+
"unevaluatedItems",
|
|
1347
|
+
"unevaluatedProperties"
|
|
1348
|
+
];
|
|
1349
|
+
var SUBSCHEMA_LIST_KEYWORDS = ["allOf", "anyOf", "prefixItems"];
|
|
1350
|
+
var SUBSCHEMA_MAP_KEYWORDS = ["properties", "patternProperties", "dependentSchemas", "$defs", "definitions"];
|
|
1351
|
+
function toArgumentJsonSchema(openapiTool) {
|
|
1352
|
+
const argumentSchema = relaxSchema(openapiTool.inputSchema);
|
|
1353
|
+
const credentialKeys = new Set(
|
|
1354
|
+
openapiTool.mapper.filter((mapper) => mapper.security).map((mapper) => mapper.inputKey)
|
|
1355
|
+
);
|
|
1356
|
+
const required = argumentSchema["required"];
|
|
1357
|
+
if (Array.isArray(required)) {
|
|
1358
|
+
argumentSchema["required"] = required.filter((key) => !credentialKeys.has(key));
|
|
1359
|
+
}
|
|
1360
|
+
return argumentSchema;
|
|
1361
|
+
}
|
|
1362
|
+
function relaxSchema(schema) {
|
|
1363
|
+
if (Array.isArray(schema)) return schema.map(relaxSchema);
|
|
1364
|
+
if (typeof schema !== "object" || schema === null) return schema;
|
|
1365
|
+
const relaxed = { ...schema };
|
|
1366
|
+
delete relaxed["format"];
|
|
1367
|
+
for (const keyword of SUBSCHEMA_KEYWORDS) {
|
|
1368
|
+
if (keyword in relaxed) relaxed[keyword] = relaxSchema(relaxed[keyword]);
|
|
1369
|
+
}
|
|
1370
|
+
for (const keyword of SUBSCHEMA_LIST_KEYWORDS) {
|
|
1371
|
+
const subschemas = relaxed[keyword];
|
|
1372
|
+
if (Array.isArray(subschemas)) relaxed[keyword] = subschemas.map(relaxSchema);
|
|
1373
|
+
}
|
|
1374
|
+
for (const keyword of SUBSCHEMA_MAP_KEYWORDS) {
|
|
1375
|
+
const subschemasByName = relaxed[keyword];
|
|
1376
|
+
if (typeof subschemasByName === "object" && subschemasByName !== null) {
|
|
1377
|
+
relaxed[keyword] = Object.fromEntries(
|
|
1378
|
+
Object.entries(subschemasByName).map(([name, subschema]) => [name, relaxSchema(subschema)])
|
|
1379
|
+
);
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
const exclusiveBranches = relaxed["oneOf"];
|
|
1383
|
+
if (Array.isArray(exclusiveBranches)) {
|
|
1384
|
+
delete relaxed["oneOf"];
|
|
1385
|
+
const branches = exclusiveBranches.map(relaxSchema);
|
|
1386
|
+
if (Array.isArray(relaxed["anyOf"])) {
|
|
1387
|
+
const allOf = Array.isArray(relaxed["allOf"]) ? relaxed["allOf"] : [];
|
|
1388
|
+
relaxed["allOf"] = [...allOf, { anyOf: branches }];
|
|
1389
|
+
} else {
|
|
1390
|
+
relaxed["anyOf"] = branches;
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
return relaxed;
|
|
1394
|
+
}
|
|
1322
1395
|
function getZodSchemaFromJsonSchema(jsonSchema, toolName, logger) {
|
|
1323
1396
|
if (typeof jsonSchema !== "object" || jsonSchema === null) {
|
|
1324
1397
|
logger.warn(`[${toolName}] No valid JSON schema provided, using permissive schema`);
|
|
@@ -1346,6 +1419,18 @@ function getZodSchemaFromJsonSchema(jsonSchema, toolName, logger) {
|
|
|
1346
1419
|
|
|
1347
1420
|
// libs/adapters/src/openapi/openapi.adapter.ts
|
|
1348
1421
|
var RESERVED_KEYS2 = ["__proto__", "constructor", "prototype"];
|
|
1422
|
+
var HTTP_METHODS = ["get", "post", "put", "patch", "delete", "head", "options", "trace"];
|
|
1423
|
+
function normalizeMethods(adapterName, optionName, methods) {
|
|
1424
|
+
return methods?.map((method) => {
|
|
1425
|
+
const lowerMethod = method.toLowerCase();
|
|
1426
|
+
if (!HTTP_METHODS.includes(lowerMethod)) {
|
|
1427
|
+
throw new Error(
|
|
1428
|
+
`[OpenAPI Adapter: ${adapterName}] generateOptions.${optionName} lists "${method}", which is not an HTTP method; use one of ${HTTP_METHODS.join(", ")}.`
|
|
1429
|
+
);
|
|
1430
|
+
}
|
|
1431
|
+
return lowerMethod;
|
|
1432
|
+
});
|
|
1433
|
+
}
|
|
1349
1434
|
function createConsoleLogger(prefix) {
|
|
1350
1435
|
const formatMessage = (level, msg) => `[${prefix}] ${level}: ${msg}`;
|
|
1351
1436
|
return {
|
|
@@ -1364,9 +1449,14 @@ var OpenapiAdapter = class extends import_sdk5.DynamicAdapter {
|
|
|
1364
1449
|
poller = null;
|
|
1365
1450
|
updateCallbacks = /* @__PURE__ */ new Set();
|
|
1366
1451
|
rebuildChain = Promise.resolve();
|
|
1452
|
+
methodFilters;
|
|
1367
1453
|
constructor(options) {
|
|
1368
1454
|
super();
|
|
1369
1455
|
this.options = options;
|
|
1456
|
+
this.methodFilters = {
|
|
1457
|
+
includeMethods: normalizeMethods(options.name, "includeMethods", options.generateOptions?.includeMethods),
|
|
1458
|
+
excludeMethods: normalizeMethods(options.name, "excludeMethods", options.generateOptions?.excludeMethods)
|
|
1459
|
+
};
|
|
1370
1460
|
this.logger = options.logger ?? createConsoleLogger(`openapi:${options.name}`);
|
|
1371
1461
|
if (options.polling?.enabled && !("url" in options)) {
|
|
1372
1462
|
throw new Error(
|
|
@@ -1390,6 +1480,8 @@ var OpenapiAdapter = class extends import_sdk5.DynamicAdapter {
|
|
|
1390
1480
|
const generateOptions = this.options.generateOptions;
|
|
1391
1481
|
let openapiTools = await this.generator.generateTools({
|
|
1392
1482
|
...generateOptions,
|
|
1483
|
+
...this.methodFilters,
|
|
1484
|
+
filterFn: this.operationFilter(),
|
|
1393
1485
|
preferredStatusCodes: generateOptions?.preferredStatusCodes ?? [200, 201, 202, 204],
|
|
1394
1486
|
includeDeprecated: generateOptions?.includeDeprecated ?? false,
|
|
1395
1487
|
includeAllResponses: generateOptions?.includeAllResponses ?? true,
|
|
@@ -1475,28 +1567,31 @@ var OpenapiAdapter = class extends import_sdk5.DynamicAdapter {
|
|
|
1475
1567
|
resolveRefResolution() {
|
|
1476
1568
|
return this.options.loadOptions?.refResolution ?? { allowedProtocols: [] };
|
|
1477
1569
|
}
|
|
1570
|
+
/**
|
|
1571
|
+
* `generateOptions.filterFn`, and with `includeOperations` set, only the operations it names: the
|
|
1572
|
+
* generator lets an operation with no `operationId` through that list.
|
|
1573
|
+
*/
|
|
1574
|
+
operationFilter() {
|
|
1575
|
+
const { includeOperations, filterFn } = this.options.generateOptions ?? {};
|
|
1576
|
+
if (!includeOperations) return filterFn;
|
|
1577
|
+
return (operation) => operation.operationId !== void 0 && includeOperations.includes(operation.operationId) && (filterFn?.(operation) ?? true);
|
|
1578
|
+
}
|
|
1478
1579
|
async initializeGenerator() {
|
|
1479
|
-
const
|
|
1580
|
+
const loadOptions = {
|
|
1581
|
+
...this.options.loadOptions,
|
|
1582
|
+
baseUrl: this.options.baseUrl,
|
|
1583
|
+
validate: this.options.loadOptions?.validate ?? true,
|
|
1584
|
+
dereference: this.options.loadOptions?.dereference ?? true,
|
|
1585
|
+
// SECURITY: do not follow spec-URL redirects by default — a 3xx to an
|
|
1586
|
+
// internal target would otherwise be fetched. With mcp-from-openapi
|
|
1587
|
+
// ≥ 2.5.0 each hop is re-validated; opt in with loadOptions.followRedirects.
|
|
1588
|
+
followRedirects: this.options.loadOptions?.followRedirects ?? false,
|
|
1589
|
+
refResolution: this.resolveRefResolution()
|
|
1590
|
+
};
|
|
1480
1591
|
if ("url" in this.options) {
|
|
1481
|
-
return await import_mcp_from_openapi3.OpenAPIToolGenerator.fromURL(this.options.url,
|
|
1482
|
-
baseUrl: this.options.baseUrl,
|
|
1483
|
-
validate: this.options.loadOptions?.validate ?? true,
|
|
1484
|
-
dereference: this.options.loadOptions?.dereference ?? true,
|
|
1485
|
-
headers: this.options.loadOptions?.headers,
|
|
1486
|
-
timeout: this.options.loadOptions?.timeout,
|
|
1487
|
-
// SECURITY: do not follow spec-URL redirects by default — a 3xx to an
|
|
1488
|
-
// internal target would otherwise be fetched. With mcp-from-openapi
|
|
1489
|
-
// ≥ 2.5.0 each hop is re-validated; opt in with loadOptions.followRedirects.
|
|
1490
|
-
followRedirects: this.options.loadOptions?.followRedirects ?? false,
|
|
1491
|
-
refResolution
|
|
1492
|
-
});
|
|
1592
|
+
return await import_mcp_from_openapi3.OpenAPIToolGenerator.fromURL(this.options.url, loadOptions);
|
|
1493
1593
|
} else if ("spec" in this.options) {
|
|
1494
|
-
return await import_mcp_from_openapi3.OpenAPIToolGenerator.fromJSON(this.options.spec,
|
|
1495
|
-
baseUrl: this.options.baseUrl,
|
|
1496
|
-
validate: this.options.loadOptions?.validate ?? true,
|
|
1497
|
-
dereference: this.options.loadOptions?.dereference ?? true,
|
|
1498
|
-
refResolution
|
|
1499
|
-
});
|
|
1594
|
+
return await import_mcp_from_openapi3.OpenAPIToolGenerator.fromJSON(this.options.spec, loadOptions);
|
|
1500
1595
|
} else {
|
|
1501
1596
|
throw new Error("Either url or spec must be provided in OpenApiAdapterOptions");
|
|
1502
1597
|
}
|
package/openapi/index.js
CHANGED
|
@@ -1037,6 +1037,7 @@ function createOpenApiTool(openapiTool, options, logger) {
|
|
|
1037
1037
|
const frontmcpValidation = validateFrontMcpExtension(metadata.frontmcp, openapiTool.name, logger);
|
|
1038
1038
|
const frontmcpExt = frontmcpValidation.data;
|
|
1039
1039
|
const schemaResult = getZodSchemaFromJsonSchema(openapiTool.inputSchema, openapiTool.name, logger);
|
|
1040
|
+
const argumentCheck = schemaResult.conversionFailed ? void 0 : getZodSchemaFromJsonSchema(toArgumentJsonSchema(openapiTool), openapiTool.name, logger);
|
|
1040
1041
|
let wrappedOutputSchema;
|
|
1041
1042
|
if (openapiTool.outputSchema !== void 0) {
|
|
1042
1043
|
const baseOutputSchema = openapiTool.outputSchema ?? { type: "string" };
|
|
@@ -1054,11 +1055,15 @@ function createOpenApiTool(openapiTool, options, logger) {
|
|
|
1054
1055
|
const toolMetadata = {
|
|
1055
1056
|
id: openapiTool.name,
|
|
1056
1057
|
name: openapiTool.name,
|
|
1058
|
+
...openapiTool.title && { title: openapiTool.title },
|
|
1057
1059
|
description: openapiTool.description,
|
|
1058
1060
|
inputSchema: schemaResult.schema.shape || {},
|
|
1059
1061
|
rawInputSchema: openapiTool.inputSchema,
|
|
1060
1062
|
// Add output schema for tool/list to expose (only if not moved to description)
|
|
1061
|
-
...wrappedOutputSchema && { rawOutputSchema: wrappedOutputSchema }
|
|
1063
|
+
...wrappedOutputSchema && { rawOutputSchema: wrappedOutputSchema },
|
|
1064
|
+
...openapiTool.annotations && { annotations: { ...openapiTool.annotations } },
|
|
1065
|
+
...openapiTool.icons?.length && { icons: openapiTool.icons.map((icon) => ({ ...icon })) },
|
|
1066
|
+
...openapiTool._meta && { _meta: { ...openapiTool._meta } }
|
|
1062
1067
|
};
|
|
1063
1068
|
if (schemaResult.conversionFailed) {
|
|
1064
1069
|
toolMetadata["_schemaConversionFailed"] = true;
|
|
@@ -1066,7 +1071,10 @@ function createOpenApiTool(openapiTool, options, logger) {
|
|
|
1066
1071
|
}
|
|
1067
1072
|
if (frontmcpExt) {
|
|
1068
1073
|
if (frontmcpExt.annotations) {
|
|
1069
|
-
toolMetadata["annotations"] = {
|
|
1074
|
+
toolMetadata["annotations"] = {
|
|
1075
|
+
...toolMetadata["annotations"] || {},
|
|
1076
|
+
...frontmcpExt.annotations
|
|
1077
|
+
};
|
|
1070
1078
|
}
|
|
1071
1079
|
if (frontmcpExt.tags) {
|
|
1072
1080
|
toolMetadata["tags"] = [...frontmcpExt.tags];
|
|
@@ -1106,6 +1114,13 @@ function createOpenApiTool(openapiTool, options, logger) {
|
|
|
1106
1114
|
}
|
|
1107
1115
|
return (0, import_sdk4.tool)(toolMetadata)(async (input, toolCtx) => {
|
|
1108
1116
|
const ctx = toolCtx.context;
|
|
1117
|
+
if (argumentCheck && !argumentCheck.conversionFailed) {
|
|
1118
|
+
const validation = argumentCheck.schema.safeParse(input);
|
|
1119
|
+
if (!validation.success) {
|
|
1120
|
+
const problems = validation.error.issues.map((issue) => `${issue.path.join(".") || "input"}: ${issue.message}`);
|
|
1121
|
+
throw new import_sdk4.InvalidInputError(`Invalid arguments for tool '${openapiTool.name}': ${problems.join("; ")}`);
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1109
1124
|
const transformContext = {
|
|
1110
1125
|
ctx,
|
|
1111
1126
|
env: process.env,
|
|
@@ -1319,6 +1334,64 @@ async function injectTransformedValues(input, transforms, ctx) {
|
|
|
1319
1334
|
}
|
|
1320
1335
|
return result;
|
|
1321
1336
|
}
|
|
1337
|
+
var SUBSCHEMA_KEYWORDS = [
|
|
1338
|
+
"items",
|
|
1339
|
+
"additionalProperties",
|
|
1340
|
+
"not",
|
|
1341
|
+
"if",
|
|
1342
|
+
"then",
|
|
1343
|
+
"else",
|
|
1344
|
+
"contains",
|
|
1345
|
+
"propertyNames",
|
|
1346
|
+
"unevaluatedItems",
|
|
1347
|
+
"unevaluatedProperties"
|
|
1348
|
+
];
|
|
1349
|
+
var SUBSCHEMA_LIST_KEYWORDS = ["allOf", "anyOf", "prefixItems"];
|
|
1350
|
+
var SUBSCHEMA_MAP_KEYWORDS = ["properties", "patternProperties", "dependentSchemas", "$defs", "definitions"];
|
|
1351
|
+
function toArgumentJsonSchema(openapiTool) {
|
|
1352
|
+
const argumentSchema = relaxSchema(openapiTool.inputSchema);
|
|
1353
|
+
const credentialKeys = new Set(
|
|
1354
|
+
openapiTool.mapper.filter((mapper) => mapper.security).map((mapper) => mapper.inputKey)
|
|
1355
|
+
);
|
|
1356
|
+
const required = argumentSchema["required"];
|
|
1357
|
+
if (Array.isArray(required)) {
|
|
1358
|
+
argumentSchema["required"] = required.filter((key) => !credentialKeys.has(key));
|
|
1359
|
+
}
|
|
1360
|
+
return argumentSchema;
|
|
1361
|
+
}
|
|
1362
|
+
function relaxSchema(schema) {
|
|
1363
|
+
if (Array.isArray(schema)) return schema.map(relaxSchema);
|
|
1364
|
+
if (typeof schema !== "object" || schema === null) return schema;
|
|
1365
|
+
const relaxed = { ...schema };
|
|
1366
|
+
delete relaxed["format"];
|
|
1367
|
+
for (const keyword of SUBSCHEMA_KEYWORDS) {
|
|
1368
|
+
if (keyword in relaxed) relaxed[keyword] = relaxSchema(relaxed[keyword]);
|
|
1369
|
+
}
|
|
1370
|
+
for (const keyword of SUBSCHEMA_LIST_KEYWORDS) {
|
|
1371
|
+
const subschemas = relaxed[keyword];
|
|
1372
|
+
if (Array.isArray(subschemas)) relaxed[keyword] = subschemas.map(relaxSchema);
|
|
1373
|
+
}
|
|
1374
|
+
for (const keyword of SUBSCHEMA_MAP_KEYWORDS) {
|
|
1375
|
+
const subschemasByName = relaxed[keyword];
|
|
1376
|
+
if (typeof subschemasByName === "object" && subschemasByName !== null) {
|
|
1377
|
+
relaxed[keyword] = Object.fromEntries(
|
|
1378
|
+
Object.entries(subschemasByName).map(([name, subschema]) => [name, relaxSchema(subschema)])
|
|
1379
|
+
);
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
const exclusiveBranches = relaxed["oneOf"];
|
|
1383
|
+
if (Array.isArray(exclusiveBranches)) {
|
|
1384
|
+
delete relaxed["oneOf"];
|
|
1385
|
+
const branches = exclusiveBranches.map(relaxSchema);
|
|
1386
|
+
if (Array.isArray(relaxed["anyOf"])) {
|
|
1387
|
+
const allOf = Array.isArray(relaxed["allOf"]) ? relaxed["allOf"] : [];
|
|
1388
|
+
relaxed["allOf"] = [...allOf, { anyOf: branches }];
|
|
1389
|
+
} else {
|
|
1390
|
+
relaxed["anyOf"] = branches;
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
return relaxed;
|
|
1394
|
+
}
|
|
1322
1395
|
function getZodSchemaFromJsonSchema(jsonSchema, toolName, logger) {
|
|
1323
1396
|
if (typeof jsonSchema !== "object" || jsonSchema === null) {
|
|
1324
1397
|
logger.warn(`[${toolName}] No valid JSON schema provided, using permissive schema`);
|
|
@@ -1346,6 +1419,18 @@ function getZodSchemaFromJsonSchema(jsonSchema, toolName, logger) {
|
|
|
1346
1419
|
|
|
1347
1420
|
// libs/adapters/src/openapi/openapi.adapter.ts
|
|
1348
1421
|
var RESERVED_KEYS2 = ["__proto__", "constructor", "prototype"];
|
|
1422
|
+
var HTTP_METHODS = ["get", "post", "put", "patch", "delete", "head", "options", "trace"];
|
|
1423
|
+
function normalizeMethods(adapterName, optionName, methods) {
|
|
1424
|
+
return methods?.map((method) => {
|
|
1425
|
+
const lowerMethod = method.toLowerCase();
|
|
1426
|
+
if (!HTTP_METHODS.includes(lowerMethod)) {
|
|
1427
|
+
throw new Error(
|
|
1428
|
+
`[OpenAPI Adapter: ${adapterName}] generateOptions.${optionName} lists "${method}", which is not an HTTP method; use one of ${HTTP_METHODS.join(", ")}.`
|
|
1429
|
+
);
|
|
1430
|
+
}
|
|
1431
|
+
return lowerMethod;
|
|
1432
|
+
});
|
|
1433
|
+
}
|
|
1349
1434
|
function createConsoleLogger(prefix) {
|
|
1350
1435
|
const formatMessage = (level, msg) => `[${prefix}] ${level}: ${msg}`;
|
|
1351
1436
|
return {
|
|
@@ -1364,9 +1449,14 @@ var OpenapiAdapter = class extends import_sdk5.DynamicAdapter {
|
|
|
1364
1449
|
poller = null;
|
|
1365
1450
|
updateCallbacks = /* @__PURE__ */ new Set();
|
|
1366
1451
|
rebuildChain = Promise.resolve();
|
|
1452
|
+
methodFilters;
|
|
1367
1453
|
constructor(options) {
|
|
1368
1454
|
super();
|
|
1369
1455
|
this.options = options;
|
|
1456
|
+
this.methodFilters = {
|
|
1457
|
+
includeMethods: normalizeMethods(options.name, "includeMethods", options.generateOptions?.includeMethods),
|
|
1458
|
+
excludeMethods: normalizeMethods(options.name, "excludeMethods", options.generateOptions?.excludeMethods)
|
|
1459
|
+
};
|
|
1370
1460
|
this.logger = options.logger ?? createConsoleLogger(`openapi:${options.name}`);
|
|
1371
1461
|
if (options.polling?.enabled && !("url" in options)) {
|
|
1372
1462
|
throw new Error(
|
|
@@ -1390,6 +1480,8 @@ var OpenapiAdapter = class extends import_sdk5.DynamicAdapter {
|
|
|
1390
1480
|
const generateOptions = this.options.generateOptions;
|
|
1391
1481
|
let openapiTools = await this.generator.generateTools({
|
|
1392
1482
|
...generateOptions,
|
|
1483
|
+
...this.methodFilters,
|
|
1484
|
+
filterFn: this.operationFilter(),
|
|
1393
1485
|
preferredStatusCodes: generateOptions?.preferredStatusCodes ?? [200, 201, 202, 204],
|
|
1394
1486
|
includeDeprecated: generateOptions?.includeDeprecated ?? false,
|
|
1395
1487
|
includeAllResponses: generateOptions?.includeAllResponses ?? true,
|
|
@@ -1475,28 +1567,31 @@ var OpenapiAdapter = class extends import_sdk5.DynamicAdapter {
|
|
|
1475
1567
|
resolveRefResolution() {
|
|
1476
1568
|
return this.options.loadOptions?.refResolution ?? { allowedProtocols: [] };
|
|
1477
1569
|
}
|
|
1570
|
+
/**
|
|
1571
|
+
* `generateOptions.filterFn`, and with `includeOperations` set, only the operations it names: the
|
|
1572
|
+
* generator lets an operation with no `operationId` through that list.
|
|
1573
|
+
*/
|
|
1574
|
+
operationFilter() {
|
|
1575
|
+
const { includeOperations, filterFn } = this.options.generateOptions ?? {};
|
|
1576
|
+
if (!includeOperations) return filterFn;
|
|
1577
|
+
return (operation) => operation.operationId !== void 0 && includeOperations.includes(operation.operationId) && (filterFn?.(operation) ?? true);
|
|
1578
|
+
}
|
|
1478
1579
|
async initializeGenerator() {
|
|
1479
|
-
const
|
|
1580
|
+
const loadOptions = {
|
|
1581
|
+
...this.options.loadOptions,
|
|
1582
|
+
baseUrl: this.options.baseUrl,
|
|
1583
|
+
validate: this.options.loadOptions?.validate ?? true,
|
|
1584
|
+
dereference: this.options.loadOptions?.dereference ?? true,
|
|
1585
|
+
// SECURITY: do not follow spec-URL redirects by default — a 3xx to an
|
|
1586
|
+
// internal target would otherwise be fetched. With mcp-from-openapi
|
|
1587
|
+
// ≥ 2.5.0 each hop is re-validated; opt in with loadOptions.followRedirects.
|
|
1588
|
+
followRedirects: this.options.loadOptions?.followRedirects ?? false,
|
|
1589
|
+
refResolution: this.resolveRefResolution()
|
|
1590
|
+
};
|
|
1480
1591
|
if ("url" in this.options) {
|
|
1481
|
-
return await import_mcp_from_openapi3.OpenAPIToolGenerator.fromURL(this.options.url,
|
|
1482
|
-
baseUrl: this.options.baseUrl,
|
|
1483
|
-
validate: this.options.loadOptions?.validate ?? true,
|
|
1484
|
-
dereference: this.options.loadOptions?.dereference ?? true,
|
|
1485
|
-
headers: this.options.loadOptions?.headers,
|
|
1486
|
-
timeout: this.options.loadOptions?.timeout,
|
|
1487
|
-
// SECURITY: do not follow spec-URL redirects by default — a 3xx to an
|
|
1488
|
-
// internal target would otherwise be fetched. With mcp-from-openapi
|
|
1489
|
-
// ≥ 2.5.0 each hop is re-validated; opt in with loadOptions.followRedirects.
|
|
1490
|
-
followRedirects: this.options.loadOptions?.followRedirects ?? false,
|
|
1491
|
-
refResolution
|
|
1492
|
-
});
|
|
1592
|
+
return await import_mcp_from_openapi3.OpenAPIToolGenerator.fromURL(this.options.url, loadOptions);
|
|
1493
1593
|
} else if ("spec" in this.options) {
|
|
1494
|
-
return await import_mcp_from_openapi3.OpenAPIToolGenerator.fromJSON(this.options.spec,
|
|
1495
|
-
baseUrl: this.options.baseUrl,
|
|
1496
|
-
validate: this.options.loadOptions?.validate ?? true,
|
|
1497
|
-
dereference: this.options.loadOptions?.dereference ?? true,
|
|
1498
|
-
refResolution
|
|
1499
|
-
});
|
|
1594
|
+
return await import_mcp_from_openapi3.OpenAPIToolGenerator.fromJSON(this.options.spec, loadOptions);
|
|
1500
1595
|
} else {
|
|
1501
1596
|
throw new Error("Either url or spec must be provided in OpenApiAdapterOptions");
|
|
1502
1597
|
}
|
|
@@ -7,6 +7,7 @@ export default class OpenapiAdapter extends DynamicAdapter<OpenApiAdapterOptions
|
|
|
7
7
|
private poller;
|
|
8
8
|
private updateCallbacks;
|
|
9
9
|
private rebuildChain;
|
|
10
|
+
private readonly methodFilters;
|
|
10
11
|
constructor(options: OpenApiAdapterOptions);
|
|
11
12
|
/**
|
|
12
13
|
* Receive the SDK logger. Called by the SDK before fetch().
|
|
@@ -29,6 +30,11 @@ export default class OpenapiAdapter extends DynamicAdapter<OpenApiAdapterOptions
|
|
|
29
30
|
* @private
|
|
30
31
|
*/
|
|
31
32
|
private resolveRefResolution;
|
|
33
|
+
/**
|
|
34
|
+
* `generateOptions.filterFn`, and with `includeOperations` set, only the operations it names: the
|
|
35
|
+
* generator lets an operation with no `operationId` through that list.
|
|
36
|
+
*/
|
|
37
|
+
private operationFilter;
|
|
32
38
|
private initializeGenerator;
|
|
33
39
|
/**
|
|
34
40
|
* Apply description mode to generate description from summary/description
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openapi.adapter.d.ts","sourceRoot":"","sources":["../../src/openapi/openapi.adapter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"openapi.adapter.d.ts","sourceRoot":"","sources":["../../src/openapi/openapi.adapter.ts"],"names":[],"mappings":"AAOA,OAAO,EAAW,cAAc,EAAE,KAAK,uBAAuB,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAS3G,OAAO,EAIL,KAAK,qBAAqB,EAQ3B,MAAM,iBAAiB,CAAC;AA6CzB,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,cAAc,CAAC,qBAAqB,CAAC;IAC/E,OAAO,CAAC,SAAS,CAAC,CAAuB;IACzC,OAAO,CAAC,MAAM,CAAiB;IACxB,OAAO,EAAE,qBAAqB,CAAC;IACtC,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,eAAe,CAA0D;IACjF,OAAO,CAAC,YAAY,CAAoC;IACxD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAmE;gBAErF,OAAO,EAAE,qBAAqB;IAkB1C;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI;IAIjC,KAAK,IAAI,OAAO,CAAC,uBAAuB,CAAC;IAsH/C;;;OAGG;IACH;;;;;;;;;;OAUG;IACH,OAAO,CAAC,oBAAoB;IAI5B;;;OAGG;IACH,OAAO,CAAC,eAAe;YAST,mBAAmB;IAuBjC;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IA0C5B;;;OAGG;IACH,OAAO,CAAC,cAAc;IAMtB;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IA6D7B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAsC3B;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IAwBhC;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IAoD5B;;;;;OAKG;IACH,OAAO,CAAC,qBAAqB;IA0D7B;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IA0C7B;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IAkBnC;;;OAGG;IACH,OAAO,CAAC,4BAA4B;IAoBpC;;;;OAIG;YACW,wBAAwB;IAiFtC;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IAgBlC;;;OAGG;IACH,OAAO,CAAC,0CAA0C;IA+BlD;;;OAGG;IACH,OAAO,CAAC,2CAA2C;IAyCnD;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAuB7B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAiB3B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,uBAAuB,KAAK,IAAI,GAAG,MAAM,IAAI;IAO3E;;;;OAIG;IACH,YAAY,IAAI,IAAI;IA6CpB;;OAEG;IACH,WAAW,IAAI,IAAI;CAOpB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openapi.tool.d.ts","sourceRoot":"","sources":["../../src/openapi/openapi.tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGvD,OAAO,
|
|
1
|
+
{"version":3,"file":"openapi.tool.d.ts","sourceRoot":"","sources":["../../src/openapi/openapi.tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGvD,OAAO,EAA2B,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAK7E,OAAO,KAAK,EAIV,qBAAqB,EAEtB,MAAM,iBAAiB,CAAC;AAMzB;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,cAAc,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,EAAE,cAAc,cA2UpH"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/adapters",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.2",
|
|
4
4
|
"description": "Adapters for the FrontMCP framework",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"homepage": "https://docs.agentfront.dev",
|
|
@@ -64,15 +64,15 @@
|
|
|
64
64
|
"node": ">=24.0.0"
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@frontmcp/auth": "1.9.
|
|
68
|
-
"@frontmcp/di": "1.9.
|
|
69
|
-
"@frontmcp/sdk": "1.9.
|
|
70
|
-
"@frontmcp/utils": "1.9.
|
|
67
|
+
"@frontmcp/auth": "1.9.2",
|
|
68
|
+
"@frontmcp/di": "1.9.2",
|
|
69
|
+
"@frontmcp/sdk": "1.9.2",
|
|
70
|
+
"@frontmcp/utils": "1.9.2",
|
|
71
71
|
"js-yaml": "^4.1.0",
|
|
72
72
|
"mcp-from-openapi": "2.8.0",
|
|
73
73
|
"openapi-types": "^12.1.3"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
|
-
"@frontmcp/lazy-zod": "1.9.
|
|
76
|
+
"@frontmcp/lazy-zod": "1.9.2"
|
|
77
77
|
}
|
|
78
78
|
}
|
package/skills/index.js
CHANGED
|
@@ -942,7 +942,7 @@ var SaasPullSource = class {
|
|
|
942
942
|
bundle = await this.loadCache();
|
|
943
943
|
if (!bundle) {
|
|
944
944
|
throw new Error(
|
|
945
|
-
`[saas-source] initial pull failed and no cached bundle is available
|
|
945
|
+
`[saas-source] initial pull failed and no cached bundle is available ${this.cacheLocation()}: ${e.message}`,
|
|
946
946
|
{ cause: e }
|
|
947
947
|
);
|
|
948
948
|
}
|
|
@@ -1088,6 +1088,10 @@ var SaasPullSource = class {
|
|
|
1088
1088
|
trimmed.startsWith("{") || trimmed.startsWith("[") ? { kind: "json", content: body } : { kind: "yaml", content: body }
|
|
1089
1089
|
);
|
|
1090
1090
|
}
|
|
1091
|
+
/** Where the last-good bundle is kept, for messages: an injected store (a Worker's KV) has no file path. */
|
|
1092
|
+
cacheLocation() {
|
|
1093
|
+
return this.deps.cache ? "in the injected bundle cache" : `at ${this.cachePath()}`;
|
|
1094
|
+
}
|
|
1091
1095
|
cachePath() {
|
|
1092
1096
|
const dir = this.cacheDir ?? DEFAULT_CACHE_DIR;
|
|
1093
1097
|
return (0, import_utils.pathResolve)(dir, `${this.options.expectedAudience.replace(/[^a-zA-Z0-9_.-]/g, "_")}.json`);
|
|
@@ -72,6 +72,8 @@ export declare class SaasPullSource implements SkillBundleSource {
|
|
|
72
72
|
*/
|
|
73
73
|
private verifyPullToken;
|
|
74
74
|
private fetchOnce;
|
|
75
|
+
/** Where the last-good bundle is kept, for messages: an injected store (a Worker's KV) has no file path. */
|
|
76
|
+
private cacheLocation;
|
|
75
77
|
private cachePath;
|
|
76
78
|
private persistCache;
|
|
77
79
|
private loadCache;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"saas-pull.source.d.ts","sourceRoot":"","sources":["../../../src/skills/sources/saas-pull.source.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAMjH;;;;GAIG;AACH,qBAAa,0BAA2B,SAAQ,KAAK;gBACvC,MAAM,EAAE,MAAM;CAI3B;AA4BD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,cAAe,YAAW,iBAAiB;IAUpD,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAZvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAEpB,OAAO,CAAC,SAAS,CAAmC;IACpD,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAuB;gBAGhC,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,MAAM,EAAE,cAAc,EACtB,IAAI,GAAE,gBAAqB;IAKxC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAwC5B,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,GAAG,MAAM,IAAI;IAO9C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAS3B,OAAO,CAAC,YAAY;IAcpB;;;;;;OAMG;IACG,OAAO,IAAI,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;YAatC,QAAQ;cAyBN,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAoBhH;;;;OAIG;YACW,eAAe;YA2Cf,SAAS;IAkBvB,OAAO,CAAC,SAAS;YAKH,YAAY;YAeZ,SAAS;IAkBvB,OAAO,CAAC,MAAM;CASf"}
|
|
1
|
+
{"version":3,"file":"saas-pull.source.d.ts","sourceRoot":"","sources":["../../../src/skills/sources/saas-pull.source.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAMjH;;;;GAIG;AACH,qBAAa,0BAA2B,SAAQ,KAAK;gBACvC,MAAM,EAAE,MAAM;CAI3B;AA4BD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,cAAe,YAAW,iBAAiB;IAUpD,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAZvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAEpB,OAAO,CAAC,SAAS,CAAmC;IACpD,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAuB;gBAGhC,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,MAAM,EAAE,cAAc,EACtB,IAAI,GAAE,gBAAqB;IAKxC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAwC5B,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,GAAG,MAAM,IAAI;IAO9C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAS3B,OAAO,CAAC,YAAY;IAcpB;;;;;;OAMG;IACG,OAAO,IAAI,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;YAatC,QAAQ;cAyBN,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAoBhH;;;;OAIG;YACW,eAAe;YA2Cf,SAAS;IAkBvB,4GAA4G;IAC5G,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,SAAS;YAKH,YAAY;YAeZ,SAAS;IAkBvB,OAAO,CAAC,MAAM;CASf"}
|