UNPKG

shenju-enterprise-search-mcp

Version:
215 lines (187 loc) 6.36 kB
/** * 云函数入口点 * 将Express应用包装为函数计算处理程序 */ const express = require('express'); const bodyParser = require('body-parser'); const cors = require('cors'); const MCPServer = require('./lib/mcp-server'); // 检测云函数环境 const isCloudFunction = process.env.FC_FUNCTION_NAME || process.env.SUPERGATEWAY || process.env.FC_RUNTIME_VERSION; console.log(`环境检测: isCloudFunction=${!!isCloudFunction}`); if (isCloudFunction) { console.log('检测到云函数环境,不会监听任何端口'); } // 创建Express应用 const app = express(); app.use(cors()); app.use(bodyParser.json()); // 添加详细日志中间件 app.use((req, res, next) => { console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`); if (req.body && Object.keys(req.body).length > 0) { console.log('请求体:', JSON.stringify(req.body).substring(0, 200) + '...'); } // 增强response对象,记录响应数据 const originalSend = res.send; res.send = function(body) { console.log(`[${new Date().toISOString()}] 响应状态: ${res.statusCode}`); // 避免记录过大的响应体 const bodyStr = typeof body === 'string' ? body : JSON.stringify(body); console.log('响应体:', bodyStr.length > 200 ? bodyStr.substring(0, 200) + '...(已截断)' : bodyStr); return originalSend.call(this, body); }; next(); }); // 获取环境变量 const API_KEY = process.env.API_KEY; const APP_ID = process.env.APP_ID; const BASE_URL = process.env.SEARCH_API_BASE_URL || 'https://api.enterprise-search.example.com/v1'; // 检查必要的环境变量 if (!API_KEY) { console.error('错误: 未设置API_KEY环境变量'); } // 创建MCP服务器 let mcpServer = null; // 确保只创建一次MCP服务器实例(因为云函数会重用实例) function getMCPServer() { if (!mcpServer) { console.log(`初始化MCP服务器,API_KEY=${API_KEY ? '已设置' : '未设置'}, APP_ID=${APP_ID || '未设置'}`); mcpServer = new MCPServer(API_KEY, APP_ID, BASE_URL); // 创建定时器,每30分钟清理一次过期会话 setInterval(() => { mcpServer.cleanSessions(); }, 1000 * 60 * 30); } return mcpServer; } // 健康检查接口 app.get('/health', (req, res) => { res.status(200).json({ status: 'ok', timestamp: new Date().toISOString() }); }); // 添加根路径接口,返回基本信息 app.get('/', (req, res) => { res.status(200).json({ service: '绅聚企业资料检索MCP服务', version: "1.0.1", status: 'running', timestamp: new Date().toISOString(), endpoints: ['/health', '/tool/list', '/tool/call'] }); }); // MCP Tool列表接口 app.get('/tool/list', (req, res) => { try { const mcpServer = getMCPServer(); const tools = mcpServer.listTools(); res.status(200).json({ jsonrpc: '2.0', result: tools, id: req.query.id || null }); } catch (error) { console.error('获取工具列表失败:', error); res.status(500).json({ jsonrpc: '2.0', error: { code: -32603, message: '服务器内部错误', data: error.message }, id: req.query.id || null }); } }); // MCP Tool调用接口 app.post('/tool/call', async (req, res) => { const { id, method, params } = req.body; // 检查请求格式 if (!method || !params) { return res.status(400).json({ jsonrpc: '2.0', error: { code: -32600, message: '无效的请求', data: 'method和params是必需的' }, id }); } try { const mcpServer = getMCPServer(); // 从方法名中提取工具名称 // 格式: <tool_name>.call const toolName = method.split('.')[0]; // 调用工具 const result = await mcpServer.callTool(toolName, params); // 返回结果 res.status(200).json({ jsonrpc: '2.0', result: result.result, id }); } catch (error) { console.error('工具调用失败:', error); res.status(500).json({ jsonrpc: '2.0', error: { code: -32603, message: error.message || '工具调用失败', data: error.response?.data || null }, id }); } }); // 函数计算处理程序 exports.handler = (req, resp, context) => { console.log('云函数触发, event:', JSON.stringify({ path: req.path, method: req.method, queries: req.queries || {} }).substring(0, 200)); // 解决云函数中可能的路径映射问题 if (req.path) { // 检查是否有需要处理的特殊路径 const path = req.path; // 针对云函数环境的路径调整,确保能够匹配到Express路由 if (path === '/' || path === '') { console.log('处理根路径请求'); // 根路径请求保持不变 } else if (path.endsWith('/tool/list')) { // 处理/tool/list路径 - 可能存在路径前缀 console.log('重新映射路径到 /tool/list'); req.path = '/tool/list'; req.url = '/tool/list'; } else if (path.endsWith('/tool/call')) { // 处理/tool/call路径 - 可能存在路径前缀 console.log('重新映射路径到 /tool/call'); req.path = '/tool/call'; req.url = '/tool/call'; } else if (path.endsWith('/health')) { // 处理/health路径 console.log('重新映射路径到 /health'); req.path = '/health'; req.url = '/health'; } else { console.log(`未知路径请求: ${path}, 尝试默认处理`); } } // 确保将云函数的路径正确映射到Express应用 app(req, resp); }; // 如果不是在云函数环境中,并且是直接执行此文件,则启动本地服务器 if (!isCloudFunction && require.main === module) { const PORT = process.env.PORT || 8080; const HOST = process.env.HOST || '0.0.0.0'; app.listen(PORT, HOST, () => { console.log(`🚀 绅聚企业资料检索MCP服务器运行在 http://${HOST}:${PORT}`); console.log('可用端点:'); console.log(`- 主页信息: http://${HOST}:${PORT}/`); console.log(`- 健康检查: http://${HOST}:${PORT}/health`); console.log(`- 工具列表: http://${HOST}:${PORT}/tool/list`); console.log(`- 工具调用: http://${HOST}:${PORT}/tool/call`); }); }