yapi-devloper-mcp
Version:
YApi MCP Integration
285 lines • 13.3 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.YapiMcpServer = void 0;
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
const zod_1 = require("zod");
const yapi_js_1 = require("./services/yapi.js");
const express_1 = __importDefault(require("express"));
const sse_js_1 = require("@modelcontextprotocol/sdk/server/sse.js");
const yapi_js_2 = require("./services/yapi.js");
class YapiMcpServer {
server;
yapiService;
sseTransport = null;
token = null;
authConfig;
constructor(baseUrl, authConfig) {
if (authConfig.type === 'token' && !authConfig.token) {
throw new Error('使用 token 认证时必须提供 token');
}
if (authConfig.type === 'password' && (!authConfig.username || !authConfig.password)) {
throw new Error('使用密码认证时必须提供用户名和密码');
}
if (authConfig.type === 'token') {
this.token = authConfig.token;
}
this.authConfig = authConfig;
this.yapiService = new yapi_js_1.YApiService(baseUrl, authConfig);
this.server = new mcp_js_1.McpServer({
name: "Yapi MCP Server",
version: "0.2.5",
});
this.registerTools();
}
registerTools() {
this.server.tool("get_api_desc", "获取YApi中特定接口的详细信息", {
apiId: zod_1.z.string().describe("YApi接口的ID"),
}, async ({ apiId }) => {
const id = apiId;
try {
console.log(`获取API接口: ${id}`);
const apiInterface = await this.yapiService.getApiInterface(id);
console.log(`成功获取API接口: ${apiInterface.title || id}`);
const formattedResponse = {
基本信息: {
接口ID: apiInterface._id,
接口名称: apiInterface.title,
接口路径: apiInterface.path,
请求方式: apiInterface.method,
接口描述: apiInterface.desc
},
请求参数: {
URL参数: apiInterface.req_params,
查询参数: apiInterface.req_query,
请求头: apiInterface.req_headers,
请求体其他: apiInterface.req_body_other,
请求体类型: apiInterface.req_body_type,
表单参数: apiInterface.req_body_form
},
响应信息: {
响应类型: apiInterface.res_body_type,
响应内容: apiInterface.res_body
},
其他信息: {
接口文档: apiInterface.markdown
}
};
return {
content: [{ type: "text", text: JSON.stringify(formattedResponse, null, 2) }],
};
}
catch (error) {
console.error(`获取API接口 ${id} 时出错:`, error);
if (error instanceof yapi_js_2.YApiError) {
return {
content: [
{
type: 'text',
text: JSON.stringify({
error: true,
code: error.code,
message: error.message,
details: error.response
}, null, 2)
}
]
};
}
return {
content: [
{
type: 'text',
text: JSON.stringify({
error: true,
message: error instanceof Error ? error.message : '获取API接口失败',
details: error
}, null, 2)
}
]
};
}
});
this.server.tool("create_api", "创建新的API接口", {
title: zod_1.z.string().describe("接口名称"),
path: zod_1.z.string().describe("接口路径"),
method: zod_1.z.string().describe("请求方法"),
project_id: zod_1.z.number().describe("项目ID"),
catid: zod_1.z.number().describe("分类ID"),
desc: zod_1.z.string().optional().describe("接口描述"),
req_params: zod_1.z.array(zod_1.z.any()).optional().describe("URL参数"),
req_query: zod_1.z.array(zod_1.z.any()).optional().describe("查询参数"),
req_headers: zod_1.z.array(zod_1.z.any()).optional().describe("请求头"),
req_body_type: zod_1.z.string().optional().describe("请求体类型"),
req_body_form: zod_1.z.array(zod_1.z.any()).optional().describe("表单参数"),
res_body_type: zod_1.z.string().optional().describe("响应体类型"),
res_body: zod_1.z.string().optional().describe("响应体"),
markdown: zod_1.z.string().optional().describe("markdown文档"),
tag: zod_1.z.array(zod_1.z.string()).optional().describe("标签"),
status: zod_1.z.string().optional().describe("状态"),
switch_notice: zod_1.z.boolean().optional().describe("是否开启通知"),
api_opened: zod_1.z.boolean().optional().describe("是否开启接口"),
req_body_is_json_schema: zod_1.z.boolean().optional().describe("请求体是否为JSON Schema"),
res_body_is_json_schema: zod_1.z.boolean().optional().describe("响应体是否为JSON Schema"),
tbpath: zod_1.z.string().optional().describe("接口路径"),
req_body: zod_1.z.string().optional().describe("请求体"),
req_body_other: zod_1.z.string().optional().describe("请求体其他"),
}, async (params) => {
try {
console.log('开始创建接口...');
const result = await this.yapiService.createFullInterface(params);
console.log('接口创建完成');
return {
content: [
{
type: 'text',
text: JSON.stringify(result)
}
]
};
}
catch (error) {
console.error('创建接口失败:', error);
if (error instanceof yapi_js_2.YApiError) {
return {
content: [
{
type: 'text',
text: JSON.stringify({
error: true,
code: error.code,
message: error.message,
details: error.response
})
}
]
};
}
return {
content: [
{
type: 'text',
text: JSON.stringify({
error: true,
message: error instanceof Error ? error.message : '创建接口失败',
details: error
})
}
]
};
}
});
this.server.tool("update_api", "更新已有的API接口", {
id: zod_1.z.string().describe("接口ID"),
title: zod_1.z.string().optional().describe("接口名称"),
path: zod_1.z.string().optional().describe("接口路径"),
method: zod_1.z.string().optional().describe("请求方法"),
desc: zod_1.z.string().optional().describe("接口描述"),
req_params: zod_1.z.array(zod_1.z.any()).optional().describe("URL参数"),
req_query: zod_1.z.array(zod_1.z.any()).optional().describe("查询参数"),
req_headers: zod_1.z.array(zod_1.z.any()).optional().describe("请求头"),
req_body_type: zod_1.z.string().optional().describe("请求体类型"),
req_body_form: zod_1.z.array(zod_1.z.any()).optional().describe("表单参数"),
res_body_type: zod_1.z.string().optional().describe("响应体类型"),
res_body: zod_1.z.string().optional().describe("响应体"),
markdown: zod_1.z.string().optional().describe("markdown文档"),
tag: zod_1.z.array(zod_1.z.string()).optional().describe("标签"),
status: zod_1.z.string().optional().describe("状态"),
switch_notice: zod_1.z.boolean().optional().describe("是否开启通知"),
api_opened: zod_1.z.boolean().optional().describe("是否开启接口"),
req_body_is_json_schema: zod_1.z.boolean().optional().describe("请求体是否为JSON Schema"),
res_body_is_json_schema: zod_1.z.boolean().optional().describe("响应体是否为JSON Schema"),
tbpath: zod_1.z.string().optional().describe("接口路径"),
req_body: zod_1.z.string().optional().describe("请求体"),
req_body_other: zod_1.z.string().optional().describe("请求体其他"),
}, async ({ id, ...params }) => {
try {
console.log("开始更新接口...");
const apiInterface = await this.yapiService.updateInterfaceDetails(id, params);
console.log("接口更新完成");
return {
content: [{
type: "text",
text: JSON.stringify({
message: "接口更新成功",
data: apiInterface
}, null, 2)
}],
};
}
catch (error) {
console.error("更新接口失败:", error);
if (error instanceof yapi_js_2.YApiError) {
return {
content: [
{
type: 'text',
text: JSON.stringify({
error: true,
code: error.code,
message: error.message,
details: error.response
}, null, 2)
}
]
};
}
return {
content: [
{
type: 'text',
text: JSON.stringify({
error: true,
message: error instanceof Error ? error.message : '更新接口失败',
details: error
}, null, 2)
}
]
};
}
});
}
async connect(transport) {
try {
console.log("正在连接传输层...");
console.log("尝试登录 YApi...");
await this.yapiService.login();
console.log("YApi 登录成功,正在连接 MCP 服务器...");
await this.server.connect(transport);
console.log("服务器已连接并准备处理请求");
}
catch (error) {
console.error("连接失败:", error);
throw error;
}
}
async startHttpServer(port) {
const app = (0, express_1.default)();
app.get("/sse", async (req, res) => {
console.log("新的 SSE 连接已建立");
this.sseTransport = new sse_js_1.SSEServerTransport("/messages", res);
await this.connect(this.sseTransport);
});
app.post("/messages", async (req, res) => {
if (!this.sseTransport) {
res.sendStatus(400);
return;
}
await this.sseTransport.handlePostMessage(req, res);
});
app.listen(port, () => {
console.log(`HTTP 服务器监听端口 ${port}`);
console.log(`SSE 端点可用于 http://localhost:${port}/sse`);
console.log(`消息端点可用于 http://localhost:${port}/messages`);
});
}
async login() {
if (this.authConfig.type === 'token') {
return;
}
}
}
exports.YapiMcpServer = YapiMcpServer;
//# sourceMappingURL=server.js.map
;