// MCP 工具注册与结果序列化辅助 /** 把任意可 JSON 化数据包装为 MCP 文本结果 (BigInt 转 Number) */ export function jsonResult(data) { return { content: [{ type: 'text', text: JSON.stringify(data, (_key, value) => (typeof value === 'bigint' ? Number(value) : value), 2), }], } } /** 工具执行失败: 统一返回 isError, 由 AI 自行读取错误信息 */ export function errorResult(message) { return { content: [{ type: 'text', text: '错误: ' + (message || '未知错误') }], isError: true, } } /** * 注册工具并统一处理异常 * @param {import('@modelcontextprotocol/sdk/server/mcp.js').McpServer} server * @param {string} name * @param {object} config * @param {(args: object) => Promise} handler */ export function tool(server, name, config, handler) { server.registerTool(name, config, async (args) => { try { return jsonResult(await handler(args || {})) } catch (e) { // 业务校验错误直接回传; Prisma / 连接错误不向 AI 泄露 SQL 细节 if (String(e?.name || '').startsWith('Prisma')) { return errorResult(`数据库操作失败${e?.code ? ' (' + e.code + ')' : ''}`) } return errorResult(e?.message || String(e)) } }) } /** 非空字符串 + 最大长度 */ export function reqStr(v, label, max) { const s = String(v ?? '').trim() if (!s) throw new Error(`${label}不能为空`) if (max && s.length > max) throw new Error(`${label}不能超过 ${max} 字`) return s } /** 时间标记: YYYY-MM-DD 或 ISO; null/'' 清空 */ export function parseMarkDate(v) { if (v === null || v === undefined || v === '') return null const d = new Date(v) if (Number.isNaN(d.getTime())) throw new Error('时间标记格式非法') return d }