refactor(apifox): 移除调试日志并优化代码结构
- 删除所有console.log调试输出 - 移除未使用的fs模块导入 - 优化ApifoxService初始化配置 - 使用新的MCP SDK注册方式替代旧版prompt处理 - 添加环境变量默认值设置
This commit is contained in:
1 parent
ad543045c7
commit
a6978c948b
2 files changed
+45
-70
No files matched your search
@@ -1,6 +1,6 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import NodeCache from 'node-cache';
|
import NodeCache from 'node-cache';
|
||||||
import fs from 'fs'
|
// import fs from 'fs'
|
||||||
|
|
||||||
const APIFOX_API_BASE = "https://apifox.gzmiyuan.com/api/v1";
|
const APIFOX_API_BASE = "https://apifox.gzmiyuan.com/api/v1";
|
||||||
|
|
||||||
@@ -50,9 +50,7 @@ export class ApifoxService {
|
|||||||
async init() {
|
async init() {
|
||||||
try {
|
try {
|
||||||
this.branchId = await this.getBranchId();
|
this.branchId = await this.getBranchId();
|
||||||
console.log('branchId', this.branchId);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error initializing branch ID:", error);
|
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,7 +108,6 @@ export class ApifoxService {
|
|||||||
|
|
||||||
async getApiTreeList() {
|
async getApiTreeList() {
|
||||||
const apiTree = await this.get(`/projects/${this.projectId}/api-tree-list`);
|
const apiTree = await this.get(`/projects/${this.projectId}/api-tree-list`);
|
||||||
console.log('-- get api tree list success', 'length', apiTree.length);
|
|
||||||
this.apiTreeList = apiTree;
|
this.apiTreeList = apiTree;
|
||||||
return apiTree;
|
return apiTree;
|
||||||
}
|
}
|
||||||
@@ -122,12 +119,10 @@ export class ApifoxService {
|
|||||||
// 检查缓存是否有效
|
// 检查缓存是否有效
|
||||||
const cachedData = this.cache.get(cacheKey);
|
const cachedData = this.cache.get(cacheKey);
|
||||||
if (cachedData) {
|
if (cachedData) {
|
||||||
console.log('Using cached folder list', 'length', cachedData.length);
|
|
||||||
return cachedData;
|
return cachedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
const {data: folderList} = await this.get(`/projects/${this.projectId}/api-detail-folders`);
|
const {data: folderList} = await this.get(`/projects/${this.projectId}/api-detail-folders`);
|
||||||
console.log('--get folder success', 'length', folderList.length);
|
|
||||||
|
|
||||||
// 设置缓存
|
// 设置缓存
|
||||||
this.cache.set(cacheKey, folderList);
|
this.cache.set(cacheKey, folderList);
|
||||||
@@ -149,12 +144,10 @@ export class ApifoxService {
|
|||||||
// 检查缓存是否有效
|
// 检查缓存是否有效
|
||||||
const cachedData = this.cache.get(cacheKey);
|
const cachedData = this.cache.get(cacheKey);
|
||||||
if (cachedData) {
|
if (cachedData) {
|
||||||
console.log('Using cached data schema');
|
|
||||||
return cachedData;
|
return cachedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
const {data:schemasTreeList} = await this.get(`/projects/${this.projectId}/data-schemas?locale=zh-CN`);
|
const {data:schemasTreeList} = await this.get(`/projects/${this.projectId}/data-schemas?locale=zh-CN`);
|
||||||
console.log('--get data schema success', 'length', schemasTreeList.length);
|
|
||||||
|
|
||||||
// 设置缓存
|
// 设置缓存
|
||||||
this.cache.set(cacheKey, schemasTreeList);
|
this.cache.set(cacheKey, schemasTreeList);
|
||||||
@@ -168,12 +161,10 @@ export class ApifoxService {
|
|||||||
// 检查缓存是否有效
|
// 检查缓存是否有效
|
||||||
const cachedData = this.cache.get(cacheKey);
|
const cachedData = this.cache.get(cacheKey);
|
||||||
if (cachedData) {
|
if (cachedData) {
|
||||||
console.log('Using cached API details');
|
|
||||||
return cachedData;
|
return cachedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
const {data:apiDetails} = await this.get(`/api-details?locale=zh-CN`, {});
|
const {data:apiDetails} = await this.get(`/api-details?locale=zh-CN`, {});
|
||||||
console.log('--get api details success', 'length', apiDetails.length);
|
|
||||||
|
|
||||||
// 设置缓存
|
// 设置缓存
|
||||||
this.cache.set(cacheKey, apiDetails);
|
this.cache.set(cacheKey, apiDetails);
|
||||||
@@ -182,7 +173,6 @@ export class ApifoxService {
|
|||||||
|
|
||||||
getSchemaRefId(obj) {
|
getSchemaRefId(obj) {
|
||||||
if (!obj || !obj.$ref) {
|
if (!obj || !obj.$ref) {
|
||||||
console.log('no schemaid', obj)
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const schemaName = obj.$ref.split('/').pop();
|
const schemaName = obj.$ref.split('/').pop();
|
||||||
@@ -275,9 +265,7 @@ export class ApifoxService {
|
|||||||
const requestSchemaId = this.getSchemaRefId(apiDetail.requestBody.jsonSchema);
|
const requestSchemaId = this.getSchemaRefId(apiDetail.requestBody.jsonSchema);
|
||||||
const responseSchema = Array.isArray(apiDetail.responses) ? apiDetail.responses[0].jsonSchema : apiDetail.responses.jsonSchema;
|
const responseSchema = Array.isArray(apiDetail.responses) ? apiDetail.responses[0].jsonSchema : apiDetail.responses.jsonSchema;
|
||||||
const responseSchemaId = this.getSchemaRefId(responseSchema);
|
const responseSchemaId = this.getSchemaRefId(responseSchema);
|
||||||
console.log('responseSchemaId', responseSchemaId);
|
|
||||||
const respDataSchemaId = this.getSchemaRefId(dataSchema.find((item) => item.id.toString() === responseSchemaId).jsonSchema.properties.data)
|
const respDataSchemaId = this.getSchemaRefId(dataSchema.find((item) => item.id.toString() === responseSchemaId).jsonSchema.properties.data)
|
||||||
console.log('respDataSchemaId', respDataSchemaId);
|
|
||||||
return {
|
return {
|
||||||
path: apiDetail.path,
|
path: apiDetail.path,
|
||||||
name: apiDetail.name,
|
name: apiDetail.name,
|
||||||
@@ -312,21 +300,7 @@ export class ApifoxService {
|
|||||||
const folder = await this.getFolderByName(folderName);
|
const folder = await this.getFolderByName(folderName);
|
||||||
const apiDetails = await this.getApiDetails();
|
const apiDetails = await this.getApiDetails();
|
||||||
const apiList = apiDetails.filter((item) => item.folderId === folder.id);
|
const apiList = apiDetails.filter((item) => item.folderId === folder.id);
|
||||||
console.log('--getApiListByFolderName success', 'length', apiList.length);
|
|
||||||
return Promise.all(apiList.map((api) => this.getApiDetailResp(api)));
|
return Promise.all(apiList.map((api) => this.getApiDetailResp(api)));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const apifoxService = new ApifoxService(345161);
|
|
||||||
|
|
||||||
apifoxService.init().then(() => {
|
|
||||||
apifoxService.getApiListByFolderName('数据中心统计数据')
|
|
||||||
.then(res => {
|
|
||||||
fs.writeFileSync('apifox-ret.json', JSON.stringify(res, null, 2));
|
|
||||||
})
|
|
||||||
|
|
||||||
}).catch((error) => {
|
|
||||||
console.error("Error initializing ApifoxService:", error);
|
|
||||||
});
|
|
||||||
@@ -2,23 +2,39 @@
|
|||||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { ApifoxService } from './apifox'
|
import { ApifoxService } from './apifox.js'
|
||||||
|
|
||||||
|
// 设置默认环境变量
|
||||||
|
if (!process.env.APIFOX_TOKEN) {
|
||||||
process.env.APIFOX_TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MzQ1MTIwLCJ0cyI6IjUyOGZiZDMwNGM3MjU2NDMiLCJpYXQiOjE3NjQxNTQyODEzMzB9.IZvoCb3pN5AUl375c4Dhpur1GdYBqyHWVkJ94bDQ6BQ';
|
process.env.APIFOX_TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MzQ1MTIwLCJ0cyI6IjUyOGZiZDMwNGM3MjU2NDMiLCJpYXQiOjE3NjQxNTQyODEzMzB9.IZvoCb3pN5AUl375c4Dhpur1GdYBqyHWVkJ94bDQ6BQ';
|
||||||
|
}
|
||||||
|
if (!process.env.APIFOX_PROJECT_ID) {
|
||||||
|
// 使用 steering 中提到的 organizationId 作为默认值
|
||||||
|
process.env.APIFOX_PROJECT_ID = '345161';
|
||||||
|
}
|
||||||
|
|
||||||
// 创建 MCP 服务器实例
|
// 创建 MCP 服务器实例
|
||||||
// 为其设置一个名字和版本
|
// 为其设置一个名字和版本
|
||||||
const server = new McpServer({
|
const server = new McpServer(
|
||||||
|
{
|
||||||
name: "apifox-mcp-server",
|
name: "apifox-mcp-server",
|
||||||
version: "1.0.0",
|
version: "1.0.0",
|
||||||
});
|
},
|
||||||
|
{
|
||||||
|
capabilities: {
|
||||||
|
prompts: {},
|
||||||
|
tools: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
const apifoxService = new ApifoxService({
|
const apifoxService = new ApifoxService({
|
||||||
projectId: process.env.APIFOX_PROJECT_ID,
|
projectId: Number(process.env.APIFOX_PROJECT_ID),
|
||||||
token: process.env.APIFOX_TOKEN
|
token: process.env.APIFOX_TOKEN
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
server.registerTool(
|
server.registerTool(
|
||||||
'get_api_by_path',
|
'get_api_by_path',
|
||||||
{
|
{
|
||||||
@@ -31,7 +47,7 @@ server.registerTool(
|
|||||||
async ({ path }) => {
|
async ({ path }) => {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const apiData = apifoxService.getApiDetailByPath(path);
|
const apiData = await apifoxService.getApiDetailByPath(path);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [
|
||||||
@@ -67,7 +83,7 @@ server.registerTool(
|
|||||||
async ({ folderName }) => {
|
async ({ folderName }) => {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const apiData = apifoxService.getApiListByFolderName(folderName);
|
const apiData = await apifoxService.getApiListByFolderName(folderName);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [
|
||||||
@@ -93,33 +109,15 @@ server.registerTool(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
// 定义 prompts 列表
|
|
||||||
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
||||||
return {
|
|
||||||
prompts: [
|
|
||||||
{
|
|
||||||
name: "gen-api-by-path",
|
|
||||||
description: "根据输入的接口路径获取Apifox接口文档定义,然后根据定义生成 api 接口代码定义",
|
|
||||||
arguments: [
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "gen-api-by-folder",
|
|
||||||
description: "根据输入的接口文件夹获取Apifox相关文件夹下所有的接口文档定义,然后根据定义生成 api 接口代码定义",
|
|
||||||
arguments: [
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// 处理获取具体 prompt 的请求
|
// 定义 prompts
|
||||||
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
server.registerPrompt(
|
||||||
const { name, arguments: args } = request.params;
|
'gen-api-by-path',
|
||||||
|
{
|
||||||
switch (name) {
|
title: 'Generate API by Path',
|
||||||
case "gen-api-by-path":
|
description: '根据输入的接口路径获取Apifox接口文档定义,然后根据定义生成 api 接口代码定义',
|
||||||
return {
|
},
|
||||||
|
() => ({
|
||||||
messages: [
|
messages: [
|
||||||
{
|
{
|
||||||
role: "user",
|
role: "user",
|
||||||
@@ -130,7 +128,7 @@ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|||||||
步骤:
|
步骤:
|
||||||
1. 使用 get_api_by_path 工具获取对应的接口定义schema
|
1. 使用 get_api_by_path 工具获取对应的接口定义schema
|
||||||
2. 根据返回的 path,method, requestSchema, responseSchema 和其他必要字段,生成 api 定义代码
|
2. 根据返回的 path,method, requestSchema, responseSchema 和其他必要字段,生成 api 定义代码
|
||||||
3. 接口的参数和返回值的类型定义,可以分别参考 requestSchema 和 responseSchema 里面的jsonSchema定义,要补充相关的注释
|
3. 接口的参数和返回值的类型定义,可以分别参考 requestSchema 和 responseSchema 里面的jsonSchema定义,可以根据description要补充相关的注释
|
||||||
4. 所有字段先定义为可空类型
|
4. 所有字段先定义为可空类型
|
||||||
5. 请根据当前项目的项目接口和代码风格生成 api 接口代码
|
5. 请根据当前项目的项目接口和代码风格生成 api 接口代码
|
||||||
|
|
||||||
@@ -138,10 +136,16 @@ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
})
|
||||||
|
);
|
||||||
|
|
||||||
case "gen-api-by-folder":
|
server.registerPrompt(
|
||||||
return {
|
'gen-api-by-folder',
|
||||||
|
{
|
||||||
|
title: 'Generate API by Folder',
|
||||||
|
description: '根据输入的接口文件夹获取Apifox相关文件夹下所有的接口文档定义,然后根据定义生成 api 接口代码定义',
|
||||||
|
},
|
||||||
|
() => ({
|
||||||
messages: [
|
messages: [
|
||||||
{
|
{
|
||||||
role: "user",
|
role: "user",
|
||||||
@@ -152,7 +156,7 @@ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|||||||
步骤:
|
步骤:
|
||||||
1. 使用 get_api_by_folder 工具获取对应的接口定义schema,可能会返回多条接口的数据
|
1. 使用 get_api_by_folder 工具获取对应的接口定义schema,可能会返回多条接口的数据
|
||||||
2. 根据返回的 path,method, requestSchema, responseSchema 和其他必要字段,生成 api 定义代码
|
2. 根据返回的 path,method, requestSchema, responseSchema 和其他必要字段,生成 api 定义代码
|
||||||
3. 接口的参数和返回值的类型定义,可以分别参考 requestSchema 和 responseSchema 里面的jsonSchema定义,要补充相关的注释
|
3. 接口的参数和返回值的类型定义,可以分别参考 requestSchema 和 responseSchema 里面的jsonSchema定义,可以根据description要补充相关的注释
|
||||||
4. 所有字段先定义为可空类型
|
4. 所有字段先定义为可空类型
|
||||||
5. 请根据当前项目的项目接口和代码风格生成 api 接口代码
|
5. 请根据当前项目的项目接口和代码风格生成 api 接口代码
|
||||||
|
|
||||||
@@ -160,12 +164,8 @@ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
})
|
||||||
|
);
|
||||||
default:
|
|
||||||
throw new Error(`未知的 prompt: ${name}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -174,6 +174,7 @@ async function main() {
|
|||||||
const transport = new StdioServerTransport();
|
const transport = new StdioServerTransport();
|
||||||
await server.connect(transport);
|
await server.connect(transport);
|
||||||
console.error("Apifox MCP 服务器已通过 stdio 启动"); // 日志输出到 stderr
|
console.error("Apifox MCP 服务器已通过 stdio 启动"); // 日志输出到 stderr
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 运行主函数,并捕获可能的错误
|
// 运行主函数,并捕获可能的错误
|
||||||
|
|||||||
Reference in new issue
Block a user