UNPKG

yapi-devloper-mcp

Version:

YApi MCP Integration

285 lines 13.3 kB
"use strict"; 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