UNPKG

yonbip-code-gen-mcp

Version:

YonBIP高级版代码生成MCP

309 lines (308 loc) 15.1 kB
#!/usr/bin/env node import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { z } from 'zod'; import dotenv from "dotenv"; import { getTemplateContent } from './readMD.js'; dotenv.config(); function formatQueryResult(res) { if (!res || !res.rows || !res.rows.length) { return "未查询到数据"; } let jsonStr = ""; jsonStr += `${res.metaData.map((meta) => meta.name).join("|") + "\n\n"}`; jsonStr += `${res.rows.map((row) => { return row.join("|") + "\n"; }).join("")}`; return jsonStr; } var server = new McpServer({ name: "code-gen-mcp-server", version: '0.0.1', capabilities: { resources: {}, tools: {}, }, instructions: '该服务用于根据用户的功能描述,做对应功能代码生成,请仔细理解用户的意图,并按以下指引选择合适的接口:\n\n' + '**原则:**\n' + '* **优先理解意图**:分析用户的真实需求,具体想要的功能,不明确时需要向用户询问\n' + '* **深入理解意图**:深入分析当前MCP Server提供的技能,理解不同技能的差别\n' + '* **必要时追问**:如果用户信息不足以调用某技能,请向用户追问缺失的信息\n' + '* **参数准确性**:确保传递给每个的参数格式和类型都正确,特别是模块组件条件单据实体接口等\n' + '* **清晰呈现结果**:将接口返回的信息以用户易于理解的方式进行呈现```\n```\n\n' + '请根据上述指引选择接口' }); /** * 1.生成推单/拉单的后端代码 或 推单/拉单的后端代码生成 */ server.tool("genPullOrFetchBill", "**生成推单/拉单的后端代码 或 推单/拉单的后端代码生成,如:**" + "\n" + "* 某单据推单生成另外的某个单据;" + "\n" + "* 拉取某个单据生成另外的单据;" + "\n" + "* 某个单据通过转换规则生成另外某个单据;" + "\n" + "* 某单据拉单另外某个单据;" + "\n" + "* 拉取某个单据生成另外的单据,下游单据类型为XX,上游单据类型为YY;" + "\n", { input: z.string().describe("拿到用户的所有描述文字"), billname: z.string().describe("从用户的话术中获取到用户想操作的单据名"), srcBillOrTranstype: z.string().describe("从用户的话术中获取到源单据类型"), destBillOrTranstype: z.string().describe("从用户的话术中获取到目标单据类型"), sourceBillVOName: z.string().describe("从用户的话术中获取到源单据vo实体全类名") }, async ({ input, billname, srcBillOrTranstype, destBillOrTranstype, sourceBillVOName }) => { let docsContent = "\n"; if (!!billname) { docsContent += " 生成代码的方法名要有这个单据名称 [" + billname + "] 的体现" + "\n"; } if (!!srcBillOrTranstype) { docsContent += " 将这个源单据类型 [" + srcBillOrTranstype + "] 适配到我的模板中" + "\n"; } if (!!destBillOrTranstype) { docsContent += " 将这个目标单据类型 [" + destBillOrTranstype + "] 适配到我的模板中" + "\n"; } if (!!sourceBillVOName) { docsContent += " 将这个源单据vo实体全类名 [" + sourceBillVOName + "] 适配到我的模板中" + "\n"; } let resourceName = "推单与拉单后端_开发推单与拉单后端流程及demo代码模板.md"; // 根据实际资源路径调整 //读取doc/template目录下指定模板的文件内容 docsContent += getTemplateContent(resourceName); return { content: [{ type: 'text', text: docsContent }], }; }); /** * 2.生成OpenAPI或OpenAPI代码生成 */ server.tool("genOpenAPI", "**生成OpenAPI或OpenAPI代码生成,如:**" + "\n" + "* 生成某单据某功能的OpenAPI;" + "\n" + "* 生成某单单据的OpenAPI;" + "\n" + "* 生成某单据的OpenAPI接口;" + "\n" + "* 某单据某功能的OpenAPI;" + "\n" + "* 生成某单据某功能的OpenAPI,模块是XX" + "\n" + "* 生成某单据的OpenAPI,带有某功能" + "\n", { input: z.string().describe("拿到用户的所有描述文字"), billname: z.string().describe("从用户的话术中获取到用户想操作的单据名"), modulecode: z.string().describe("从用户的话术中获取到模块编码"), componentcode: z.string().describe("从用户的话术中获取到组件编码"), entitycode: z.string().describe("从用户的话术中获取到实体编码") }, async ({ input, billname, modulecode, componentcode, entitycode }) => { let docsContent = "\n"; if (!!billname) { docsContent += " 生成代码的方法名要有这个单据名称 [" + billname + "] 的体现" + "\n"; } if (!!modulecode) { docsContent += " 将这个模块编码 [" + modulecode + "] 适配到我的模板中" + "\n"; } if (!!componentcode) { docsContent += " 将这个组件编码 [" + componentcode + "] 适配到我的模板中" + "\n"; } if (!!entitycode) { docsContent += " 将这个实体编码 [" + entitycode + "] 适配到我的模板中" + "\n"; } let resourceName = "OpenAPI_开发OpenAPI流程及demo代码模板.md"; // 根据实际资源路径调整 //读取doc/template目录下指定模板的文件内容 docsContent += getTemplateContent(resourceName); return { content: [{ type: 'text', text: docsContent }], }; }); /** * 3.生成参照功能的代码生成 */ server.tool("genBillReference", "**生成参照 或 参照功能的代码,如:**" + "\n" + "* 生成某业务单据的参照;" + "\n" + "* 某单据参照;" + "\n" + "* 某档案的参照;" + "\n" + "* 根据某sql条件查询的参照;" + "\n" + "* 生成带某条件的某单据的参照;" + "\n" + "* 生成某个表的带某条件的参照;" + "\n", { input: z.string().describe("拿到用户的所有描述文字"), billname: z.string().describe("从用户的话术中获取到用户想操作的单据名"), tablename: z.string().describe("从用户的话术中获取到数据库表名"), condition: z.string().describe("从用户的话术中获取到参照条件"), modulecode: z.string().describe("从用户的话术中获取到模块编码"), componentcode: z.string().describe("从用户的话术中获取到组件编码"), entitycode: z.string().describe("从用户的话术中获取到实体编码") }, async ({ input, billname, tablename, condition, modulecode, componentcode, entitycode }) => { let docsContent = "\n"; if (!!billname) { docsContent += " 生成代码的方法名要有这个单据名称 [" + billname + "] 的体现" + "\n"; } if (!!tablename) { docsContent += " 将提取到的数据库表名 [" + tablename + "] 填写到对应的代码中" + "\n"; } if (!!condition) { docsContent += " 将提取到的查询条件 [" + condition + "] 填写到对应的代码中" + "\n"; } if (!!modulecode) { docsContent += " 将这个模块编码 [" + modulecode + "] 适配到我的模板中" + "\n"; } if (!!componentcode) { docsContent += " 将这个组件编码 [" + componentcode + "] 适配到我的模板中" + "\n"; } if (!!entitycode) { docsContent += " 将这个实体编码 [" + entitycode + "] 适配到我的模板中" + "\n"; } let resourceName = "参照_开发参照流程及demo代码模板.md"; // 根据实际资源路径调整 //读取doc/template目录下指定模板的文件内容 docsContent += getTemplateContent(resourceName); return { content: [{ type: 'text', text: docsContent }], }; }); /** * 4.生成client端控制器Action代码生成 */ server.tool("genController", "**client端控制器Action代码生成,如:**" + "\n" + "* 生成某单据查询的控制器Action;" + "\n" + "* 生成某单据查询功能的Action;" + "\n" + "* 生成某单据新增功能的Action;" + "\n" + "* 生成某单据修改功能的Action;" + "\n" + "* 生成某单据保存功能的Action;" + "\n" + "* 生成某单据删除功能的Action;" + "\n" + "* 生成某单据查询某些数据功能的Action;" + "\n" + "* 生成某功能的Action类;" + "\n", { input: z.string().describe("拿到用户的所有描述文字"), billname: z.string().describe("从用户的话术中获取到用户想操作的单据名"), modulecode: z.string().describe("从用户的话术中获取到模块编码"), func: z.string().describe("从用户的话术中获取到具体的功能") }, async ({ input, billname, modulecode, func }) => { let docsContent = "\n"; if (!!billname) { docsContent += " 生成代码的方法名要有这个单据名称 [" + billname + "] 的体现" + "\n"; } if (!!modulecode) { docsContent += " 将这个模块编码 [" + modulecode + "] 适配到我的模板中" + "\n"; } if (!!func) { docsContent += " 理解[" + func + "]的意义进行根据上下文补充功能逻辑" + "\n"; } let resourceName = "控制器Action开发.md"; // 根据实际资源路径调整 //读取doc/template目录下指定模板的文件内容 docsContent += getTemplateContent(resourceName); return { content: [{ type: 'text', text: docsContent }], }; }); /** * 5.生成后台任务 */ server.tool("genBackgroundWork", "**后台任务 或 定时任务,如:**" + "\n" + "* 某单据某功能的后台任务;" + "\n" + "* 某功能的后台任务;" + "\n" + "* 生成一个后台任务,带有某功能;" + "\n" + "* 某单据某功能的定时任务;" + "\n" + "* 某功能的定时任务;" + "\n" + "* 生成一个定时任务,带有某功能;" + "\n", { input: z.string().describe("拿到用户的所有描述文字"), business: z.string().describe("从用户的话术中获取到用户想做的业务功能") }, async ({ input, business }) => { let docsContent = "\n"; if (!!business) { docsContent += " 将用户的业务生成代码后,放到这个模板中,用户业务为:" + business + "\n"; } let resourceName = "后台任务_开发后台任务流程及demo代码模板.md"; // 根据实际资源路径调整 //读取doc/template目录下指定模板的文件内容 docsContent += getTemplateContent(resourceName); return { content: [{ type: 'text', text: docsContent }], }; }); /** * 6.生成拉单前端代码 */ server.tool("genFetchBillFront", "**拉单前端 或 生成拉单前端代码 或 某单据拉单另一单据的前端,如:**" + "\n" + "* 生成拉单前端;" + "\n" + "* 拉单前端模板;" + "\n" + "* 某某拉单前端;" + "\n" + "* 生成推单前端;" + "\n" + "* 某单据新增拉单另一单据的前端;" + "\n" + "* 某单据新增拉单另一单据的前端代码;" + "\n" + "* 某单据新增拉单另一单据的前端,上游单据类型为XX" + "\n", { input: z.string().describe("拿到用户的所有描述文字"), }, async ({ input }) => { let docsContent = "\n"; let resourceName = "拉单前端_开发拉单前端流程及demo代码模板.md"; // 根据实际资源路径调整 //读取doc/template目录下指定模板的文件内容 docsContent += getTemplateContent(resourceName); return { content: [{ type: 'text', text: docsContent }], }; }); /** * 7.生成预警前端代码 */ server.tool("genPreAlert", "**预警任务 或 生成一个预警任务,如:**" + "\n" + "* 某单据某功能的预警任务;" + "\n" + "* 生成一个预警任务,对某功能进行预警;" + "\n" + "* 生成一个预警任务,在某个条件下触发预警;" + "\n", { input: z.string().describe("拿到用户的所有描述文字"), }, async ({ input }) => { let docsContent = "\n"; let resourceName = "预警_开发消息预警流程及demo代码模板.md"; // 根据实际资源路径调整 //读取doc/template目录下指定模板的文件内容 docsContent += getTemplateContent(resourceName); return { content: [{ type: 'text', text: docsContent }], }; }); server.tool("genMultiSelectTranslation", "**表单参照多选翻译,如:**" + "\n" + "* 表单参照多选保存后不显示数据;" + "\n" + "* 表单中参照字段多选保存之后不能正常显示数据;" + "\n" + "* 表单中参照字段多选之后如果做翻译处理;" + "\n", { input: z.string().describe("拿到用户的所有描述文字"), }, async ({ input }) => { let docsContent = "\n"; let resourceName = "表单多选参照翻译处理代码模板.md"; // 根据实际资源路径调整 //读取doc/template目录下指定模板的文件内容 docsContent += getTemplateContent(resourceName); return { content: [{ type: 'text', text: docsContent }], }; }); /** * 8.采购订单生成付款计划时追加制单人信息 */ server.tool("genAppendOrderPayPlanBillMaker", "**采购订单生成付款计划时追加制单人信息**" + "\n" + "* 采购订单生成付款计划时,需要将制单人信息追加到付款计划中;" + "\n" + "* 采购订单生成付款计划时,需要将制单人信息追加到付款计划中,制单人信息为:" + "\n", { input: z.string().describe("拿到用户的所有描述文字"), }, async ({ input }) => { let docsContent = "\n"; let resourceName = "采购订单生成付款计划时追加制单人信息.md"; // 根据实际资源路径调整 //读取doc/template目录下指定模板的文件内容 docsContent += getTemplateContent(resourceName); return { content: [{ type: 'text', text: docsContent }], }; }); server.tool("genSupplierAndPurchaserVehicleManagement", "**供应商/采购商车辆信息管理功能**" + "\n", { input: z.string().describe("拿到用户的所有描述文字"), }, async ({ input }) => { let docsContent = "\n"; let resourceName = "供应商和采购商车辆信息管理功能.md"; // 根据实际资源路径调整 //读取doc/template目录下指定模板的文件内容 docsContent += getTemplateContent(resourceName); return { content: [{ type: 'text', text: docsContent }], }; }); /** * 初始化函数 * 用于执行服务启动前的初始化操作 */ async function init() { } /** * 主函数,用于启动MCP服务器 * * 该函数创建一个新的stdio传输层,初始化服务,并连接服务器到传输层, * 使MCP服务器能够在标准输入输出上运行 */ async function main() { const transport = new StdioServerTransport(); await init(); await server.connect(transport); console.error('Meta Query MCP Server running on stdio @liupzhc'); } main().catch((error) => { console.error('Fatal error in main():', error); process.exit(1); });