api2mcp 0.3.2 → 0.4.0-beta.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 +54 -1
- package/dist/{chunk-YPGEM247.mjs → chunk-7JKK7Z2Y.mjs} +714 -5
- package/dist/chunk-7JKK7Z2Y.mjs.map +1 -0
- package/dist/cli.js +709 -5
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +8 -2
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +409 -1
- package/dist/index.d.ts +409 -1
- package/dist/index.js +726 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +27 -1
- package/package.json +1 -1
- package/dist/chunk-YPGEM247.mjs.map +0 -1
|
@@ -131,7 +131,8 @@ function loadFromFile(workingDir = process.cwd()) {
|
|
|
131
131
|
timeout: parsed.timeout,
|
|
132
132
|
headers: parsed.headers,
|
|
133
133
|
toolPrefix: parsed.toolPrefix,
|
|
134
|
-
debug: parsed.debug
|
|
134
|
+
debug: parsed.debug,
|
|
135
|
+
mode: parsed.mode
|
|
135
136
|
};
|
|
136
137
|
} catch (error) {
|
|
137
138
|
throw new ConfigurationError(
|
|
@@ -162,6 +163,9 @@ function loadFromCli(args) {
|
|
|
162
163
|
if (args.debug !== void 0) {
|
|
163
164
|
config.debug = args.debug;
|
|
164
165
|
}
|
|
166
|
+
if (args.mode) {
|
|
167
|
+
config.mode = args.mode;
|
|
168
|
+
}
|
|
165
169
|
return config;
|
|
166
170
|
}
|
|
167
171
|
function mergeConfigs(...configs) {
|
|
@@ -176,6 +180,7 @@ function mergeConfigs(...configs) {
|
|
|
176
180
|
if (config.headers !== void 0) merged.headers = config.headers;
|
|
177
181
|
if (config.toolPrefix !== void 0) merged.toolPrefix = config.toolPrefix;
|
|
178
182
|
if (config.debug !== void 0) merged.debug = config.debug;
|
|
183
|
+
if (config.mode !== void 0) merged.mode = config.mode;
|
|
179
184
|
}
|
|
180
185
|
if (merged.timeout === void 0) {
|
|
181
186
|
merged.timeout = DEFAULT_TIMEOUT;
|
|
@@ -200,6 +205,7 @@ function loadConfig(cliArgs = {}, env = process.env) {
|
|
|
200
205
|
baseUrl: config.baseUrl,
|
|
201
206
|
timeout: config.timeout,
|
|
202
207
|
toolPrefix: config.toolPrefix,
|
|
208
|
+
mode: config.mode,
|
|
203
209
|
debug: config.debug
|
|
204
210
|
});
|
|
205
211
|
return config;
|
|
@@ -848,6 +854,568 @@ function getBaseUrl(doc, overrideUrl) {
|
|
|
848
854
|
return void 0;
|
|
849
855
|
}
|
|
850
856
|
|
|
857
|
+
// src/registry/api-registry.ts
|
|
858
|
+
var DEFAULT_PAGE_SIZE = 20;
|
|
859
|
+
var DEFAULT_SEARCH_LIMIT = 50;
|
|
860
|
+
var ApiRegistry = class {
|
|
861
|
+
apis = /* @__PURE__ */ new Map();
|
|
862
|
+
nameIndex = /* @__PURE__ */ new Map();
|
|
863
|
+
// name -> id
|
|
864
|
+
tagIndex = /* @__PURE__ */ new Map();
|
|
865
|
+
// tag -> set of ids
|
|
866
|
+
/**
|
|
867
|
+
* 注册 API
|
|
868
|
+
*/
|
|
869
|
+
register(entry) {
|
|
870
|
+
if (this.apis.has(entry.id)) {
|
|
871
|
+
logger.warn(`API already registered: ${entry.id}, overwriting`);
|
|
872
|
+
}
|
|
873
|
+
this.apis.set(entry.id, entry);
|
|
874
|
+
this.nameIndex.set(entry.name, entry.id);
|
|
875
|
+
if (entry.tags) {
|
|
876
|
+
for (const tag of entry.tags) {
|
|
877
|
+
if (!this.tagIndex.has(tag)) {
|
|
878
|
+
this.tagIndex.set(tag, /* @__PURE__ */ new Set());
|
|
879
|
+
}
|
|
880
|
+
this.tagIndex.get(tag)?.add(entry.id);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
logger.debug(`Registered API: ${entry.id}`);
|
|
884
|
+
}
|
|
885
|
+
/**
|
|
886
|
+
* 批量注册 API
|
|
887
|
+
*/
|
|
888
|
+
registerAll(entries) {
|
|
889
|
+
for (const entry of entries) {
|
|
890
|
+
this.register(entry);
|
|
891
|
+
}
|
|
892
|
+
logger.info(`Registered ${entries.length} APIs in registry`);
|
|
893
|
+
}
|
|
894
|
+
/**
|
|
895
|
+
* 获取单个 API
|
|
896
|
+
*/
|
|
897
|
+
get(id) {
|
|
898
|
+
return this.apis.get(id);
|
|
899
|
+
}
|
|
900
|
+
/**
|
|
901
|
+
* 通过名称获取 API
|
|
902
|
+
*/
|
|
903
|
+
getByName(name) {
|
|
904
|
+
const id = this.nameIndex.get(name);
|
|
905
|
+
return id ? this.apis.get(id) : void 0;
|
|
906
|
+
}
|
|
907
|
+
/**
|
|
908
|
+
* 检查 API 是否存在
|
|
909
|
+
*/
|
|
910
|
+
has(id) {
|
|
911
|
+
return this.apis.has(id);
|
|
912
|
+
}
|
|
913
|
+
/**
|
|
914
|
+
* 搜索 API
|
|
915
|
+
*/
|
|
916
|
+
search(options) {
|
|
917
|
+
const {
|
|
918
|
+
query,
|
|
919
|
+
searchIn = ["name", "summary", "description", "path"],
|
|
920
|
+
limit = DEFAULT_SEARCH_LIMIT
|
|
921
|
+
} = options;
|
|
922
|
+
const normalizedQuery = query.toLowerCase().trim();
|
|
923
|
+
const results = [];
|
|
924
|
+
for (const entry of this.apis.values()) {
|
|
925
|
+
const matchedFields = [];
|
|
926
|
+
let score = 0;
|
|
927
|
+
if (searchIn.includes("name") && entry.name) {
|
|
928
|
+
const nameLower = entry.name.toLowerCase();
|
|
929
|
+
if (nameLower.includes(normalizedQuery)) {
|
|
930
|
+
matchedFields.push("name");
|
|
931
|
+
score += nameLower === normalizedQuery ? 1 : 0.8;
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
if (searchIn.includes("summary") && entry.summary) {
|
|
935
|
+
const summaryLower = entry.summary.toLowerCase();
|
|
936
|
+
if (summaryLower.includes(normalizedQuery)) {
|
|
937
|
+
matchedFields.push("summary");
|
|
938
|
+
score += 0.6;
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
if (searchIn.includes("description") && entry.description) {
|
|
942
|
+
const descLower = entry.description.toLowerCase();
|
|
943
|
+
if (descLower.includes(normalizedQuery)) {
|
|
944
|
+
matchedFields.push("description");
|
|
945
|
+
score += 0.4;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
if (searchIn.includes("path") && entry.path) {
|
|
949
|
+
const pathLower = entry.path.toLowerCase();
|
|
950
|
+
if (pathLower.includes(normalizedQuery)) {
|
|
951
|
+
matchedFields.push("path");
|
|
952
|
+
score += 0.5;
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
if (matchedFields.length > 0) {
|
|
956
|
+
results.push({
|
|
957
|
+
id: entry.id,
|
|
958
|
+
name: entry.name,
|
|
959
|
+
method: entry.method,
|
|
960
|
+
path: entry.path,
|
|
961
|
+
summary: entry.summary,
|
|
962
|
+
matchedFields,
|
|
963
|
+
score: Math.min(score, 1)
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
results.sort((a, b) => b.score - a.score);
|
|
968
|
+
return results.slice(0, limit);
|
|
969
|
+
}
|
|
970
|
+
/**
|
|
971
|
+
* 分页列出 API
|
|
972
|
+
*/
|
|
973
|
+
list(options = {}) {
|
|
974
|
+
const { page = 1, pageSize = DEFAULT_PAGE_SIZE, tag } = options;
|
|
975
|
+
let entries;
|
|
976
|
+
if (tag) {
|
|
977
|
+
const ids = this.tagIndex.get(tag);
|
|
978
|
+
entries = ids ? Array.from(ids).map((id) => this.apis.get(id)).filter((entry) => entry !== void 0) : [];
|
|
979
|
+
} else {
|
|
980
|
+
entries = Array.from(this.apis.values());
|
|
981
|
+
}
|
|
982
|
+
const total = entries.length;
|
|
983
|
+
const totalPages = Math.ceil(total / pageSize);
|
|
984
|
+
const startIndex = (page - 1) * pageSize;
|
|
985
|
+
const endIndex = startIndex + pageSize;
|
|
986
|
+
const pageEntries = entries.slice(startIndex, endIndex);
|
|
987
|
+
const items = pageEntries.map((entry) => ({
|
|
988
|
+
id: entry.id,
|
|
989
|
+
name: entry.name,
|
|
990
|
+
method: entry.method,
|
|
991
|
+
path: entry.path,
|
|
992
|
+
summary: entry.summary,
|
|
993
|
+
tags: entry.tags,
|
|
994
|
+
deprecated: entry.deprecated
|
|
995
|
+
}));
|
|
996
|
+
return {
|
|
997
|
+
page,
|
|
998
|
+
pageSize,
|
|
999
|
+
total,
|
|
1000
|
+
totalPages,
|
|
1001
|
+
items
|
|
1002
|
+
};
|
|
1003
|
+
}
|
|
1004
|
+
/**
|
|
1005
|
+
* 获取所有标签
|
|
1006
|
+
*/
|
|
1007
|
+
getTags() {
|
|
1008
|
+
return Array.from(this.tagIndex.keys()).sort();
|
|
1009
|
+
}
|
|
1010
|
+
/**
|
|
1011
|
+
* 获取 API 详情
|
|
1012
|
+
*/
|
|
1013
|
+
getDetail(id) {
|
|
1014
|
+
const entry = this.apis.get(id);
|
|
1015
|
+
if (!entry) {
|
|
1016
|
+
return void 0;
|
|
1017
|
+
}
|
|
1018
|
+
return {
|
|
1019
|
+
...entry,
|
|
1020
|
+
parameterSchema: this.buildParameterSchema(entry),
|
|
1021
|
+
requestBodySchema: this.buildRequestBodySchema(entry),
|
|
1022
|
+
responseSchemas: this.buildResponseSchemas(entry)
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
1025
|
+
/**
|
|
1026
|
+
* 获取统计信息
|
|
1027
|
+
*/
|
|
1028
|
+
getStats() {
|
|
1029
|
+
const byMethod = {};
|
|
1030
|
+
const byTag = {};
|
|
1031
|
+
for (const entry of this.apis.values()) {
|
|
1032
|
+
const method = entry.method.toUpperCase();
|
|
1033
|
+
byMethod[method] = (byMethod[method] || 0) + 1;
|
|
1034
|
+
if (entry.tags) {
|
|
1035
|
+
for (const tag of entry.tags) {
|
|
1036
|
+
byTag[tag] = (byTag[tag] || 0) + 1;
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
return {
|
|
1041
|
+
totalApis: this.apis.size,
|
|
1042
|
+
tags: this.getTags(),
|
|
1043
|
+
byMethod,
|
|
1044
|
+
byTag
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
/**
|
|
1048
|
+
* 获取 API 数量
|
|
1049
|
+
*/
|
|
1050
|
+
get size() {
|
|
1051
|
+
return this.apis.size;
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* 构建参数 Schema
|
|
1055
|
+
*/
|
|
1056
|
+
buildParameterSchema(entry) {
|
|
1057
|
+
const { operation } = entry;
|
|
1058
|
+
if (!operation.parameters || operation.parameters.length === 0) {
|
|
1059
|
+
return void 0;
|
|
1060
|
+
}
|
|
1061
|
+
const properties = {};
|
|
1062
|
+
const required = [];
|
|
1063
|
+
for (const param of operation.parameters) {
|
|
1064
|
+
const paramName = param.name;
|
|
1065
|
+
properties[paramName] = {
|
|
1066
|
+
...param.schema,
|
|
1067
|
+
description: param.description,
|
|
1068
|
+
in: param.in
|
|
1069
|
+
};
|
|
1070
|
+
if (param.required) {
|
|
1071
|
+
required.push(paramName);
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
return {
|
|
1075
|
+
type: "object",
|
|
1076
|
+
properties,
|
|
1077
|
+
required: required.length > 0 ? required : void 0
|
|
1078
|
+
};
|
|
1079
|
+
}
|
|
1080
|
+
/**
|
|
1081
|
+
* 构建请求体 Schema
|
|
1082
|
+
*/
|
|
1083
|
+
buildRequestBodySchema(entry) {
|
|
1084
|
+
const { operation } = entry;
|
|
1085
|
+
if (!operation.requestBody) {
|
|
1086
|
+
return void 0;
|
|
1087
|
+
}
|
|
1088
|
+
const jsonContent = operation.requestBody.content["application/json"];
|
|
1089
|
+
if (!jsonContent?.schema) {
|
|
1090
|
+
return void 0;
|
|
1091
|
+
}
|
|
1092
|
+
return {
|
|
1093
|
+
...jsonContent.schema,
|
|
1094
|
+
description: operation.requestBody.description,
|
|
1095
|
+
required: operation.requestBody.required
|
|
1096
|
+
};
|
|
1097
|
+
}
|
|
1098
|
+
/**
|
|
1099
|
+
* 构建响应 Schema
|
|
1100
|
+
*/
|
|
1101
|
+
buildResponseSchemas(entry) {
|
|
1102
|
+
const { operation } = entry;
|
|
1103
|
+
if (!operation.responses) {
|
|
1104
|
+
return void 0;
|
|
1105
|
+
}
|
|
1106
|
+
const schemas = {};
|
|
1107
|
+
for (const [status, response] of Object.entries(operation.responses)) {
|
|
1108
|
+
const jsonContent = response.content?.["application/json"];
|
|
1109
|
+
schemas[status] = {
|
|
1110
|
+
description: response.description,
|
|
1111
|
+
schema: jsonContent?.schema
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
1114
|
+
return schemas;
|
|
1115
|
+
}
|
|
1116
|
+
};
|
|
1117
|
+
|
|
1118
|
+
// src/tools/discovery/api-detail.ts
|
|
1119
|
+
import { z as z3 } from "zod";
|
|
1120
|
+
var apiDetailSchema = z3.object({
|
|
1121
|
+
id: z3.string().min(1).describe("API ID\uFF08operationId \u6216\u5DE5\u5177\u540D\u79F0\uFF09")
|
|
1122
|
+
});
|
|
1123
|
+
var apiDetailTool = {
|
|
1124
|
+
name: "api_detail",
|
|
1125
|
+
description: `\u83B7\u53D6 API \u7684\u8BE6\u7EC6\u4FE1\u606F\u3002
|
|
1126
|
+
|
|
1127
|
+
\u4F7F\u7528\u573A\u666F\uFF1A
|
|
1128
|
+
- \u67E5\u770B\u67D0\u4E2A API \u7684\u5B8C\u6574\u53C2\u6570\u5B9A\u4E49
|
|
1129
|
+
- \u4E86\u89E3\u8BF7\u6C42\u4F53\u548C\u54CD\u5E94\u7684\u7ED3\u6784
|
|
1130
|
+
- \u5728\u8C03\u7528 API \u524D\u4E86\u89E3\u9700\u8981\u54EA\u4E9B\u53C2\u6570
|
|
1131
|
+
|
|
1132
|
+
\u8FD4\u56DE\u5185\u5BB9\u5305\u62EC\uFF1A
|
|
1133
|
+
- API \u57FA\u672C\u4FE1\u606F\uFF08\u65B9\u6CD5\u3001\u8DEF\u5F84\u3001\u63CF\u8FF0\uFF09
|
|
1134
|
+
- \u53C2\u6570 Schema\uFF08\u8DEF\u5F84\u53C2\u6570\u3001\u67E5\u8BE2\u53C2\u6570\u3001\u5934\u53C2\u6570\uFF09
|
|
1135
|
+
- \u8BF7\u6C42\u4F53 Schema
|
|
1136
|
+
- \u54CD\u5E94 Schema`,
|
|
1137
|
+
inputSchema: apiDetailSchema
|
|
1138
|
+
};
|
|
1139
|
+
function formatSchema(schema, indent = 0) {
|
|
1140
|
+
if (!schema) return "\u65E0";
|
|
1141
|
+
const spaces = " ".repeat(indent);
|
|
1142
|
+
const lines = [];
|
|
1143
|
+
if (schema.type) {
|
|
1144
|
+
lines.push(`${spaces}\u7C7B\u578B: ${schema.type}`);
|
|
1145
|
+
}
|
|
1146
|
+
if (schema.description) {
|
|
1147
|
+
lines.push(`${spaces}\u63CF\u8FF0: ${schema.description}`);
|
|
1148
|
+
}
|
|
1149
|
+
if (schema.properties) {
|
|
1150
|
+
lines.push(`${spaces}\u5C5E\u6027:`);
|
|
1151
|
+
const props = schema.properties;
|
|
1152
|
+
const required = schema.required || [];
|
|
1153
|
+
for (const [name, prop] of Object.entries(props)) {
|
|
1154
|
+
const isRequired = required.includes(name);
|
|
1155
|
+
const reqTag = isRequired ? " (\u5FC5\u586B)" : " (\u53EF\u9009)";
|
|
1156
|
+
const propType = prop.type || "unknown";
|
|
1157
|
+
const propDesc = prop.description ? ` - ${prop.description}` : "";
|
|
1158
|
+
lines.push(`${spaces} - ${name}${reqTag}: ${propType}${propDesc}`);
|
|
1159
|
+
if (prop.properties) {
|
|
1160
|
+
lines.push(formatSchema(prop, indent + 2));
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
if (schema.enum) {
|
|
1165
|
+
lines.push(`${spaces}\u679A\u4E3E\u503C: ${schema.enum.join(", ")}`);
|
|
1166
|
+
}
|
|
1167
|
+
if (schema.example !== void 0) {
|
|
1168
|
+
lines.push(`${spaces}\u793A\u4F8B: ${JSON.stringify(schema.example)}`);
|
|
1169
|
+
}
|
|
1170
|
+
return lines.join("\n");
|
|
1171
|
+
}
|
|
1172
|
+
function executeApiDetail(registry, input) {
|
|
1173
|
+
const { id } = input;
|
|
1174
|
+
logger.debug(`Executing api_detail: id=${id}`);
|
|
1175
|
+
const detail = registry.getDetail(id);
|
|
1176
|
+
if (!detail) {
|
|
1177
|
+
const byName = registry.getByName(id);
|
|
1178
|
+
if (byName) {
|
|
1179
|
+
return executeApiDetail(registry, { id: byName.id });
|
|
1180
|
+
}
|
|
1181
|
+
return `\u9519\u8BEF: \u627E\u4E0D\u5230 API "${id}"
|
|
1182
|
+
|
|
1183
|
+
\u8BF7\u4F7F\u7528 api_search \u641C\u7D22\u53EF\u7528\u7684 API\u3002`;
|
|
1184
|
+
}
|
|
1185
|
+
const lines = [];
|
|
1186
|
+
lines.push(`## API: ${detail.name}`);
|
|
1187
|
+
lines.push("");
|
|
1188
|
+
const methodBadge = `[${detail.method.toUpperCase()}]`;
|
|
1189
|
+
const deprecatedTag = detail.deprecated ? " \u26A0\uFE0F \u5DF2\u5E9F\u5F03" : "";
|
|
1190
|
+
lines.push(`**${methodBadge}** \`${detail.path}\`${deprecatedTag}`);
|
|
1191
|
+
lines.push("");
|
|
1192
|
+
if (detail.summary) {
|
|
1193
|
+
lines.push(`**\u6458\u8981**: ${detail.summary}`);
|
|
1194
|
+
lines.push("");
|
|
1195
|
+
}
|
|
1196
|
+
if (detail.description) {
|
|
1197
|
+
lines.push(`**\u63CF\u8FF0**: ${detail.description}`);
|
|
1198
|
+
lines.push("");
|
|
1199
|
+
}
|
|
1200
|
+
if (detail.tags && detail.tags.length > 0) {
|
|
1201
|
+
lines.push(`**\u6807\u7B7E**: ${detail.tags.map((t) => `\`${t}\``).join(", ")}`);
|
|
1202
|
+
lines.push("");
|
|
1203
|
+
}
|
|
1204
|
+
lines.push("### \u53C2\u6570");
|
|
1205
|
+
lines.push("");
|
|
1206
|
+
if (detail.parameterSchema) {
|
|
1207
|
+
lines.push(formatSchema(detail.parameterSchema));
|
|
1208
|
+
} else {
|
|
1209
|
+
lines.push("\u65E0\u53C2\u6570");
|
|
1210
|
+
}
|
|
1211
|
+
lines.push("");
|
|
1212
|
+
if (detail.requestBodySchema) {
|
|
1213
|
+
lines.push("### \u8BF7\u6C42\u4F53");
|
|
1214
|
+
lines.push("");
|
|
1215
|
+
lines.push(formatSchema(detail.requestBodySchema));
|
|
1216
|
+
lines.push("");
|
|
1217
|
+
}
|
|
1218
|
+
if (detail.responseSchemas && Object.keys(detail.responseSchemas).length > 0) {
|
|
1219
|
+
lines.push("### \u54CD\u5E94");
|
|
1220
|
+
lines.push("");
|
|
1221
|
+
for (const [status, resp] of Object.entries(detail.responseSchemas)) {
|
|
1222
|
+
lines.push(`#### \u72B6\u6001\u7801: ${status}`);
|
|
1223
|
+
if (resp.description) {
|
|
1224
|
+
lines.push(`${resp.description}`);
|
|
1225
|
+
}
|
|
1226
|
+
if (resp.schema) {
|
|
1227
|
+
lines.push(formatSchema(resp.schema, 1));
|
|
1228
|
+
}
|
|
1229
|
+
lines.push("");
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
lines.push("---");
|
|
1233
|
+
lines.push("### \u8C03\u7528\u65B9\u5F0F");
|
|
1234
|
+
lines.push("");
|
|
1235
|
+
lines.push("\u4F7F\u7528 api_execute \u5DE5\u5177\u8C03\u7528\u6B64 API:");
|
|
1236
|
+
lines.push("```");
|
|
1237
|
+
lines.push(`api_execute(operationId="${detail.id}", parameters={...})`);
|
|
1238
|
+
lines.push("```");
|
|
1239
|
+
return lines.join("\n");
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
// src/tools/discovery/api-execute.ts
|
|
1243
|
+
import { z as z4 } from "zod";
|
|
1244
|
+
var apiExecuteSchema = z4.object({
|
|
1245
|
+
operationId: z4.string().min(1).describe("API ID\uFF08operationId \u6216\u5DE5\u5177\u540D\u79F0\uFF09"),
|
|
1246
|
+
parameters: z4.record(z4.unknown()).optional().describe("API \u53C2\u6570\uFF08\u8DEF\u5F84\u53C2\u6570\u3001\u67E5\u8BE2\u53C2\u6570\u3001\u8BF7\u6C42\u4F53\u7B49\uFF09"),
|
|
1247
|
+
_baseUrl: z4.string().url().optional().describe("API base URL\uFF08\u53EF\u9009\uFF0C\u8986\u76D6\u9ED8\u8BA4\u914D\u7F6E\uFF09")
|
|
1248
|
+
});
|
|
1249
|
+
var apiExecuteTool = {
|
|
1250
|
+
name: "api_execute",
|
|
1251
|
+
description: `\u6267\u884C API \u8C03\u7528\u3002
|
|
1252
|
+
|
|
1253
|
+
\u4F7F\u7528\u573A\u666F\uFF1A
|
|
1254
|
+
- \u76F4\u63A5\u8C03\u7528\u5DF2\u77E5\u7684 API
|
|
1255
|
+
- \u4F7F\u7528 api_search \u6216 api_list \u627E\u5230 API \u540E\u6267\u884C\u8C03\u7528
|
|
1256
|
+
|
|
1257
|
+
\u4F7F\u7528\u6B65\u9AA4\uFF1A
|
|
1258
|
+
1. \u5148\u4F7F\u7528 api_search \u6216 api_list \u627E\u5230\u9700\u8981\u7684 API
|
|
1259
|
+
2. \u4F7F\u7528 api_detail \u67E5\u770B\u53C2\u6570\u8981\u6C42
|
|
1260
|
+
3. \u4F7F\u7528 api_execute \u6267\u884C\u8C03\u7528
|
|
1261
|
+
|
|
1262
|
+
\u53C2\u6570\u8BF4\u660E\uFF1A
|
|
1263
|
+
- operationId: API \u7684\u552F\u4E00\u6807\u8BC6\u7B26
|
|
1264
|
+
- parameters: \u5305\u542B\u8DEF\u5F84\u53C2\u6570\u3001\u67E5\u8BE2\u53C2\u6570\u3001\u8BF7\u6C42\u4F53\u7B49
|
|
1265
|
+
- \u8DEF\u5F84\u53C2\u6570: URL \u8DEF\u5F84\u4E2D\u7684\u53C2\u6570 (\u5982 /users/{id} \u4E2D\u7684 id)
|
|
1266
|
+
- \u67E5\u8BE2\u53C2\u6570: URL \u95EE\u53F7\u540E\u7684\u53C2\u6570
|
|
1267
|
+
- body: \u8BF7\u6C42\u4F53\uFF08JSON \u5BF9\u8C61\uFF09`,
|
|
1268
|
+
inputSchema: apiExecuteSchema
|
|
1269
|
+
};
|
|
1270
|
+
async function executeApiExecute(registry, config, input) {
|
|
1271
|
+
const { operationId, parameters = {}, _baseUrl } = input;
|
|
1272
|
+
logger.debug(`Executing api_execute: operationId=${operationId}`);
|
|
1273
|
+
let apiEntry = registry.get(operationId);
|
|
1274
|
+
if (!apiEntry) {
|
|
1275
|
+
apiEntry = registry.getByName(operationId);
|
|
1276
|
+
}
|
|
1277
|
+
if (!apiEntry) {
|
|
1278
|
+
return `\u9519\u8BEF: \u627E\u4E0D\u5230 API "${operationId}"
|
|
1279
|
+
|
|
1280
|
+
\u8BF7\u4F7F\u7528 api_search \u641C\u7D22\u53EF\u7528\u7684 API\u3002`;
|
|
1281
|
+
}
|
|
1282
|
+
if (apiEntry.deprecated) {
|
|
1283
|
+
logger.warn(`API ${operationId} is deprecated`);
|
|
1284
|
+
}
|
|
1285
|
+
try {
|
|
1286
|
+
const executionConfig = {
|
|
1287
|
+
...config,
|
|
1288
|
+
baseUrl: _baseUrl || config.baseUrl
|
|
1289
|
+
};
|
|
1290
|
+
if (!executionConfig.baseUrl) {
|
|
1291
|
+
return `\u9519\u8BEF: \u6CA1\u6709\u914D\u7F6E base URL
|
|
1292
|
+
|
|
1293
|
+
\u8BF7\u901A\u8FC7\u4EE5\u4E0B\u65B9\u5F0F\u4E4B\u4E00\u63D0\u4F9B base URL:
|
|
1294
|
+
1. \u5728\u914D\u7F6E\u6587\u4EF6\u4E2D\u8BBE\u7F6E baseUrl
|
|
1295
|
+
2. \u542F\u52A8\u65F6\u4F7F\u7528 --base-url \u53C2\u6570
|
|
1296
|
+
3. \u8C03\u7528\u65F6\u63D0\u4F9B _baseUrl \u53C2\u6570`;
|
|
1297
|
+
}
|
|
1298
|
+
logger.info(`Executing API: ${apiEntry.method} ${apiEntry.path}`);
|
|
1299
|
+
const response = await executeRequest(apiEntry.operation, parameters, executionConfig);
|
|
1300
|
+
const formattedResponse = formatResponse(response);
|
|
1301
|
+
return formattedResponse;
|
|
1302
|
+
} catch (error) {
|
|
1303
|
+
const errorMessage = error instanceof ToolExecutionError ? `\u9519\u8BEF: ${error.message}` : `\u9519\u8BEF: ${error instanceof Error ? error.message : "\u672A\u77E5\u9519\u8BEF"}`;
|
|
1304
|
+
logger.error(`API execution failed: ${operationId}`, error);
|
|
1305
|
+
return errorMessage;
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
// src/tools/discovery/api-list.ts
|
|
1310
|
+
import { z as z5 } from "zod";
|
|
1311
|
+
var apiListSchema = z5.object({
|
|
1312
|
+
page: z5.number().int().min(1).default(1).describe("\u9875\u7801\uFF08\u4ECE 1 \u5F00\u59CB\uFF09"),
|
|
1313
|
+
pageSize: z5.number().int().min(1).max(100).default(20).describe("\u6BCF\u9875\u6570\u91CF\uFF081-100\uFF09"),
|
|
1314
|
+
tag: z5.string().optional().describe("\u6309\u6807\u7B7E\u8FC7\u6EE4")
|
|
1315
|
+
});
|
|
1316
|
+
var apiListTool = {
|
|
1317
|
+
name: "api_list",
|
|
1318
|
+
description: `\u5206\u9875\u6D4F\u89C8\u6240\u6709\u53EF\u7528\u7684 API\u3002
|
|
1319
|
+
|
|
1320
|
+
\u4F7F\u7528\u573A\u666F\uFF1A
|
|
1321
|
+
- \u67E5\u770B\u6709\u54EA\u4E9B API \u53EF\u7528
|
|
1322
|
+
- \u6309\u6807\u7B7E\u8FC7\u6EE4 API
|
|
1323
|
+
- \u6D4F\u89C8 API \u5217\u8868\u4EE5\u627E\u5230\u9700\u8981\u7684\u63A5\u53E3
|
|
1324
|
+
|
|
1325
|
+
\u8FD4\u56DE\u5185\u5BB9\u5305\u62EC\uFF1AAPI ID\u3001\u540D\u79F0\u3001HTTP \u65B9\u6CD5\u3001\u8DEF\u5F84\u3001\u6458\u8981\u3001\u6807\u7B7E\u7B49\u3002`,
|
|
1326
|
+
inputSchema: apiListSchema
|
|
1327
|
+
};
|
|
1328
|
+
function executeApiList(registry, input) {
|
|
1329
|
+
const { page, pageSize, tag } = input;
|
|
1330
|
+
logger.debug(`Executing api_list: page=${page}, pageSize=${pageSize}, tag=${tag}`);
|
|
1331
|
+
const result = registry.list({ page, pageSize, tag });
|
|
1332
|
+
const lines = [];
|
|
1333
|
+
lines.push(`## API \u5217\u8868 (${result.total} \u4E2A API)`);
|
|
1334
|
+
lines.push(`\u9875\u7801: ${result.page}/${result.totalPages}`);
|
|
1335
|
+
if (tag) {
|
|
1336
|
+
lines.push(`\u6807\u7B7E\u8FC7\u6EE4: ${tag}`);
|
|
1337
|
+
}
|
|
1338
|
+
lines.push("");
|
|
1339
|
+
if (result.items.length === 0) {
|
|
1340
|
+
lines.push("\u6CA1\u6709\u627E\u5230\u5339\u914D\u7684 API\u3002");
|
|
1341
|
+
return lines.join("\n");
|
|
1342
|
+
}
|
|
1343
|
+
for (const item of result.items) {
|
|
1344
|
+
const methodBadge = `[${item.method.toUpperCase().padEnd(6)}]`;
|
|
1345
|
+
const deprecatedTag = item.deprecated ? " [\u5DF2\u5E9F\u5F03]" : "";
|
|
1346
|
+
const tags = item.tags ? ` (${item.tags.join(", ")})` : "";
|
|
1347
|
+
lines.push(`### ${item.id}`);
|
|
1348
|
+
lines.push(`${methodBadge} ${item.path}${deprecatedTag}${tags}`);
|
|
1349
|
+
if (item.summary) {
|
|
1350
|
+
lines.push(`${item.summary}`);
|
|
1351
|
+
}
|
|
1352
|
+
lines.push("");
|
|
1353
|
+
}
|
|
1354
|
+
if (result.totalPages > 1) {
|
|
1355
|
+
lines.push("---");
|
|
1356
|
+
if (result.page < result.totalPages) {
|
|
1357
|
+
lines.push(`\u4F7F\u7528 page=${result.page + 1} \u67E5\u770B\u4E0B\u4E00\u9875`);
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
return lines.join("\n");
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
// src/tools/discovery/api-search.ts
|
|
1364
|
+
import { z as z6 } from "zod";
|
|
1365
|
+
var apiSearchSchema = z6.object({
|
|
1366
|
+
query: z6.string().min(1).describe("\u641C\u7D22\u5173\u952E\u8BCD"),
|
|
1367
|
+
searchIn: z6.array(z6.enum(["name", "summary", "description", "path"])).optional().default(["name", "summary", "description", "path"]).describe("\u641C\u7D22\u8303\u56F4\uFF08\u9ED8\u8BA4\u641C\u7D22\u6240\u6709\u5B57\u6BB5\uFF09"),
|
|
1368
|
+
limit: z6.number().int().min(1).max(100).optional().default(20).describe("\u6700\u5927\u8FD4\u56DE\u6570\u91CF\uFF081-100\uFF09")
|
|
1369
|
+
});
|
|
1370
|
+
var apiSearchTool = {
|
|
1371
|
+
name: "api_search",
|
|
1372
|
+
description: `\u641C\u7D22 API\u3002
|
|
1373
|
+
|
|
1374
|
+
\u4F7F\u7528\u573A\u666F\uFF1A
|
|
1375
|
+
- \u6839\u636E\u5173\u952E\u8BCD\u5FEB\u901F\u627E\u5230\u76F8\u5173 API
|
|
1376
|
+
- \u641C\u7D22\u7279\u5B9A\u529F\u80FD\u6216\u8D44\u6E90\u7684\u63A5\u53E3
|
|
1377
|
+
- \u67E5\u627E\u5305\u542B\u7279\u5B9A\u8DEF\u5F84\u6BB5\u7684 API
|
|
1378
|
+
|
|
1379
|
+
\u641C\u7D22\u8303\u56F4\u5305\u62EC\uFF1AAPI \u540D\u79F0\u3001\u6458\u8981\u3001\u63CF\u8FF0\u3001\u8DEF\u5F84\u3002
|
|
1380
|
+
\u7ED3\u679C\u6309\u5339\u914D\u5EA6\u6392\u5E8F\uFF0C\u6700\u5339\u914D\u7684\u6392\u5728\u524D\u9762\u3002`,
|
|
1381
|
+
inputSchema: apiSearchSchema
|
|
1382
|
+
};
|
|
1383
|
+
function executeApiSearch(registry, input) {
|
|
1384
|
+
const { query, searchIn, limit } = input;
|
|
1385
|
+
logger.debug(
|
|
1386
|
+
`Executing api_search: query="${query}", searchIn=${searchIn?.join(",")}, limit=${limit}`
|
|
1387
|
+
);
|
|
1388
|
+
const results = registry.search({ query, searchIn, limit });
|
|
1389
|
+
const lines = [];
|
|
1390
|
+
lines.push(`## \u641C\u7D22\u7ED3\u679C: "${query}"`);
|
|
1391
|
+
lines.push(`\u627E\u5230 ${results.length} \u4E2A\u5339\u914D\u7684 API`);
|
|
1392
|
+
lines.push("");
|
|
1393
|
+
if (results.length === 0) {
|
|
1394
|
+
lines.push("\u6CA1\u6709\u627E\u5230\u5339\u914D\u7684 API\u3002");
|
|
1395
|
+
lines.push("");
|
|
1396
|
+
lines.push("\u5EFA\u8BAE\uFF1A");
|
|
1397
|
+
lines.push("- \u5C1D\u8BD5\u4F7F\u7528\u4E0D\u540C\u7684\u5173\u952E\u8BCD");
|
|
1398
|
+
lines.push("- \u68C0\u67E5\u62FC\u5199\u662F\u5426\u6B63\u786E");
|
|
1399
|
+
lines.push("- \u4F7F\u7528\u66F4\u901A\u7528\u7684\u641C\u7D22\u8BCD");
|
|
1400
|
+
return lines.join("\n");
|
|
1401
|
+
}
|
|
1402
|
+
for (const item of results) {
|
|
1403
|
+
const methodBadge = `[${item.method.toUpperCase().padEnd(6)}]`;
|
|
1404
|
+
const matchInfo = `\u5339\u914D\u5B57\u6BB5: ${item.matchedFields.join(", ")}`;
|
|
1405
|
+
lines.push(`### ${item.id}`);
|
|
1406
|
+
lines.push(`${methodBadge} ${item.path}`);
|
|
1407
|
+
if (item.summary) {
|
|
1408
|
+
lines.push(`${item.summary}`);
|
|
1409
|
+
}
|
|
1410
|
+
lines.push(`_${matchInfo}_ (\u76F8\u5173\u5EA6: ${Math.round(item.score * 100)}%)`);
|
|
1411
|
+
lines.push("");
|
|
1412
|
+
}
|
|
1413
|
+
lines.push("---");
|
|
1414
|
+
lines.push("\u4F7F\u7528 api_detail <id> \u67E5\u770B API \u8BE6\u60C5");
|
|
1415
|
+
lines.push("\u4F7F\u7528 api_execute <id> <parameters> \u6267\u884C API");
|
|
1416
|
+
return lines.join("\n");
|
|
1417
|
+
}
|
|
1418
|
+
|
|
851
1419
|
// src/server/tool-manager.ts
|
|
852
1420
|
var ToolManager = class {
|
|
853
1421
|
tools = /* @__PURE__ */ new Map();
|
|
@@ -884,6 +1452,23 @@ var ToolManager = class {
|
|
|
884
1452
|
}
|
|
885
1453
|
logger.info(`Registered ${tools.length} tools`);
|
|
886
1454
|
}
|
|
1455
|
+
/**
|
|
1456
|
+
* 获取工具
|
|
1457
|
+
*/
|
|
1458
|
+
getTool(name) {
|
|
1459
|
+
return this.tools.get(name);
|
|
1460
|
+
}
|
|
1461
|
+
/**
|
|
1462
|
+
* 通过 operationId 获取工具
|
|
1463
|
+
*/
|
|
1464
|
+
getToolByOperationId(operationId) {
|
|
1465
|
+
for (const tool of this.tools.values()) {
|
|
1466
|
+
if (tool.operation.operationId === operationId) {
|
|
1467
|
+
return tool;
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
return void 0;
|
|
1471
|
+
}
|
|
887
1472
|
/**
|
|
888
1473
|
* 执行工具
|
|
889
1474
|
*/
|
|
@@ -929,6 +1514,40 @@ var ToolManager = class {
|
|
|
929
1514
|
};
|
|
930
1515
|
}
|
|
931
1516
|
}
|
|
1517
|
+
/**
|
|
1518
|
+
* 通过 operation 直接执行(用于 ondemand 模式)
|
|
1519
|
+
*/
|
|
1520
|
+
async executeByOperation(operation, args) {
|
|
1521
|
+
try {
|
|
1522
|
+
logger.debug(`Executing operation: ${operation.operationId || operation.path}`, args);
|
|
1523
|
+
const { _baseUrl, ...restArgs } = args;
|
|
1524
|
+
const executionConfig = {
|
|
1525
|
+
...this.config,
|
|
1526
|
+
baseUrl: typeof _baseUrl === "string" ? _baseUrl : this.config.baseUrl
|
|
1527
|
+
};
|
|
1528
|
+
const response = await executeRequest(operation, restArgs, executionConfig);
|
|
1529
|
+
const formattedResponse = formatResponse(response);
|
|
1530
|
+
return {
|
|
1531
|
+
content: [
|
|
1532
|
+
{
|
|
1533
|
+
type: "text",
|
|
1534
|
+
text: formattedResponse
|
|
1535
|
+
}
|
|
1536
|
+
]
|
|
1537
|
+
};
|
|
1538
|
+
} catch (error) {
|
|
1539
|
+
const errorMessage = error instanceof ToolExecutionError ? `Error: ${error.message}` : `Error: ${error instanceof Error ? error.message : "Unknown error"}`;
|
|
1540
|
+
logger.error(`Operation execution failed: ${operation.operationId || operation.path}`, error);
|
|
1541
|
+
return {
|
|
1542
|
+
content: [
|
|
1543
|
+
{
|
|
1544
|
+
type: "text",
|
|
1545
|
+
text: errorMessage
|
|
1546
|
+
}
|
|
1547
|
+
]
|
|
1548
|
+
};
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
932
1551
|
/**
|
|
933
1552
|
* 获取所有已注册的工具名称
|
|
934
1553
|
*/
|
|
@@ -941,13 +1560,82 @@ var ToolManager = class {
|
|
|
941
1560
|
getToolCount() {
|
|
942
1561
|
return this.tools.size;
|
|
943
1562
|
}
|
|
1563
|
+
/**
|
|
1564
|
+
* 获取配置
|
|
1565
|
+
*/
|
|
1566
|
+
getConfig() {
|
|
1567
|
+
return this.config;
|
|
1568
|
+
}
|
|
944
1569
|
};
|
|
945
1570
|
|
|
946
1571
|
// src/server/index.ts
|
|
947
1572
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
948
1573
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
1574
|
+
function createRegistry(operations, components) {
|
|
1575
|
+
const registry = new ApiRegistry();
|
|
1576
|
+
for (const tool of operations) {
|
|
1577
|
+
const entry = {
|
|
1578
|
+
id: tool.operation.operationId || tool.name,
|
|
1579
|
+
name: tool.name,
|
|
1580
|
+
method: tool.operation.method,
|
|
1581
|
+
path: tool.operation.path,
|
|
1582
|
+
summary: tool.operation.summary,
|
|
1583
|
+
description: tool.operation.description,
|
|
1584
|
+
tags: tool.operation.tags,
|
|
1585
|
+
deprecated: tool.operation.deprecated,
|
|
1586
|
+
operation: tool.operation,
|
|
1587
|
+
components
|
|
1588
|
+
};
|
|
1589
|
+
registry.register(entry);
|
|
1590
|
+
}
|
|
1591
|
+
return registry;
|
|
1592
|
+
}
|
|
1593
|
+
function registerOndemandTools(server, registry, config) {
|
|
1594
|
+
server.tool(
|
|
1595
|
+
apiListTool.name,
|
|
1596
|
+
apiListTool.description,
|
|
1597
|
+
apiListSchema.shape,
|
|
1598
|
+
async (args) => {
|
|
1599
|
+
const result = executeApiList(registry, args);
|
|
1600
|
+
return { content: [{ type: "text", text: result }] };
|
|
1601
|
+
}
|
|
1602
|
+
);
|
|
1603
|
+
server.tool(
|
|
1604
|
+
apiSearchTool.name,
|
|
1605
|
+
apiSearchTool.description,
|
|
1606
|
+
apiSearchSchema.shape,
|
|
1607
|
+
async (args) => {
|
|
1608
|
+
const result = executeApiSearch(registry, args);
|
|
1609
|
+
return { content: [{ type: "text", text: result }] };
|
|
1610
|
+
}
|
|
1611
|
+
);
|
|
1612
|
+
server.tool(
|
|
1613
|
+
apiDetailTool.name,
|
|
1614
|
+
apiDetailTool.description,
|
|
1615
|
+
apiDetailSchema.shape,
|
|
1616
|
+
async (args) => {
|
|
1617
|
+
const result = executeApiDetail(registry, args);
|
|
1618
|
+
return { content: [{ type: "text", text: result }] };
|
|
1619
|
+
}
|
|
1620
|
+
);
|
|
1621
|
+
server.tool(
|
|
1622
|
+
apiExecuteTool.name,
|
|
1623
|
+
apiExecuteTool.description,
|
|
1624
|
+
apiExecuteSchema.shape,
|
|
1625
|
+
async (args) => {
|
|
1626
|
+
const result = await executeApiExecute(
|
|
1627
|
+
registry,
|
|
1628
|
+
config,
|
|
1629
|
+
args
|
|
1630
|
+
);
|
|
1631
|
+
return { content: [{ type: "text", text: result }] };
|
|
1632
|
+
}
|
|
1633
|
+
);
|
|
1634
|
+
logger.info("Registered 4 discovery tools (ondemand mode)");
|
|
1635
|
+
}
|
|
949
1636
|
async function createServer(config) {
|
|
950
1637
|
logger.info("Creating MCP server...");
|
|
1638
|
+
logger.info(`Mode: ${config.mode || "default"}`);
|
|
951
1639
|
const server = new McpServer({
|
|
952
1640
|
name: "api2mcp",
|
|
953
1641
|
version: "0.1.0"
|
|
@@ -963,9 +1651,17 @@ async function createServer(config) {
|
|
|
963
1651
|
openApiDoc.components?.schemas,
|
|
964
1652
|
config.toolPrefix
|
|
965
1653
|
);
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
1654
|
+
if (config.mode === "ondemand") {
|
|
1655
|
+
const registry = createRegistry(tools, openApiDoc.components?.schemas);
|
|
1656
|
+
registerOndemandTools(server, registry, effectiveConfig);
|
|
1657
|
+
const stats = registry.getStats();
|
|
1658
|
+
logger.info(`Server ready with ${stats.totalApis} APIs in registry`);
|
|
1659
|
+
logger.info(`Tags: ${stats.tags.slice(0, 5).join(", ")}${stats.tags.length > 5 ? "..." : ""}`);
|
|
1660
|
+
} else {
|
|
1661
|
+
const toolManager = new ToolManager(server, effectiveConfig);
|
|
1662
|
+
toolManager.registerTools(tools);
|
|
1663
|
+
logger.info(`Server ready with ${toolManager.getToolCount()} tools`);
|
|
1664
|
+
}
|
|
969
1665
|
return server;
|
|
970
1666
|
}
|
|
971
1667
|
async function startServer(config) {
|
|
@@ -991,8 +1687,21 @@ export {
|
|
|
991
1687
|
formatResponse,
|
|
992
1688
|
parseOpenApi,
|
|
993
1689
|
getBaseUrl,
|
|
1690
|
+
ApiRegistry,
|
|
1691
|
+
apiDetailSchema,
|
|
1692
|
+
apiDetailTool,
|
|
1693
|
+
executeApiDetail,
|
|
1694
|
+
apiExecuteSchema,
|
|
1695
|
+
apiExecuteTool,
|
|
1696
|
+
executeApiExecute,
|
|
1697
|
+
apiListSchema,
|
|
1698
|
+
apiListTool,
|
|
1699
|
+
executeApiList,
|
|
1700
|
+
apiSearchSchema,
|
|
1701
|
+
apiSearchTool,
|
|
1702
|
+
executeApiSearch,
|
|
994
1703
|
ToolManager,
|
|
995
1704
|
createServer,
|
|
996
1705
|
startServer
|
|
997
1706
|
};
|
|
998
|
-
//# sourceMappingURL=chunk-
|
|
1707
|
+
//# sourceMappingURL=chunk-7JKK7Z2Y.mjs.map
|