mcp-from-openapi 2.1.2 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -554
- package/esm/index.mjs +246 -21
- package/esm/package.json +16 -10
- package/format-resolver.d.ts +12 -0
- package/generator.d.ts +15 -1
- package/index.d.ts +2 -1
- package/index.js +250 -23
- package/package.json +16 -10
- package/types.d.ts +59 -2
- package/CHANGELOG.md +0 -81
package/index.js
CHANGED
|
@@ -27,9 +27,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
));
|
|
28
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
29
|
|
|
30
|
-
//
|
|
30
|
+
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
BUILTIN_FORMAT_RESOLVERS: () => BUILTIN_FORMAT_RESOLVERS,
|
|
33
34
|
GenerationError: () => GenerationError,
|
|
34
35
|
LoadError: () => LoadError,
|
|
35
36
|
OpenAPIToolError: () => OpenAPIToolError,
|
|
@@ -44,17 +45,17 @@ __export(index_exports, {
|
|
|
44
45
|
Validator: () => Validator,
|
|
45
46
|
createSecurityContext: () => createSecurityContext,
|
|
46
47
|
isReferenceObject: () => isReferenceObject,
|
|
48
|
+
resolveSchemaFormats: () => resolveSchemaFormats,
|
|
47
49
|
toJsonSchema: () => toJsonSchema
|
|
48
50
|
});
|
|
49
51
|
module.exports = __toCommonJS(index_exports);
|
|
50
52
|
|
|
51
|
-
//
|
|
53
|
+
// src/generator.ts
|
|
52
54
|
var yaml = __toESM(require("yaml"));
|
|
53
|
-
var fs = __toESM(require("fs/promises"));
|
|
54
55
|
var path = __toESM(require("path"));
|
|
55
|
-
var
|
|
56
|
+
var fs = __toESM(require("fs/promises"));
|
|
56
57
|
|
|
57
|
-
//
|
|
58
|
+
// src/types.ts
|
|
58
59
|
function isReferenceObject(obj) {
|
|
59
60
|
return obj && typeof obj === "object" && "$ref" in obj;
|
|
60
61
|
}
|
|
@@ -120,7 +121,7 @@ function toJsonSchema(schema) {
|
|
|
120
121
|
return result;
|
|
121
122
|
}
|
|
122
123
|
|
|
123
|
-
//
|
|
124
|
+
// src/parameter-resolver.ts
|
|
124
125
|
var ParameterResolver = class {
|
|
125
126
|
namingStrategy;
|
|
126
127
|
constructor(namingStrategy) {
|
|
@@ -385,7 +386,7 @@ var ParameterResolver = class {
|
|
|
385
386
|
}
|
|
386
387
|
};
|
|
387
388
|
|
|
388
|
-
//
|
|
389
|
+
// src/response-builder.ts
|
|
389
390
|
var ResponseBuilder = class {
|
|
390
391
|
preferredStatusCodes;
|
|
391
392
|
includeAllResponses;
|
|
@@ -505,7 +506,7 @@ var ResponseBuilder = class {
|
|
|
505
506
|
}
|
|
506
507
|
};
|
|
507
508
|
|
|
508
|
-
//
|
|
509
|
+
// src/validator.ts
|
|
509
510
|
var Validator = class {
|
|
510
511
|
/**
|
|
511
512
|
* Validate an OpenAPI document
|
|
@@ -696,7 +697,7 @@ var Validator = class {
|
|
|
696
697
|
}
|
|
697
698
|
};
|
|
698
699
|
|
|
699
|
-
//
|
|
700
|
+
// src/errors.ts
|
|
700
701
|
var OpenAPIToolError = class extends Error {
|
|
701
702
|
context;
|
|
702
703
|
constructor(message, context) {
|
|
@@ -736,7 +737,116 @@ var SchemaError = class extends OpenAPIToolError {
|
|
|
736
737
|
}
|
|
737
738
|
};
|
|
738
739
|
|
|
739
|
-
//
|
|
740
|
+
// src/format-resolver.ts
|
|
741
|
+
var BUILTIN_FORMAT_RESOLVERS = {
|
|
742
|
+
// String formats
|
|
743
|
+
uuid: (schema) => ({
|
|
744
|
+
...schema,
|
|
745
|
+
pattern: schema.pattern ?? "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$",
|
|
746
|
+
description: schema.description || "UUID string (RFC 4122)"
|
|
747
|
+
}),
|
|
748
|
+
"date-time": (schema) => ({
|
|
749
|
+
...schema,
|
|
750
|
+
description: schema.description || "ISO 8601 date-time (e.g., 2024-01-15T09:30:00Z)"
|
|
751
|
+
}),
|
|
752
|
+
date: (schema) => ({
|
|
753
|
+
...schema,
|
|
754
|
+
pattern: schema.pattern ?? "^\\d{4}-\\d{2}-\\d{2}$",
|
|
755
|
+
description: schema.description || "ISO 8601 date (e.g., 2024-01-15)"
|
|
756
|
+
}),
|
|
757
|
+
time: (schema) => ({
|
|
758
|
+
...schema,
|
|
759
|
+
pattern: schema.pattern ?? "^\\d{2}:\\d{2}:\\d{2}",
|
|
760
|
+
description: schema.description || "ISO 8601 time (e.g., 09:30:00)"
|
|
761
|
+
}),
|
|
762
|
+
email: (schema) => ({
|
|
763
|
+
...schema,
|
|
764
|
+
description: schema.description || "Email address (RFC 5322)"
|
|
765
|
+
}),
|
|
766
|
+
uri: (schema) => ({
|
|
767
|
+
...schema,
|
|
768
|
+
description: schema.description || "URI (RFC 3986)"
|
|
769
|
+
}),
|
|
770
|
+
"uri-reference": (schema) => ({
|
|
771
|
+
...schema,
|
|
772
|
+
description: schema.description || "URI reference (RFC 3986)"
|
|
773
|
+
}),
|
|
774
|
+
hostname: (schema) => ({
|
|
775
|
+
...schema,
|
|
776
|
+
description: schema.description || "Internet hostname (RFC 1123)"
|
|
777
|
+
}),
|
|
778
|
+
ipv4: (schema) => ({
|
|
779
|
+
...schema,
|
|
780
|
+
pattern: schema.pattern ?? "^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$",
|
|
781
|
+
description: schema.description || "IPv4 address"
|
|
782
|
+
}),
|
|
783
|
+
ipv6: (schema) => ({
|
|
784
|
+
...schema,
|
|
785
|
+
description: schema.description || "IPv6 address (RFC 4291)"
|
|
786
|
+
}),
|
|
787
|
+
// Integer formats
|
|
788
|
+
int32: (schema) => ({
|
|
789
|
+
...schema,
|
|
790
|
+
minimum: schema.minimum ?? -2147483648,
|
|
791
|
+
maximum: schema.maximum ?? 2147483647
|
|
792
|
+
}),
|
|
793
|
+
int64: (schema) => ({
|
|
794
|
+
...schema,
|
|
795
|
+
minimum: schema.minimum ?? Number.MIN_SAFE_INTEGER,
|
|
796
|
+
maximum: schema.maximum ?? Number.MAX_SAFE_INTEGER
|
|
797
|
+
}),
|
|
798
|
+
// Binary/encoding formats
|
|
799
|
+
byte: (schema) => ({
|
|
800
|
+
...schema,
|
|
801
|
+
pattern: schema.pattern ?? "^[A-Za-z0-9+/]*={0,2}$",
|
|
802
|
+
description: schema.description || "Base64-encoded string (RFC 4648)"
|
|
803
|
+
}),
|
|
804
|
+
binary: (schema) => ({
|
|
805
|
+
...schema,
|
|
806
|
+
description: schema.description || "Binary data"
|
|
807
|
+
}),
|
|
808
|
+
// Sensitive data formats
|
|
809
|
+
password: (schema) => ({
|
|
810
|
+
...schema,
|
|
811
|
+
description: schema.description || "Password (sensitive, UI should mask input)"
|
|
812
|
+
})
|
|
813
|
+
};
|
|
814
|
+
function resolveSchemaFormats(schema, resolvers) {
|
|
815
|
+
if (!schema || typeof schema !== "object") return schema;
|
|
816
|
+
let result = { ...schema };
|
|
817
|
+
const format = result["format"];
|
|
818
|
+
if (format && resolvers[format]) {
|
|
819
|
+
result = { ...resolvers[format](result) };
|
|
820
|
+
}
|
|
821
|
+
if (result["properties"] && typeof result["properties"] === "object") {
|
|
822
|
+
const props = {};
|
|
823
|
+
for (const [key, value] of Object.entries(result["properties"])) {
|
|
824
|
+
props[key] = resolveSchemaFormats(value, resolvers);
|
|
825
|
+
}
|
|
826
|
+
result["properties"] = props;
|
|
827
|
+
}
|
|
828
|
+
if (result["items"]) {
|
|
829
|
+
if (Array.isArray(result["items"])) {
|
|
830
|
+
result["items"] = result["items"].map((item) => resolveSchemaFormats(item, resolvers));
|
|
831
|
+
} else {
|
|
832
|
+
result["items"] = resolveSchemaFormats(result["items"], resolvers);
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
if (result["additionalProperties"] && typeof result["additionalProperties"] === "object") {
|
|
836
|
+
result["additionalProperties"] = resolveSchemaFormats(result["additionalProperties"], resolvers);
|
|
837
|
+
}
|
|
838
|
+
for (const key of ["allOf", "anyOf", "oneOf"]) {
|
|
839
|
+
if (result[key] && Array.isArray(result[key])) {
|
|
840
|
+
result[key] = result[key].map((s) => resolveSchemaFormats(s, resolvers));
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
if (result["not"] && typeof result["not"] === "object") {
|
|
844
|
+
result["not"] = resolveSchemaFormats(result["not"], resolvers);
|
|
845
|
+
}
|
|
846
|
+
return result;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
// src/generator.ts
|
|
740
850
|
var OpenAPIToolGenerator = class _OpenAPIToolGenerator {
|
|
741
851
|
document;
|
|
742
852
|
dereferencedDocument;
|
|
@@ -752,7 +862,8 @@ var OpenAPIToolGenerator = class _OpenAPIToolGenerator {
|
|
|
752
862
|
headers: options.headers ?? {},
|
|
753
863
|
timeout: options.timeout ?? 3e4,
|
|
754
864
|
validate: options.validate ?? true,
|
|
755
|
-
followRedirects: options.followRedirects ?? true
|
|
865
|
+
followRedirects: options.followRedirects ?? true,
|
|
866
|
+
refResolution: options.refResolution ?? {}
|
|
756
867
|
};
|
|
757
868
|
}
|
|
758
869
|
/**
|
|
@@ -858,19 +969,116 @@ var OpenAPIToolGenerator = class _OpenAPIToolGenerator {
|
|
|
858
969
|
return validator.validate(this.document);
|
|
859
970
|
}
|
|
860
971
|
/**
|
|
861
|
-
*
|
|
972
|
+
* Hostnames and IP patterns that are blocked by default to prevent SSRF.
|
|
973
|
+
* Covers RFC 1918/6598 private ranges, link-local, loopback, and cloud metadata endpoints.
|
|
862
974
|
*/
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
975
|
+
static BLOCKED_HOSTNAME_PATTERNS = [
|
|
976
|
+
"localhost",
|
|
977
|
+
"metadata.google.internal",
|
|
978
|
+
/^127\.\d+\.\d+\.\d+$/,
|
|
979
|
+
// 127.0.0.0/8 loopback
|
|
980
|
+
/^10\.\d+\.\d+\.\d+$/,
|
|
981
|
+
// 10.0.0.0/8 private
|
|
982
|
+
/^172\.(1[6-9]|2\d|3[01])\.\d+\.\d+$/,
|
|
983
|
+
// 172.16.0.0/12 private
|
|
984
|
+
/^192\.168\.\d+\.\d+$/,
|
|
985
|
+
// 192.168.0.0/16 private
|
|
986
|
+
/^169\.254\.\d+\.\d+$/,
|
|
987
|
+
// 169.254.0.0/16 link-local / cloud metadata
|
|
988
|
+
/^0\.0\.0\.0$/,
|
|
989
|
+
// unspecified
|
|
990
|
+
"::1",
|
|
991
|
+
// IPv6 loopback
|
|
992
|
+
/^fd[0-9a-f]{2}:/i,
|
|
993
|
+
// fd00::/8 IPv6 ULA
|
|
994
|
+
/^fe80:/i,
|
|
995
|
+
// fe80::/10 IPv6 link-local
|
|
996
|
+
/^\[::1\]$/,
|
|
997
|
+
// bracketed IPv6 loopback
|
|
998
|
+
/^\[fd[0-9a-f]{2}:/i,
|
|
999
|
+
// bracketed IPv6 ULA
|
|
1000
|
+
/^\[fe80:/i
|
|
1001
|
+
// bracketed IPv6 link-local
|
|
1002
|
+
];
|
|
1003
|
+
/**
|
|
1004
|
+
* Check whether a hostname is blocked (internal/private IP or explicit blocklist).
|
|
1005
|
+
*/
|
|
1006
|
+
isBlockedHost(hostname, refOpts) {
|
|
1007
|
+
if (refOpts.allowInternalIPs) {
|
|
1008
|
+
return refOpts.blockedHosts.includes(hostname);
|
|
1009
|
+
}
|
|
1010
|
+
if (refOpts.blockedHosts.includes(hostname)) {
|
|
1011
|
+
return true;
|
|
1012
|
+
}
|
|
1013
|
+
for (const pattern of _OpenAPIToolGenerator.BLOCKED_HOSTNAME_PATTERNS) {
|
|
1014
|
+
if (typeof pattern === "string") {
|
|
1015
|
+
if (hostname === pattern) return true;
|
|
1016
|
+
} else {
|
|
1017
|
+
if (pattern.test(hostname)) return true;
|
|
868
1018
|
}
|
|
869
1019
|
}
|
|
1020
|
+
return false;
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
1023
|
+
* Build $RefParser options based on refResolution configuration.
|
|
1024
|
+
* Defaults: allow http/https, block file://, block internal IPs.
|
|
1025
|
+
*/
|
|
1026
|
+
buildRefParserOptions() {
|
|
1027
|
+
const raw = this.options.refResolution;
|
|
1028
|
+
const refOpts = {
|
|
1029
|
+
allowedProtocols: raw.allowedProtocols ?? ["http", "https"],
|
|
1030
|
+
allowedHosts: raw.allowedHosts ?? [],
|
|
1031
|
+
blockedHosts: raw.blockedHosts ?? [],
|
|
1032
|
+
allowInternalIPs: raw.allowInternalIPs ?? false
|
|
1033
|
+
};
|
|
1034
|
+
const allowedProtocols = new Set(refOpts.allowedProtocols);
|
|
1035
|
+
const hasNetworkProtocol = allowedProtocols.size > 0 && !([...allowedProtocols].length === 1 && allowedProtocols.has("file"));
|
|
1036
|
+
if (allowedProtocols.size === 0) {
|
|
1037
|
+
return { resolve: { external: false } };
|
|
1038
|
+
}
|
|
1039
|
+
const resolveConfig = {
|
|
1040
|
+
external: true,
|
|
1041
|
+
file: allowedProtocols.has("file") ? void 0 : false
|
|
1042
|
+
};
|
|
1043
|
+
if (hasNetworkProtocol) {
|
|
1044
|
+
const hasHostAllowlist = refOpts.allowedHosts.length > 0;
|
|
1045
|
+
const hostAllowSet = new Set(refOpts.allowedHosts);
|
|
1046
|
+
resolveConfig["http"] = {
|
|
1047
|
+
canRead: (file) => {
|
|
1048
|
+
try {
|
|
1049
|
+
const parsed = new URL(file.url);
|
|
1050
|
+
const protocol = parsed.protocol.replace(":", "");
|
|
1051
|
+
if (!allowedProtocols.has(protocol)) {
|
|
1052
|
+
return false;
|
|
1053
|
+
}
|
|
1054
|
+
if (hasHostAllowlist && !hostAllowSet.has(parsed.hostname)) {
|
|
1055
|
+
return false;
|
|
1056
|
+
}
|
|
1057
|
+
if (this.isBlockedHost(parsed.hostname, refOpts)) {
|
|
1058
|
+
return false;
|
|
1059
|
+
}
|
|
1060
|
+
return true;
|
|
1061
|
+
} catch {
|
|
1062
|
+
return false;
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
};
|
|
1066
|
+
} else {
|
|
1067
|
+
resolveConfig["http"] = false;
|
|
1068
|
+
}
|
|
1069
|
+
return { resolve: resolveConfig };
|
|
1070
|
+
}
|
|
1071
|
+
/**
|
|
1072
|
+
* Initialize the generator (dereference if needed, then validate)
|
|
1073
|
+
*/
|
|
1074
|
+
async initialize() {
|
|
870
1075
|
if (this.options.dereference && !this.dereferencedDocument) {
|
|
871
1076
|
try {
|
|
872
|
-
|
|
873
|
-
|
|
1077
|
+
const { default: $RefParser } = await import("@apidevtools/json-schema-ref-parser");
|
|
1078
|
+
const refParserOptions = this.buildRefParserOptions();
|
|
1079
|
+
this.dereferencedDocument = await $RefParser.dereference(
|
|
1080
|
+
JSON.parse(JSON.stringify(this.document)),
|
|
1081
|
+
refParserOptions
|
|
874
1082
|
);
|
|
875
1083
|
} catch (error) {
|
|
876
1084
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -879,6 +1087,14 @@ var OpenAPIToolGenerator = class _OpenAPIToolGenerator {
|
|
|
879
1087
|
});
|
|
880
1088
|
}
|
|
881
1089
|
}
|
|
1090
|
+
if (this.options.validate) {
|
|
1091
|
+
const validator = new Validator();
|
|
1092
|
+
const documentToValidate = this.dereferencedDocument ?? this.document;
|
|
1093
|
+
const result = await validator.validate(documentToValidate);
|
|
1094
|
+
if (!result.valid) {
|
|
1095
|
+
throw new ParseError("Invalid OpenAPI document", { errors: result.errors });
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
882
1098
|
}
|
|
883
1099
|
/**
|
|
884
1100
|
* Generate all tools from the OpenAPI specification
|
|
@@ -947,11 +1163,18 @@ var OpenAPIToolGenerator = class _OpenAPIToolGenerator {
|
|
|
947
1163
|
const name = this.generateToolName(pathStr, method, operation.operationId, options);
|
|
948
1164
|
const description = operation.summary || operation.description || `${method.toUpperCase()} ${pathStr}`;
|
|
949
1165
|
const metadata = this.extractMetadata(pathStr, method, operation, document, outputSchema);
|
|
1166
|
+
const formatResolvers = {
|
|
1167
|
+
...options.resolveFormats ? BUILTIN_FORMAT_RESOLVERS : {},
|
|
1168
|
+
...options.formatResolvers
|
|
1169
|
+
};
|
|
1170
|
+
const hasFormatResolvers = Object.keys(formatResolvers).length > 0;
|
|
1171
|
+
const resolvedInputSchema = hasFormatResolvers ? resolveSchemaFormats(inputSchema, formatResolvers) : inputSchema;
|
|
1172
|
+
const resolvedOutputSchema = hasFormatResolvers && outputSchema ? resolveSchemaFormats(outputSchema, formatResolvers) : outputSchema;
|
|
950
1173
|
return {
|
|
951
1174
|
name,
|
|
952
1175
|
description,
|
|
953
|
-
inputSchema,
|
|
954
|
-
outputSchema,
|
|
1176
|
+
inputSchema: resolvedInputSchema,
|
|
1177
|
+
outputSchema: resolvedOutputSchema,
|
|
955
1178
|
mapper,
|
|
956
1179
|
metadata
|
|
957
1180
|
};
|
|
@@ -1074,7 +1297,7 @@ var OpenAPIToolGenerator = class _OpenAPIToolGenerator {
|
|
|
1074
1297
|
}
|
|
1075
1298
|
};
|
|
1076
1299
|
|
|
1077
|
-
//
|
|
1300
|
+
// src/schema-builder.ts
|
|
1078
1301
|
var SchemaBuilder = class {
|
|
1079
1302
|
/**
|
|
1080
1303
|
* Merge multiple schemas into one
|
|
@@ -1353,7 +1576,7 @@ var SchemaBuilder = class {
|
|
|
1353
1576
|
}
|
|
1354
1577
|
};
|
|
1355
1578
|
|
|
1356
|
-
//
|
|
1579
|
+
// src/security-resolver.ts
|
|
1357
1580
|
var SecurityResolver = class {
|
|
1358
1581
|
/**
|
|
1359
1582
|
* Resolve security parameters from mapper entries
|
|
@@ -1401,6 +1624,7 @@ var SecurityResolver = class {
|
|
|
1401
1624
|
if (requiresSignature) {
|
|
1402
1625
|
resolved.requiresSignature = true;
|
|
1403
1626
|
resolved.signatureInfo = {
|
|
1627
|
+
/* c8 ignore next -- signatureScheme is always set from security.scheme */
|
|
1404
1628
|
scheme: signatureScheme || "unknown"
|
|
1405
1629
|
};
|
|
1406
1630
|
}
|
|
@@ -1446,6 +1670,7 @@ var SecurityResolver = class {
|
|
|
1446
1670
|
return this.resolveBasicAuth(context);
|
|
1447
1671
|
case "digest":
|
|
1448
1672
|
return this.resolveDigestAuth(context);
|
|
1673
|
+
/* c8 ignore next -- hoba is part of the same fall-through as mutual/negotiate/vapid/scram */
|
|
1449
1674
|
case "hoba":
|
|
1450
1675
|
case "mutual":
|
|
1451
1676
|
case "negotiate":
|
|
@@ -1594,6 +1819,7 @@ function createSecurityContext(auth) {
|
|
|
1594
1819
|
}
|
|
1595
1820
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1596
1821
|
0 && (module.exports = {
|
|
1822
|
+
BUILTIN_FORMAT_RESOLVERS,
|
|
1597
1823
|
GenerationError,
|
|
1598
1824
|
LoadError,
|
|
1599
1825
|
OpenAPIToolError,
|
|
@@ -1608,5 +1834,6 @@ function createSecurityContext(auth) {
|
|
|
1608
1834
|
Validator,
|
|
1609
1835
|
createSecurityContext,
|
|
1610
1836
|
isReferenceObject,
|
|
1837
|
+
resolveSchemaFormats,
|
|
1611
1838
|
toJsonSchema
|
|
1612
1839
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-from-openapi",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Production-ready library for converting OpenAPI specifications into MCP tool definitions",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -20,15 +20,14 @@
|
|
|
20
20
|
],
|
|
21
21
|
"repository": {
|
|
22
22
|
"type": "git",
|
|
23
|
-
"url": "git+https://github.com/agentfront/
|
|
24
|
-
"directory": "libs/mcp-from-openapi"
|
|
23
|
+
"url": "git+https://github.com/agentfront/mcp-from-openapi.git"
|
|
25
24
|
},
|
|
26
25
|
"bugs": {
|
|
27
|
-
"url": "https://github.com/agentfront/
|
|
26
|
+
"url": "https://github.com/agentfront/mcp-from-openapi/issues"
|
|
28
27
|
},
|
|
29
|
-
"homepage": "https://github.com/agentfront/
|
|
28
|
+
"homepage": "https://github.com/agentfront/mcp-from-openapi#readme",
|
|
30
29
|
"engines": {
|
|
31
|
-
"node": ">=
|
|
30
|
+
"node": ">=20.0.0"
|
|
32
31
|
},
|
|
33
32
|
"type": "commonjs",
|
|
34
33
|
"main": "./index.js",
|
|
@@ -46,19 +45,26 @@
|
|
|
46
45
|
"types": "./index.d.ts",
|
|
47
46
|
"default": "./esm/index.mjs"
|
|
48
47
|
}
|
|
49
|
-
}
|
|
50
|
-
"./esm": null
|
|
48
|
+
}
|
|
51
49
|
},
|
|
52
50
|
"dependencies": {
|
|
53
|
-
"@apidevtools/json-schema-ref-parser": "^
|
|
51
|
+
"@apidevtools/json-schema-ref-parser": "^15.3.5",
|
|
54
52
|
"openapi-types": "^12.1.3",
|
|
55
|
-
"yaml": "^2.8.
|
|
53
|
+
"yaml": "^2.8.3"
|
|
56
54
|
},
|
|
57
55
|
"peerDependencies": {
|
|
58
56
|
"zod": "^4.0.0"
|
|
59
57
|
},
|
|
60
58
|
"devDependencies": {
|
|
59
|
+
"@swc/core": "~1.5.7",
|
|
60
|
+
"@swc/helpers": "^0.5.18",
|
|
61
|
+
"@swc/jest": "~0.2.38",
|
|
62
|
+
"@types/jest": "^29.5.0",
|
|
63
|
+
"@types/json-schema": "^7.0.15",
|
|
61
64
|
"@types/node": "^24.0.0",
|
|
65
|
+
"esbuild": "^0.27.2",
|
|
66
|
+
"jest": "^29.7.0",
|
|
67
|
+
"tslib": "^2.8.1",
|
|
62
68
|
"typescript": "^5.0.0",
|
|
63
69
|
"zod": "^4.0.0"
|
|
64
70
|
}
|
package/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { JSONSchema } from 'zod/v4/core';
|
|
2
2
|
/** JSON Schema type from Zod v4 */
|
|
3
|
-
type JsonSchema = JSONSchema.JSONSchema;
|
|
3
|
+
export type JsonSchema = JSONSchema.JSONSchema;
|
|
4
4
|
import type { OpenAPIV3, OpenAPIV3_1 } from 'openapi-types';
|
|
5
5
|
/**
|
|
6
6
|
* OpenAPI specification version 3.0.x or 3.1.x
|
|
@@ -326,6 +326,37 @@ export interface ServerInfo {
|
|
|
326
326
|
*/
|
|
327
327
|
variables?: Record<string, ServerVariableObject>;
|
|
328
328
|
}
|
|
329
|
+
/**
|
|
330
|
+
* Controls how external $ref pointers are resolved during dereferencing.
|
|
331
|
+
* By default, only http/https protocols are allowed and internal/private
|
|
332
|
+
* IP addresses are blocked to prevent SSRF attacks.
|
|
333
|
+
*/
|
|
334
|
+
export interface RefResolutionOptions {
|
|
335
|
+
/**
|
|
336
|
+
* Protocols allowed for external $ref resolution.
|
|
337
|
+
* Any protocol string is accepted (http, https, ftp, ws, wss, etc.).
|
|
338
|
+
* @default ['http', 'https']
|
|
339
|
+
*/
|
|
340
|
+
allowedProtocols?: string[];
|
|
341
|
+
/**
|
|
342
|
+
* Hostnames allowed for external $ref resolution (network protocols only).
|
|
343
|
+
* When set, only refs pointing to these hosts are resolved.
|
|
344
|
+
* When not set, all hosts are allowed except blocked internal ranges.
|
|
345
|
+
*/
|
|
346
|
+
allowedHosts?: string[];
|
|
347
|
+
/**
|
|
348
|
+
* Additional hostnames/IPs to block. Applied on top of the built-in
|
|
349
|
+
* internal IP block list (localhost, 169.254.x.x, 10.x.x.x, etc.).
|
|
350
|
+
*/
|
|
351
|
+
blockedHosts?: string[];
|
|
352
|
+
/**
|
|
353
|
+
* Disable the built-in internal/private IP block list.
|
|
354
|
+
* WARNING: Enabling this may expose your application to SSRF attacks
|
|
355
|
+
* against cloud metadata endpoints and internal services.
|
|
356
|
+
* @default false
|
|
357
|
+
*/
|
|
358
|
+
allowInternalIPs?: boolean;
|
|
359
|
+
}
|
|
329
360
|
/**
|
|
330
361
|
* Options for loading OpenAPI specifications
|
|
331
362
|
*/
|
|
@@ -359,6 +390,12 @@ export interface LoadOptions {
|
|
|
359
390
|
* @default true
|
|
360
391
|
*/
|
|
361
392
|
followRedirects?: boolean;
|
|
393
|
+
/**
|
|
394
|
+
* Controls external $ref resolution security.
|
|
395
|
+
* By default, file:// is blocked and internal IPs are blocked.
|
|
396
|
+
* @see RefResolutionOptions
|
|
397
|
+
*/
|
|
398
|
+
refResolution?: RefResolutionOptions;
|
|
362
399
|
}
|
|
363
400
|
/**
|
|
364
401
|
* Operation object with additional context for filtering
|
|
@@ -420,7 +457,28 @@ export interface GenerateOptions {
|
|
|
420
457
|
* @default false
|
|
421
458
|
*/
|
|
422
459
|
includeSecurityInInput?: boolean;
|
|
460
|
+
/**
|
|
461
|
+
* Enable built-in format-to-schema resolution.
|
|
462
|
+
* Enriches schemas with concrete constraints (patterns, descriptions, min/max)
|
|
463
|
+
* based on OpenAPI format values (uuid, date-time, email, int32, etc.).
|
|
464
|
+
* @default false
|
|
465
|
+
*/
|
|
466
|
+
resolveFormats?: boolean;
|
|
467
|
+
/**
|
|
468
|
+
* Custom format resolvers. Keys are format names, values are functions
|
|
469
|
+
* that receive the original schema and return an enriched schema.
|
|
470
|
+
*
|
|
471
|
+
* When used with `resolveFormats: true`, custom resolvers are merged with
|
|
472
|
+
* built-in resolvers (custom takes precedence for the same format).
|
|
473
|
+
* When used without `resolveFormats`, only custom resolvers are applied.
|
|
474
|
+
*/
|
|
475
|
+
formatResolvers?: Record<string, FormatResolver>;
|
|
423
476
|
}
|
|
477
|
+
/**
|
|
478
|
+
* A function that enriches a JSON Schema based on its format field.
|
|
479
|
+
* Receives the schema and returns a new schema with additional constraints.
|
|
480
|
+
*/
|
|
481
|
+
export type FormatResolver = (schema: JsonSchema) => JsonSchema;
|
|
424
482
|
/**
|
|
425
483
|
* Naming strategy for resolving parameter conflicts
|
|
426
484
|
*/
|
|
@@ -493,4 +551,3 @@ export interface ValidationWarning {
|
|
|
493
551
|
*/
|
|
494
552
|
code?: string;
|
|
495
553
|
}
|
|
496
|
-
export {};
|
package/CHANGELOG.md
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
## [2.1.2] - 2025-12-27
|
|
2
|
-
|
|
3
|
-
### Changed
|
|
4
|
-
|
|
5
|
-
- Added `publish-alpha` Nx target to enable alpha publishing flow using common script.
|
|
6
|
-
|
|
7
|
-
## [2.1.1] - 2025-12-24
|
|
8
|
-
|
|
9
|
-
### Fixed
|
|
10
|
-
|
|
11
|
-
- Revised build setup to emit CJS and ESM bundles with corrected export map and sideEffects flag to improve tree shaking.
|
|
12
|
-
- Synced package entry points and type outputs with the new build artifacts while preserving the public API surface.
|
|
13
|
-
|
|
14
|
-
## [2.1.0] - 2025-12-19
|
|
15
|
-
|
|
16
|
-
### Added
|
|
17
|
-
|
|
18
|
-
- Introduced logger support within the OpenAPI adapter to improve observability.
|
|
19
|
-
- Expanded security handling with automatic auth type routing and enhanced documentation.
|
|
20
|
-
|
|
21
|
-
### Changed
|
|
22
|
-
|
|
23
|
-
- Refined security resolver examples and guidance for broader authentication scheme coverage.
|
|
24
|
-
|
|
25
|
-
## [2.0.0] - 2025-12-11
|
|
26
|
-
|
|
27
|
-
### Breaking
|
|
28
|
-
|
|
29
|
-
- Migrated to Zod v4 (now a peer dependency) and aligned JSON schema types with Zod’s v4 JSONSchema
|
|
30
|
-
- Renamed utility export `toJSONSchema7` to `toJsonSchema`, affecting consumers of the types/helpers
|
|
31
|
-
|
|
32
|
-
### Changed
|
|
33
|
-
|
|
34
|
-
- Updated SWC/Jest config to inline ES2022 settings and modernized tooling versions
|
|
35
|
-
- Adjusted exports formatting and minor parameter resolver refactors for consistency
|
|
36
|
-
|
|
37
|
-
# Changelog
|
|
38
|
-
|
|
39
|
-
## [1.0.0] - 2025-11-21
|
|
40
|
-
|
|
41
|
-
### Features
|
|
42
|
-
|
|
43
|
-
- Production-ready library for converting OpenAPI specifications into MCP tool definitions
|
|
44
|
-
- OpenAPI 3.0+ and Swagger 2.0 support
|
|
45
|
-
- Comprehensive operation parsing:
|
|
46
|
-
- RESTful endpoint detection (GET, POST, PUT, PATCH, DELETE, etc.)
|
|
47
|
-
- Path parameter extraction and validation
|
|
48
|
-
- Query parameter handling
|
|
49
|
-
- Request body schema conversion
|
|
50
|
-
- Response schema parsing
|
|
51
|
-
- Advanced OpenAPI features:
|
|
52
|
-
- Reference resolution ($ref) across the entire specification
|
|
53
|
-
- Security scheme detection and configuration
|
|
54
|
-
- Parameter conflict resolution
|
|
55
|
-
- Operation naming controls and customization
|
|
56
|
-
- Request mapper generation:
|
|
57
|
-
- Automatic parameter mapping from MCP tool inputs to HTTP requests
|
|
58
|
-
- Type-safe parameter handling
|
|
59
|
-
- Support for different parameter locations (path, query, header, cookie)
|
|
60
|
-
- Request body transformation
|
|
61
|
-
- Tool metadata generation:
|
|
62
|
-
- Descriptive tool names from operation IDs
|
|
63
|
-
- Documentation from OpenAPI descriptions
|
|
64
|
-
- Schema validation rules
|
|
65
|
-
- Multiple input formats:
|
|
66
|
-
- JSON OpenAPI specifications
|
|
67
|
-
- YAML OpenAPI specifications
|
|
68
|
-
- Inline specification objects
|
|
69
|
-
- URL references to remote specifications
|
|
70
|
-
- Type-safe TypeScript implementation
|
|
71
|
-
- Node.js 18+ compatibility
|
|
72
|
-
|
|
73
|
-
### Documentation
|
|
74
|
-
|
|
75
|
-
- Complete API reference
|
|
76
|
-
- OpenAPI conversion examples
|
|
77
|
-
- Integration guides for MCP servers
|
|
78
|
-
- Best practices for tool generation
|
|
79
|
-
|
|
80
|
-
This is the first official release of `mcp-from-openapi`, extracted from the FrontMCP framework to be published as a
|
|
81
|
-
standalone, reusable library for the community.
|