api2mcp 0.3.2 → 0.4.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-UQT2XNCH.mjs} +719 -5
- package/dist/chunk-UQT2XNCH.mjs.map +1 -0
- package/dist/cli.js +714 -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 +731 -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
package/dist/cli.js
CHANGED
|
@@ -161,7 +161,8 @@ function loadFromFile(workingDir = process.cwd()) {
|
|
|
161
161
|
timeout: parsed.timeout,
|
|
162
162
|
headers: parsed.headers,
|
|
163
163
|
toolPrefix: parsed.toolPrefix,
|
|
164
|
-
debug: parsed.debug
|
|
164
|
+
debug: parsed.debug,
|
|
165
|
+
mode: parsed.mode
|
|
165
166
|
};
|
|
166
167
|
} catch (error) {
|
|
167
168
|
throw new ConfigurationError(
|
|
@@ -192,6 +193,9 @@ function loadFromCli(args) {
|
|
|
192
193
|
if (args.debug !== void 0) {
|
|
193
194
|
config.debug = args.debug;
|
|
194
195
|
}
|
|
196
|
+
if (args.mode) {
|
|
197
|
+
config.mode = args.mode;
|
|
198
|
+
}
|
|
195
199
|
return config;
|
|
196
200
|
}
|
|
197
201
|
function mergeConfigs(...configs) {
|
|
@@ -206,6 +210,7 @@ function mergeConfigs(...configs) {
|
|
|
206
210
|
if (config.headers !== void 0) merged.headers = config.headers;
|
|
207
211
|
if (config.toolPrefix !== void 0) merged.toolPrefix = config.toolPrefix;
|
|
208
212
|
if (config.debug !== void 0) merged.debug = config.debug;
|
|
213
|
+
if (config.mode !== void 0) merged.mode = config.mode;
|
|
209
214
|
}
|
|
210
215
|
if (merged.timeout === void 0) {
|
|
211
216
|
merged.timeout = DEFAULT_TIMEOUT;
|
|
@@ -230,6 +235,7 @@ function loadConfig(cliArgs = {}, env = process.env) {
|
|
|
230
235
|
baseUrl: config.baseUrl,
|
|
231
236
|
timeout: config.timeout,
|
|
232
237
|
toolPrefix: config.toolPrefix,
|
|
238
|
+
mode: config.mode,
|
|
233
239
|
debug: config.debug
|
|
234
240
|
});
|
|
235
241
|
return config;
|
|
@@ -693,6 +699,399 @@ function getBaseUrl(doc, overrideUrl) {
|
|
|
693
699
|
return void 0;
|
|
694
700
|
}
|
|
695
701
|
|
|
702
|
+
// src/registry/api-registry.ts
|
|
703
|
+
var DEFAULT_PAGE_SIZE = 20;
|
|
704
|
+
var DEFAULT_SEARCH_LIMIT = 50;
|
|
705
|
+
var ApiRegistry = class {
|
|
706
|
+
apis = /* @__PURE__ */ new Map();
|
|
707
|
+
nameIndex = /* @__PURE__ */ new Map();
|
|
708
|
+
// name -> id
|
|
709
|
+
tagIndex = /* @__PURE__ */ new Map();
|
|
710
|
+
// tag -> set of ids
|
|
711
|
+
/**
|
|
712
|
+
* 注册 API
|
|
713
|
+
*/
|
|
714
|
+
register(entry) {
|
|
715
|
+
if (this.apis.has(entry.id)) {
|
|
716
|
+
logger.warn(`API already registered: ${entry.id}, overwriting`);
|
|
717
|
+
}
|
|
718
|
+
this.apis.set(entry.id, entry);
|
|
719
|
+
this.nameIndex.set(entry.name, entry.id);
|
|
720
|
+
if (entry.tags) {
|
|
721
|
+
for (const tag of entry.tags) {
|
|
722
|
+
if (!this.tagIndex.has(tag)) {
|
|
723
|
+
this.tagIndex.set(tag, /* @__PURE__ */ new Set());
|
|
724
|
+
}
|
|
725
|
+
this.tagIndex.get(tag)?.add(entry.id);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
logger.debug(`Registered API: ${entry.id}`);
|
|
729
|
+
}
|
|
730
|
+
/**
|
|
731
|
+
* 批量注册 API
|
|
732
|
+
*/
|
|
733
|
+
registerAll(entries) {
|
|
734
|
+
for (const entry of entries) {
|
|
735
|
+
this.register(entry);
|
|
736
|
+
}
|
|
737
|
+
logger.info(`Registered ${entries.length} APIs in registry`);
|
|
738
|
+
}
|
|
739
|
+
/**
|
|
740
|
+
* 获取单个 API
|
|
741
|
+
*/
|
|
742
|
+
get(id) {
|
|
743
|
+
return this.apis.get(id);
|
|
744
|
+
}
|
|
745
|
+
/**
|
|
746
|
+
* 通过名称获取 API
|
|
747
|
+
*/
|
|
748
|
+
getByName(name) {
|
|
749
|
+
const id = this.nameIndex.get(name);
|
|
750
|
+
return id ? this.apis.get(id) : void 0;
|
|
751
|
+
}
|
|
752
|
+
/**
|
|
753
|
+
* 检查 API 是否存在
|
|
754
|
+
*/
|
|
755
|
+
has(id) {
|
|
756
|
+
return this.apis.has(id);
|
|
757
|
+
}
|
|
758
|
+
/**
|
|
759
|
+
* 搜索 API
|
|
760
|
+
*/
|
|
761
|
+
search(options) {
|
|
762
|
+
const {
|
|
763
|
+
query,
|
|
764
|
+
searchIn = ["name", "summary", "description", "path"],
|
|
765
|
+
limit = DEFAULT_SEARCH_LIMIT
|
|
766
|
+
} = options;
|
|
767
|
+
const normalizedQuery = query.toLowerCase().trim();
|
|
768
|
+
const results = [];
|
|
769
|
+
for (const entry of this.apis.values()) {
|
|
770
|
+
const matchedFields = [];
|
|
771
|
+
let score = 0;
|
|
772
|
+
if (searchIn.includes("name") && entry.name) {
|
|
773
|
+
const nameLower = entry.name.toLowerCase();
|
|
774
|
+
if (nameLower.includes(normalizedQuery)) {
|
|
775
|
+
matchedFields.push("name");
|
|
776
|
+
score += nameLower === normalizedQuery ? 1 : 0.8;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
if (searchIn.includes("summary") && entry.summary) {
|
|
780
|
+
const summaryLower = entry.summary.toLowerCase();
|
|
781
|
+
if (summaryLower.includes(normalizedQuery)) {
|
|
782
|
+
matchedFields.push("summary");
|
|
783
|
+
score += 0.6;
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
if (searchIn.includes("description") && entry.description) {
|
|
787
|
+
const descLower = entry.description.toLowerCase();
|
|
788
|
+
if (descLower.includes(normalizedQuery)) {
|
|
789
|
+
matchedFields.push("description");
|
|
790
|
+
score += 0.4;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
if (searchIn.includes("path") && entry.path) {
|
|
794
|
+
const pathLower = entry.path.toLowerCase();
|
|
795
|
+
if (pathLower.includes(normalizedQuery)) {
|
|
796
|
+
matchedFields.push("path");
|
|
797
|
+
score += 0.5;
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
if (matchedFields.length > 0) {
|
|
801
|
+
results.push({
|
|
802
|
+
id: entry.id,
|
|
803
|
+
name: entry.name,
|
|
804
|
+
method: entry.method,
|
|
805
|
+
path: entry.path,
|
|
806
|
+
summary: entry.summary,
|
|
807
|
+
matchedFields,
|
|
808
|
+
score: Math.min(score, 1)
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
results.sort((a, b) => b.score - a.score);
|
|
813
|
+
return results.slice(0, limit);
|
|
814
|
+
}
|
|
815
|
+
/**
|
|
816
|
+
* 分页列出 API
|
|
817
|
+
*/
|
|
818
|
+
list(options = {}) {
|
|
819
|
+
const { page = 1, pageSize = DEFAULT_PAGE_SIZE, tag } = options;
|
|
820
|
+
let entries;
|
|
821
|
+
if (tag) {
|
|
822
|
+
const ids = this.tagIndex.get(tag);
|
|
823
|
+
entries = ids ? Array.from(ids).map((id) => this.apis.get(id)).filter((entry) => entry !== void 0) : [];
|
|
824
|
+
} else {
|
|
825
|
+
entries = Array.from(this.apis.values());
|
|
826
|
+
}
|
|
827
|
+
const total = entries.length;
|
|
828
|
+
const totalPages = Math.ceil(total / pageSize);
|
|
829
|
+
const startIndex = (page - 1) * pageSize;
|
|
830
|
+
const endIndex = startIndex + pageSize;
|
|
831
|
+
const pageEntries = entries.slice(startIndex, endIndex);
|
|
832
|
+
const items = pageEntries.map((entry) => ({
|
|
833
|
+
id: entry.id,
|
|
834
|
+
name: entry.name,
|
|
835
|
+
method: entry.method,
|
|
836
|
+
path: entry.path,
|
|
837
|
+
summary: entry.summary,
|
|
838
|
+
tags: entry.tags,
|
|
839
|
+
deprecated: entry.deprecated
|
|
840
|
+
}));
|
|
841
|
+
return {
|
|
842
|
+
page,
|
|
843
|
+
pageSize,
|
|
844
|
+
total,
|
|
845
|
+
totalPages,
|
|
846
|
+
items
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
/**
|
|
850
|
+
* 获取所有标签
|
|
851
|
+
*/
|
|
852
|
+
getTags() {
|
|
853
|
+
return Array.from(this.tagIndex.keys()).sort();
|
|
854
|
+
}
|
|
855
|
+
/**
|
|
856
|
+
* 获取 API 详情
|
|
857
|
+
*/
|
|
858
|
+
getDetail(id) {
|
|
859
|
+
const entry = this.apis.get(id);
|
|
860
|
+
if (!entry) {
|
|
861
|
+
return void 0;
|
|
862
|
+
}
|
|
863
|
+
return {
|
|
864
|
+
...entry,
|
|
865
|
+
parameterSchema: this.buildParameterSchema(entry),
|
|
866
|
+
requestBodySchema: this.buildRequestBodySchema(entry),
|
|
867
|
+
responseSchemas: this.buildResponseSchemas(entry)
|
|
868
|
+
};
|
|
869
|
+
}
|
|
870
|
+
/**
|
|
871
|
+
* 获取统计信息
|
|
872
|
+
*/
|
|
873
|
+
getStats() {
|
|
874
|
+
const byMethod = {};
|
|
875
|
+
const byTag = {};
|
|
876
|
+
for (const entry of this.apis.values()) {
|
|
877
|
+
const method = entry.method.toUpperCase();
|
|
878
|
+
byMethod[method] = (byMethod[method] || 0) + 1;
|
|
879
|
+
if (entry.tags) {
|
|
880
|
+
for (const tag of entry.tags) {
|
|
881
|
+
byTag[tag] = (byTag[tag] || 0) + 1;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
return {
|
|
886
|
+
totalApis: this.apis.size,
|
|
887
|
+
tags: this.getTags(),
|
|
888
|
+
byMethod,
|
|
889
|
+
byTag
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
/**
|
|
893
|
+
* 获取 API 数量
|
|
894
|
+
*/
|
|
895
|
+
get size() {
|
|
896
|
+
return this.apis.size;
|
|
897
|
+
}
|
|
898
|
+
/**
|
|
899
|
+
* 构建参数 Schema
|
|
900
|
+
*/
|
|
901
|
+
buildParameterSchema(entry) {
|
|
902
|
+
const { operation } = entry;
|
|
903
|
+
if (!operation.parameters || operation.parameters.length === 0) {
|
|
904
|
+
return void 0;
|
|
905
|
+
}
|
|
906
|
+
const properties = {};
|
|
907
|
+
const required = [];
|
|
908
|
+
for (const param of operation.parameters) {
|
|
909
|
+
const paramName = param.name;
|
|
910
|
+
properties[paramName] = {
|
|
911
|
+
...param.schema,
|
|
912
|
+
description: param.description,
|
|
913
|
+
in: param.in
|
|
914
|
+
};
|
|
915
|
+
if (param.required) {
|
|
916
|
+
required.push(paramName);
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
return {
|
|
920
|
+
type: "object",
|
|
921
|
+
properties,
|
|
922
|
+
required: required.length > 0 ? required : void 0
|
|
923
|
+
};
|
|
924
|
+
}
|
|
925
|
+
/**
|
|
926
|
+
* 构建请求体 Schema
|
|
927
|
+
*/
|
|
928
|
+
buildRequestBodySchema(entry) {
|
|
929
|
+
const { operation } = entry;
|
|
930
|
+
if (!operation.requestBody) {
|
|
931
|
+
return void 0;
|
|
932
|
+
}
|
|
933
|
+
const jsonContent = operation.requestBody.content["application/json"];
|
|
934
|
+
if (!jsonContent?.schema) {
|
|
935
|
+
return void 0;
|
|
936
|
+
}
|
|
937
|
+
return {
|
|
938
|
+
...jsonContent.schema,
|
|
939
|
+
description: operation.requestBody.description,
|
|
940
|
+
bodyRequired: operation.requestBody.required
|
|
941
|
+
};
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* 构建响应 Schema
|
|
945
|
+
*/
|
|
946
|
+
buildResponseSchemas(entry) {
|
|
947
|
+
const { operation } = entry;
|
|
948
|
+
if (!operation.responses) {
|
|
949
|
+
return void 0;
|
|
950
|
+
}
|
|
951
|
+
const schemas = {};
|
|
952
|
+
for (const [status, response] of Object.entries(operation.responses)) {
|
|
953
|
+
const jsonContent = response.content?.["application/json"];
|
|
954
|
+
schemas[status] = {
|
|
955
|
+
description: response.description,
|
|
956
|
+
schema: jsonContent?.schema
|
|
957
|
+
};
|
|
958
|
+
}
|
|
959
|
+
return schemas;
|
|
960
|
+
}
|
|
961
|
+
};
|
|
962
|
+
|
|
963
|
+
// src/tools/discovery/api-detail.ts
|
|
964
|
+
var import_zod3 = require("zod");
|
|
965
|
+
var apiDetailSchema = import_zod3.z.object({
|
|
966
|
+
id: import_zod3.z.string().min(1).describe("API ID\uFF08operationId \u6216\u5DE5\u5177\u540D\u79F0\uFF09")
|
|
967
|
+
});
|
|
968
|
+
var apiDetailTool = {
|
|
969
|
+
name: "api_detail",
|
|
970
|
+
description: `\u83B7\u53D6 API \u7684\u8BE6\u7EC6\u4FE1\u606F\u3002
|
|
971
|
+
|
|
972
|
+
\u4F7F\u7528\u573A\u666F\uFF1A
|
|
973
|
+
- \u67E5\u770B\u67D0\u4E2A API \u7684\u5B8C\u6574\u53C2\u6570\u5B9A\u4E49
|
|
974
|
+
- \u4E86\u89E3\u8BF7\u6C42\u4F53\u548C\u54CD\u5E94\u7684\u7ED3\u6784
|
|
975
|
+
- \u5728\u8C03\u7528 API \u524D\u4E86\u89E3\u9700\u8981\u54EA\u4E9B\u53C2\u6570
|
|
976
|
+
|
|
977
|
+
\u8FD4\u56DE\u5185\u5BB9\u5305\u62EC\uFF1A
|
|
978
|
+
- API \u57FA\u672C\u4FE1\u606F\uFF08\u65B9\u6CD5\u3001\u8DEF\u5F84\u3001\u63CF\u8FF0\uFF09
|
|
979
|
+
- \u53C2\u6570 Schema\uFF08\u8DEF\u5F84\u53C2\u6570\u3001\u67E5\u8BE2\u53C2\u6570\u3001\u5934\u53C2\u6570\uFF09
|
|
980
|
+
- \u8BF7\u6C42\u4F53 Schema
|
|
981
|
+
- \u54CD\u5E94 Schema`,
|
|
982
|
+
inputSchema: apiDetailSchema
|
|
983
|
+
};
|
|
984
|
+
function formatSchema(schema, indent = 0) {
|
|
985
|
+
if (!schema) return "\u65E0";
|
|
986
|
+
const spaces = " ".repeat(indent);
|
|
987
|
+
const lines = [];
|
|
988
|
+
if (schema.type) {
|
|
989
|
+
lines.push(`${spaces}\u7C7B\u578B: ${schema.type}`);
|
|
990
|
+
}
|
|
991
|
+
if (schema.description) {
|
|
992
|
+
lines.push(`${spaces}\u63CF\u8FF0: ${schema.description}`);
|
|
993
|
+
}
|
|
994
|
+
if (schema.properties) {
|
|
995
|
+
lines.push(`${spaces}\u5C5E\u6027:`);
|
|
996
|
+
const props = schema.properties;
|
|
997
|
+
const required = schema.required || [];
|
|
998
|
+
for (const [name, prop] of Object.entries(props)) {
|
|
999
|
+
const isRequired = required.includes(name);
|
|
1000
|
+
const reqTag = isRequired ? " (\u5FC5\u586B)" : " (\u53EF\u9009)";
|
|
1001
|
+
const propType = prop.type || "unknown";
|
|
1002
|
+
const propDesc = prop.description ? ` - ${prop.description}` : "";
|
|
1003
|
+
lines.push(`${spaces} - ${name}${reqTag}: ${propType}${propDesc}`);
|
|
1004
|
+
if (prop.properties) {
|
|
1005
|
+
lines.push(formatSchema(prop, indent + 2));
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
if (schema.enum) {
|
|
1010
|
+
lines.push(`${spaces}\u679A\u4E3E\u503C: ${schema.enum.join(", ")}`);
|
|
1011
|
+
}
|
|
1012
|
+
if (schema.example !== void 0) {
|
|
1013
|
+
lines.push(`${spaces}\u793A\u4F8B: ${JSON.stringify(schema.example)}`);
|
|
1014
|
+
}
|
|
1015
|
+
return lines.join("\n");
|
|
1016
|
+
}
|
|
1017
|
+
function executeApiDetail(registry, input) {
|
|
1018
|
+
const { id } = input;
|
|
1019
|
+
logger.debug(`Executing api_detail: id=${id}`);
|
|
1020
|
+
const detail = registry.getDetail(id);
|
|
1021
|
+
if (!detail) {
|
|
1022
|
+
const byName = registry.getByName(id);
|
|
1023
|
+
if (byName) {
|
|
1024
|
+
return executeApiDetail(registry, { id: byName.id });
|
|
1025
|
+
}
|
|
1026
|
+
return `\u9519\u8BEF: \u627E\u4E0D\u5230 API "${id}"
|
|
1027
|
+
|
|
1028
|
+
\u8BF7\u4F7F\u7528 api_search \u641C\u7D22\u53EF\u7528\u7684 API\u3002`;
|
|
1029
|
+
}
|
|
1030
|
+
const lines = [];
|
|
1031
|
+
lines.push(`## API: ${detail.name}`);
|
|
1032
|
+
lines.push("");
|
|
1033
|
+
const methodBadge = `[${detail.method.toUpperCase()}]`;
|
|
1034
|
+
const deprecatedTag = detail.deprecated ? " \u26A0\uFE0F \u5DF2\u5E9F\u5F03" : "";
|
|
1035
|
+
lines.push(`**${methodBadge}** \`${detail.path}\`${deprecatedTag}`);
|
|
1036
|
+
lines.push("");
|
|
1037
|
+
if (detail.summary) {
|
|
1038
|
+
lines.push(`**\u6458\u8981**: ${detail.summary}`);
|
|
1039
|
+
lines.push("");
|
|
1040
|
+
}
|
|
1041
|
+
if (detail.description) {
|
|
1042
|
+
lines.push(`**\u63CF\u8FF0**: ${detail.description}`);
|
|
1043
|
+
lines.push("");
|
|
1044
|
+
}
|
|
1045
|
+
if (detail.tags && detail.tags.length > 0) {
|
|
1046
|
+
lines.push(`**\u6807\u7B7E**: ${detail.tags.map((t) => `\`${t}\``).join(", ")}`);
|
|
1047
|
+
lines.push("");
|
|
1048
|
+
}
|
|
1049
|
+
lines.push("### \u53C2\u6570");
|
|
1050
|
+
lines.push("");
|
|
1051
|
+
if (detail.parameterSchema) {
|
|
1052
|
+
lines.push(formatSchema(detail.parameterSchema));
|
|
1053
|
+
} else {
|
|
1054
|
+
lines.push("\u65E0\u53C2\u6570");
|
|
1055
|
+
}
|
|
1056
|
+
lines.push("");
|
|
1057
|
+
if (detail.requestBodySchema) {
|
|
1058
|
+
const bodyRequired = detail.requestBodySchema.bodyRequired;
|
|
1059
|
+
lines.push("### \u8BF7\u6C42\u4F53");
|
|
1060
|
+
lines.push("");
|
|
1061
|
+
if (bodyRequired) {
|
|
1062
|
+
lines.push("**\u5FC5\u586B**: \u662F");
|
|
1063
|
+
lines.push("");
|
|
1064
|
+
}
|
|
1065
|
+
lines.push(formatSchema(detail.requestBodySchema));
|
|
1066
|
+
lines.push("");
|
|
1067
|
+
}
|
|
1068
|
+
if (detail.responseSchemas && Object.keys(detail.responseSchemas).length > 0) {
|
|
1069
|
+
lines.push("### \u54CD\u5E94");
|
|
1070
|
+
lines.push("");
|
|
1071
|
+
for (const [status, resp] of Object.entries(detail.responseSchemas)) {
|
|
1072
|
+
lines.push(`#### \u72B6\u6001\u7801: ${status}`);
|
|
1073
|
+
if (resp.description) {
|
|
1074
|
+
lines.push(`${resp.description}`);
|
|
1075
|
+
}
|
|
1076
|
+
if (resp.schema) {
|
|
1077
|
+
lines.push(formatSchema(resp.schema, 1));
|
|
1078
|
+
}
|
|
1079
|
+
lines.push("");
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
lines.push("---");
|
|
1083
|
+
lines.push("### \u8C03\u7528\u65B9\u5F0F");
|
|
1084
|
+
lines.push("");
|
|
1085
|
+
lines.push("\u4F7F\u7528 api_execute \u5DE5\u5177\u8C03\u7528\u6B64 API:");
|
|
1086
|
+
lines.push("```");
|
|
1087
|
+
lines.push(`api_execute(operationId="${detail.id}", parameters={...})`);
|
|
1088
|
+
lines.push("```");
|
|
1089
|
+
return lines.join("\n");
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
// src/tools/discovery/api-execute.ts
|
|
1093
|
+
var import_zod4 = require("zod");
|
|
1094
|
+
|
|
696
1095
|
// src/executor/request-builder.ts
|
|
697
1096
|
function groupParametersByLocation(parameters) {
|
|
698
1097
|
const groups = {
|
|
@@ -884,6 +1283,182 @@ function formatResponse(response) {
|
|
|
884
1283
|
return lines.join("\n");
|
|
885
1284
|
}
|
|
886
1285
|
|
|
1286
|
+
// src/tools/discovery/api-execute.ts
|
|
1287
|
+
var apiExecuteSchema = import_zod4.z.object({
|
|
1288
|
+
operationId: import_zod4.z.string().min(1).describe("API ID\uFF08operationId \u6216\u5DE5\u5177\u540D\u79F0\uFF09"),
|
|
1289
|
+
parameters: import_zod4.z.record(import_zod4.z.unknown()).optional().describe("API \u53C2\u6570\uFF08\u8DEF\u5F84\u53C2\u6570\u3001\u67E5\u8BE2\u53C2\u6570\u3001\u8BF7\u6C42\u4F53\u7B49\uFF09"),
|
|
1290
|
+
_baseUrl: import_zod4.z.string().url().optional().describe("API base URL\uFF08\u53EF\u9009\uFF0C\u8986\u76D6\u9ED8\u8BA4\u914D\u7F6E\uFF09")
|
|
1291
|
+
});
|
|
1292
|
+
var apiExecuteTool = {
|
|
1293
|
+
name: "api_execute",
|
|
1294
|
+
description: `\u6267\u884C API \u8C03\u7528\u3002
|
|
1295
|
+
|
|
1296
|
+
\u4F7F\u7528\u573A\u666F\uFF1A
|
|
1297
|
+
- \u76F4\u63A5\u8C03\u7528\u5DF2\u77E5\u7684 API
|
|
1298
|
+
- \u4F7F\u7528 api_search \u6216 api_list \u627E\u5230 API \u540E\u6267\u884C\u8C03\u7528
|
|
1299
|
+
|
|
1300
|
+
\u4F7F\u7528\u6B65\u9AA4\uFF1A
|
|
1301
|
+
1. \u5148\u4F7F\u7528 api_search \u6216 api_list \u627E\u5230\u9700\u8981\u7684 API
|
|
1302
|
+
2. \u4F7F\u7528 api_detail \u67E5\u770B\u53C2\u6570\u8981\u6C42
|
|
1303
|
+
3. \u4F7F\u7528 api_execute \u6267\u884C\u8C03\u7528
|
|
1304
|
+
|
|
1305
|
+
\u53C2\u6570\u8BF4\u660E\uFF1A
|
|
1306
|
+
- operationId: API \u7684\u552F\u4E00\u6807\u8BC6\u7B26
|
|
1307
|
+
- parameters: \u5305\u542B\u8DEF\u5F84\u53C2\u6570\u3001\u67E5\u8BE2\u53C2\u6570\u3001\u8BF7\u6C42\u4F53\u7B49
|
|
1308
|
+
- \u8DEF\u5F84\u53C2\u6570: URL \u8DEF\u5F84\u4E2D\u7684\u53C2\u6570 (\u5982 /users/{id} \u4E2D\u7684 id)
|
|
1309
|
+
- \u67E5\u8BE2\u53C2\u6570: URL \u95EE\u53F7\u540E\u7684\u53C2\u6570
|
|
1310
|
+
- body: \u8BF7\u6C42\u4F53\uFF08JSON \u5BF9\u8C61\uFF09`,
|
|
1311
|
+
inputSchema: apiExecuteSchema
|
|
1312
|
+
};
|
|
1313
|
+
async function executeApiExecute(registry, config, input) {
|
|
1314
|
+
const { operationId, parameters = {}, _baseUrl } = input;
|
|
1315
|
+
logger.debug(`Executing api_execute: operationId=${operationId}`);
|
|
1316
|
+
let apiEntry = registry.get(operationId);
|
|
1317
|
+
if (!apiEntry) {
|
|
1318
|
+
apiEntry = registry.getByName(operationId);
|
|
1319
|
+
}
|
|
1320
|
+
if (!apiEntry) {
|
|
1321
|
+
return `\u9519\u8BEF: \u627E\u4E0D\u5230 API "${operationId}"
|
|
1322
|
+
|
|
1323
|
+
\u8BF7\u4F7F\u7528 api_search \u641C\u7D22\u53EF\u7528\u7684 API\u3002`;
|
|
1324
|
+
}
|
|
1325
|
+
if (apiEntry.deprecated) {
|
|
1326
|
+
logger.warn(`API ${operationId} is deprecated`);
|
|
1327
|
+
}
|
|
1328
|
+
try {
|
|
1329
|
+
const executionConfig = {
|
|
1330
|
+
...config,
|
|
1331
|
+
baseUrl: _baseUrl || config.baseUrl
|
|
1332
|
+
};
|
|
1333
|
+
if (!executionConfig.baseUrl) {
|
|
1334
|
+
return `\u9519\u8BEF: \u6CA1\u6709\u914D\u7F6E base URL
|
|
1335
|
+
|
|
1336
|
+
\u8BF7\u901A\u8FC7\u4EE5\u4E0B\u65B9\u5F0F\u4E4B\u4E00\u63D0\u4F9B base URL:
|
|
1337
|
+
1. \u5728\u914D\u7F6E\u6587\u4EF6\u4E2D\u8BBE\u7F6E baseUrl
|
|
1338
|
+
2. \u542F\u52A8\u65F6\u4F7F\u7528 --base-url \u53C2\u6570
|
|
1339
|
+
3. \u8C03\u7528\u65F6\u63D0\u4F9B _baseUrl \u53C2\u6570`;
|
|
1340
|
+
}
|
|
1341
|
+
logger.info(`Executing API: ${apiEntry.method} ${apiEntry.path}`);
|
|
1342
|
+
const response = await executeRequest(apiEntry.operation, parameters, executionConfig);
|
|
1343
|
+
const formattedResponse = formatResponse(response);
|
|
1344
|
+
return formattedResponse;
|
|
1345
|
+
} catch (error) {
|
|
1346
|
+
const errorMessage = error instanceof ToolExecutionError ? `\u9519\u8BEF: ${error.message}` : `\u9519\u8BEF: ${error instanceof Error ? error.message : "\u672A\u77E5\u9519\u8BEF"}`;
|
|
1347
|
+
logger.error(`API execution failed: ${operationId}`, error);
|
|
1348
|
+
return errorMessage;
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
// src/tools/discovery/api-list.ts
|
|
1353
|
+
var import_zod5 = require("zod");
|
|
1354
|
+
var apiListSchema = import_zod5.z.object({
|
|
1355
|
+
page: import_zod5.z.number().int().min(1).default(1).describe("\u9875\u7801\uFF08\u4ECE 1 \u5F00\u59CB\uFF09"),
|
|
1356
|
+
pageSize: import_zod5.z.number().int().min(1).max(100).default(20).describe("\u6BCF\u9875\u6570\u91CF\uFF081-100\uFF09"),
|
|
1357
|
+
tag: import_zod5.z.string().optional().describe("\u6309\u6807\u7B7E\u8FC7\u6EE4")
|
|
1358
|
+
});
|
|
1359
|
+
var apiListTool = {
|
|
1360
|
+
name: "api_list",
|
|
1361
|
+
description: `\u5206\u9875\u6D4F\u89C8\u6240\u6709\u53EF\u7528\u7684 API\u3002
|
|
1362
|
+
|
|
1363
|
+
\u4F7F\u7528\u573A\u666F\uFF1A
|
|
1364
|
+
- \u67E5\u770B\u6709\u54EA\u4E9B API \u53EF\u7528
|
|
1365
|
+
- \u6309\u6807\u7B7E\u8FC7\u6EE4 API
|
|
1366
|
+
- \u6D4F\u89C8 API \u5217\u8868\u4EE5\u627E\u5230\u9700\u8981\u7684\u63A5\u53E3
|
|
1367
|
+
|
|
1368
|
+
\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`,
|
|
1369
|
+
inputSchema: apiListSchema
|
|
1370
|
+
};
|
|
1371
|
+
function executeApiList(registry, input) {
|
|
1372
|
+
const { page, pageSize, tag } = input;
|
|
1373
|
+
logger.debug(`Executing api_list: page=${page}, pageSize=${pageSize}, tag=${tag}`);
|
|
1374
|
+
const result = registry.list({ page, pageSize, tag });
|
|
1375
|
+
const lines = [];
|
|
1376
|
+
lines.push(`## API \u5217\u8868 (${result.total} \u4E2A API)`);
|
|
1377
|
+
lines.push(`\u9875\u7801: ${result.page}/${result.totalPages}`);
|
|
1378
|
+
if (tag) {
|
|
1379
|
+
lines.push(`\u6807\u7B7E\u8FC7\u6EE4: ${tag}`);
|
|
1380
|
+
}
|
|
1381
|
+
lines.push("");
|
|
1382
|
+
if (result.items.length === 0) {
|
|
1383
|
+
lines.push("\u6CA1\u6709\u627E\u5230\u5339\u914D\u7684 API\u3002");
|
|
1384
|
+
return lines.join("\n");
|
|
1385
|
+
}
|
|
1386
|
+
for (const item of result.items) {
|
|
1387
|
+
const methodBadge = `[${item.method.toUpperCase().padEnd(6)}]`;
|
|
1388
|
+
const deprecatedTag = item.deprecated ? " [\u5DF2\u5E9F\u5F03]" : "";
|
|
1389
|
+
const tags = item.tags ? ` (${item.tags.join(", ")})` : "";
|
|
1390
|
+
lines.push(`### ${item.id}`);
|
|
1391
|
+
lines.push(`${methodBadge} ${item.path}${deprecatedTag}${tags}`);
|
|
1392
|
+
if (item.summary) {
|
|
1393
|
+
lines.push(`${item.summary}`);
|
|
1394
|
+
}
|
|
1395
|
+
lines.push("");
|
|
1396
|
+
}
|
|
1397
|
+
if (result.totalPages > 1) {
|
|
1398
|
+
lines.push("---");
|
|
1399
|
+
if (result.page < result.totalPages) {
|
|
1400
|
+
lines.push(`\u4F7F\u7528 page=${result.page + 1} \u67E5\u770B\u4E0B\u4E00\u9875`);
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
return lines.join("\n");
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
// src/tools/discovery/api-search.ts
|
|
1407
|
+
var import_zod6 = require("zod");
|
|
1408
|
+
var apiSearchSchema = import_zod6.z.object({
|
|
1409
|
+
query: import_zod6.z.string().min(1).describe("\u641C\u7D22\u5173\u952E\u8BCD"),
|
|
1410
|
+
searchIn: import_zod6.z.array(import_zod6.z.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"),
|
|
1411
|
+
limit: import_zod6.z.number().int().min(1).max(100).optional().default(20).describe("\u6700\u5927\u8FD4\u56DE\u6570\u91CF\uFF081-100\uFF09")
|
|
1412
|
+
});
|
|
1413
|
+
var apiSearchTool = {
|
|
1414
|
+
name: "api_search",
|
|
1415
|
+
description: `\u641C\u7D22 API\u3002
|
|
1416
|
+
|
|
1417
|
+
\u4F7F\u7528\u573A\u666F\uFF1A
|
|
1418
|
+
- \u6839\u636E\u5173\u952E\u8BCD\u5FEB\u901F\u627E\u5230\u76F8\u5173 API
|
|
1419
|
+
- \u641C\u7D22\u7279\u5B9A\u529F\u80FD\u6216\u8D44\u6E90\u7684\u63A5\u53E3
|
|
1420
|
+
- \u67E5\u627E\u5305\u542B\u7279\u5B9A\u8DEF\u5F84\u6BB5\u7684 API
|
|
1421
|
+
|
|
1422
|
+
\u641C\u7D22\u8303\u56F4\u5305\u62EC\uFF1AAPI \u540D\u79F0\u3001\u6458\u8981\u3001\u63CF\u8FF0\u3001\u8DEF\u5F84\u3002
|
|
1423
|
+
\u7ED3\u679C\u6309\u5339\u914D\u5EA6\u6392\u5E8F\uFF0C\u6700\u5339\u914D\u7684\u6392\u5728\u524D\u9762\u3002`,
|
|
1424
|
+
inputSchema: apiSearchSchema
|
|
1425
|
+
};
|
|
1426
|
+
function executeApiSearch(registry, input) {
|
|
1427
|
+
const { query, searchIn, limit } = input;
|
|
1428
|
+
logger.debug(
|
|
1429
|
+
`Executing api_search: query="${query}", searchIn=${searchIn?.join(",")}, limit=${limit}`
|
|
1430
|
+
);
|
|
1431
|
+
const results = registry.search({ query, searchIn, limit });
|
|
1432
|
+
const lines = [];
|
|
1433
|
+
lines.push(`## \u641C\u7D22\u7ED3\u679C: "${query}"`);
|
|
1434
|
+
lines.push(`\u627E\u5230 ${results.length} \u4E2A\u5339\u914D\u7684 API`);
|
|
1435
|
+
lines.push("");
|
|
1436
|
+
if (results.length === 0) {
|
|
1437
|
+
lines.push("\u6CA1\u6709\u627E\u5230\u5339\u914D\u7684 API\u3002");
|
|
1438
|
+
lines.push("");
|
|
1439
|
+
lines.push("\u5EFA\u8BAE\uFF1A");
|
|
1440
|
+
lines.push("- \u5C1D\u8BD5\u4F7F\u7528\u4E0D\u540C\u7684\u5173\u952E\u8BCD");
|
|
1441
|
+
lines.push("- \u68C0\u67E5\u62FC\u5199\u662F\u5426\u6B63\u786E");
|
|
1442
|
+
lines.push("- \u4F7F\u7528\u66F4\u901A\u7528\u7684\u641C\u7D22\u8BCD");
|
|
1443
|
+
return lines.join("\n");
|
|
1444
|
+
}
|
|
1445
|
+
for (const item of results) {
|
|
1446
|
+
const methodBadge = `[${item.method.toUpperCase().padEnd(6)}]`;
|
|
1447
|
+
const matchInfo = `\u5339\u914D\u5B57\u6BB5: ${item.matchedFields.join(", ")}`;
|
|
1448
|
+
lines.push(`### ${item.id}`);
|
|
1449
|
+
lines.push(`${methodBadge} ${item.path}`);
|
|
1450
|
+
if (item.summary) {
|
|
1451
|
+
lines.push(`${item.summary}`);
|
|
1452
|
+
}
|
|
1453
|
+
lines.push(`_${matchInfo}_ (\u76F8\u5173\u5EA6: ${Math.round(item.score * 100)}%)`);
|
|
1454
|
+
lines.push("");
|
|
1455
|
+
}
|
|
1456
|
+
lines.push("---");
|
|
1457
|
+
lines.push("\u4F7F\u7528 api_detail <id> \u67E5\u770B API \u8BE6\u60C5");
|
|
1458
|
+
lines.push("\u4F7F\u7528 api_execute <id> <parameters> \u6267\u884C API");
|
|
1459
|
+
return lines.join("\n");
|
|
1460
|
+
}
|
|
1461
|
+
|
|
887
1462
|
// src/server/tool-manager.ts
|
|
888
1463
|
var ToolManager = class {
|
|
889
1464
|
tools = /* @__PURE__ */ new Map();
|
|
@@ -920,6 +1495,23 @@ var ToolManager = class {
|
|
|
920
1495
|
}
|
|
921
1496
|
logger.info(`Registered ${tools.length} tools`);
|
|
922
1497
|
}
|
|
1498
|
+
/**
|
|
1499
|
+
* 获取工具
|
|
1500
|
+
*/
|
|
1501
|
+
getTool(name) {
|
|
1502
|
+
return this.tools.get(name);
|
|
1503
|
+
}
|
|
1504
|
+
/**
|
|
1505
|
+
* 通过 operationId 获取工具
|
|
1506
|
+
*/
|
|
1507
|
+
getToolByOperationId(operationId) {
|
|
1508
|
+
for (const tool of this.tools.values()) {
|
|
1509
|
+
if (tool.operation.operationId === operationId) {
|
|
1510
|
+
return tool;
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
return void 0;
|
|
1514
|
+
}
|
|
923
1515
|
/**
|
|
924
1516
|
* 执行工具
|
|
925
1517
|
*/
|
|
@@ -965,6 +1557,40 @@ var ToolManager = class {
|
|
|
965
1557
|
};
|
|
966
1558
|
}
|
|
967
1559
|
}
|
|
1560
|
+
/**
|
|
1561
|
+
* 通过 operation 直接执行(用于 ondemand 模式)
|
|
1562
|
+
*/
|
|
1563
|
+
async executeByOperation(operation, args) {
|
|
1564
|
+
try {
|
|
1565
|
+
logger.debug(`Executing operation: ${operation.operationId || operation.path}`, args);
|
|
1566
|
+
const { _baseUrl, ...restArgs } = args;
|
|
1567
|
+
const executionConfig = {
|
|
1568
|
+
...this.config,
|
|
1569
|
+
baseUrl: typeof _baseUrl === "string" ? _baseUrl : this.config.baseUrl
|
|
1570
|
+
};
|
|
1571
|
+
const response = await executeRequest(operation, restArgs, executionConfig);
|
|
1572
|
+
const formattedResponse = formatResponse(response);
|
|
1573
|
+
return {
|
|
1574
|
+
content: [
|
|
1575
|
+
{
|
|
1576
|
+
type: "text",
|
|
1577
|
+
text: formattedResponse
|
|
1578
|
+
}
|
|
1579
|
+
]
|
|
1580
|
+
};
|
|
1581
|
+
} catch (error) {
|
|
1582
|
+
const errorMessage = error instanceof ToolExecutionError ? `Error: ${error.message}` : `Error: ${error instanceof Error ? error.message : "Unknown error"}`;
|
|
1583
|
+
logger.error(`Operation execution failed: ${operation.operationId || operation.path}`, error);
|
|
1584
|
+
return {
|
|
1585
|
+
content: [
|
|
1586
|
+
{
|
|
1587
|
+
type: "text",
|
|
1588
|
+
text: errorMessage
|
|
1589
|
+
}
|
|
1590
|
+
]
|
|
1591
|
+
};
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
968
1594
|
/**
|
|
969
1595
|
* 获取所有已注册的工具名称
|
|
970
1596
|
*/
|
|
@@ -977,11 +1603,80 @@ var ToolManager = class {
|
|
|
977
1603
|
getToolCount() {
|
|
978
1604
|
return this.tools.size;
|
|
979
1605
|
}
|
|
1606
|
+
/**
|
|
1607
|
+
* 获取配置
|
|
1608
|
+
*/
|
|
1609
|
+
getConfig() {
|
|
1610
|
+
return this.config;
|
|
1611
|
+
}
|
|
980
1612
|
};
|
|
981
1613
|
|
|
982
1614
|
// src/server/index.ts
|
|
1615
|
+
function createRegistry(operations, components) {
|
|
1616
|
+
const registry = new ApiRegistry();
|
|
1617
|
+
for (const tool of operations) {
|
|
1618
|
+
const entry = {
|
|
1619
|
+
id: tool.operation.operationId || tool.name,
|
|
1620
|
+
name: tool.name,
|
|
1621
|
+
method: tool.operation.method,
|
|
1622
|
+
path: tool.operation.path,
|
|
1623
|
+
summary: tool.operation.summary,
|
|
1624
|
+
description: tool.operation.description,
|
|
1625
|
+
tags: tool.operation.tags,
|
|
1626
|
+
deprecated: tool.operation.deprecated,
|
|
1627
|
+
operation: tool.operation,
|
|
1628
|
+
components
|
|
1629
|
+
};
|
|
1630
|
+
registry.register(entry);
|
|
1631
|
+
}
|
|
1632
|
+
return registry;
|
|
1633
|
+
}
|
|
1634
|
+
function registerOndemandTools(server, registry, config) {
|
|
1635
|
+
server.tool(
|
|
1636
|
+
apiListTool.name,
|
|
1637
|
+
apiListTool.description,
|
|
1638
|
+
apiListSchema.shape,
|
|
1639
|
+
async (args) => {
|
|
1640
|
+
const result = executeApiList(registry, args);
|
|
1641
|
+
return { content: [{ type: "text", text: result }] };
|
|
1642
|
+
}
|
|
1643
|
+
);
|
|
1644
|
+
server.tool(
|
|
1645
|
+
apiSearchTool.name,
|
|
1646
|
+
apiSearchTool.description,
|
|
1647
|
+
apiSearchSchema.shape,
|
|
1648
|
+
async (args) => {
|
|
1649
|
+
const result = executeApiSearch(registry, args);
|
|
1650
|
+
return { content: [{ type: "text", text: result }] };
|
|
1651
|
+
}
|
|
1652
|
+
);
|
|
1653
|
+
server.tool(
|
|
1654
|
+
apiDetailTool.name,
|
|
1655
|
+
apiDetailTool.description,
|
|
1656
|
+
apiDetailSchema.shape,
|
|
1657
|
+
async (args) => {
|
|
1658
|
+
const result = executeApiDetail(registry, args);
|
|
1659
|
+
return { content: [{ type: "text", text: result }] };
|
|
1660
|
+
}
|
|
1661
|
+
);
|
|
1662
|
+
server.tool(
|
|
1663
|
+
apiExecuteTool.name,
|
|
1664
|
+
apiExecuteTool.description,
|
|
1665
|
+
apiExecuteSchema.shape,
|
|
1666
|
+
async (args) => {
|
|
1667
|
+
const result = await executeApiExecute(
|
|
1668
|
+
registry,
|
|
1669
|
+
config,
|
|
1670
|
+
args
|
|
1671
|
+
);
|
|
1672
|
+
return { content: [{ type: "text", text: result }] };
|
|
1673
|
+
}
|
|
1674
|
+
);
|
|
1675
|
+
logger.info("Registered 4 discovery tools (ondemand mode)");
|
|
1676
|
+
}
|
|
983
1677
|
async function createServer(config) {
|
|
984
1678
|
logger.info("Creating MCP server...");
|
|
1679
|
+
logger.info(`Mode: ${config.mode || "default"}`);
|
|
985
1680
|
const server = new import_mcp.McpServer({
|
|
986
1681
|
name: "api2mcp",
|
|
987
1682
|
version: "0.1.0"
|
|
@@ -997,9 +1692,17 @@ async function createServer(config) {
|
|
|
997
1692
|
openApiDoc.components?.schemas,
|
|
998
1693
|
config.toolPrefix
|
|
999
1694
|
);
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1695
|
+
if (config.mode === "ondemand") {
|
|
1696
|
+
const registry = createRegistry(tools, openApiDoc.components?.schemas);
|
|
1697
|
+
registerOndemandTools(server, registry, effectiveConfig);
|
|
1698
|
+
const stats = registry.getStats();
|
|
1699
|
+
logger.info(`Server ready with ${stats.totalApis} APIs in registry`);
|
|
1700
|
+
logger.info(`Tags: ${stats.tags.slice(0, 5).join(", ")}${stats.tags.length > 5 ? "..." : ""}`);
|
|
1701
|
+
} else {
|
|
1702
|
+
const toolManager = new ToolManager(server, effectiveConfig);
|
|
1703
|
+
toolManager.registerTools(tools);
|
|
1704
|
+
logger.info(`Server ready with ${toolManager.getToolCount()} tools`);
|
|
1705
|
+
}
|
|
1003
1706
|
return server;
|
|
1004
1707
|
}
|
|
1005
1708
|
async function startServer(config) {
|
|
@@ -1011,7 +1714,11 @@ async function startServer(config) {
|
|
|
1011
1714
|
|
|
1012
1715
|
// src/cli.ts
|
|
1013
1716
|
var program = new import_commander.Command();
|
|
1014
|
-
program.name("api2mcp").description("Convert OpenAPI specifications to MCP tools").version("0.1.0").option("-u, --url <url>", "OpenAPI document URL or file path").option("-b, --base-url <url>", "API base URL (overrides OpenAPI servers)").option("-t, --timeout <ms>", "Request timeout in milliseconds", parseInt).option("-h, --headers <json>", "Custom headers as JSON string").option("-p, --prefix <prefix>", "Tool name prefix").option(
|
|
1717
|
+
program.name("api2mcp").description("Convert OpenAPI specifications to MCP tools").version("0.1.0").option("-u, --url <url>", "OpenAPI document URL or file path").option("-b, --base-url <url>", "API base URL (overrides OpenAPI servers)").option("-t, --timeout <ms>", "Request timeout in milliseconds", parseInt).option("-h, --headers <json>", "Custom headers as JSON string").option("-p, --prefix <prefix>", "Tool name prefix").option(
|
|
1718
|
+
"-m, --mode <mode>",
|
|
1719
|
+
"Working mode: default (all APIs as tools) or ondemand (discovery tools)",
|
|
1720
|
+
"default"
|
|
1721
|
+
).option("-d, --debug", "Enable debug mode", false).action(async (options) => {
|
|
1015
1722
|
let config;
|
|
1016
1723
|
try {
|
|
1017
1724
|
config = loadConfig({
|
|
@@ -1020,6 +1727,7 @@ program.name("api2mcp").description("Convert OpenAPI specifications to MCP tools
|
|
|
1020
1727
|
timeout: options.timeout,
|
|
1021
1728
|
headers: options.headers,
|
|
1022
1729
|
prefix: options.prefix,
|
|
1730
|
+
mode: options.mode,
|
|
1023
1731
|
debug: options.debug
|
|
1024
1732
|
});
|
|
1025
1733
|
logger.info(`Starting api2mcp...`);
|
|
@@ -1027,6 +1735,7 @@ program.name("api2mcp").description("Convert OpenAPI specifications to MCP tools
|
|
|
1027
1735
|
if (config.baseUrl) {
|
|
1028
1736
|
logger.info(`Base URL: ${config.baseUrl}`);
|
|
1029
1737
|
}
|
|
1738
|
+
logger.info(`Mode: ${config.mode || "default"}`);
|
|
1030
1739
|
await startServer(config);
|
|
1031
1740
|
} catch (error) {
|
|
1032
1741
|
if (error instanceof ConfigurationError) {
|