UNPKG

aliyun-bailian-mcp-server

Version:
191 lines (167 loc) 5.39 kB
/** * 阿里云函数计算入口点 * 将Express应用包装为函数计算处理程序 */ const express = require('express'); const bodyParser = require('body-parser'); const cors = require('cors'); const MCPServer = require('./lib/mcp-server'); // 创建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}`); console.log('请求头:', JSON.stringify(req.headers)); if (req.body && Object.keys(req.body).length > 0) { console.log('请求体:', JSON.stringify(req.body)); } // 增强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 > 1000 ? bodyStr.substring(0, 1000) + '...(已截断)' : 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.BAILIAN_API_BASE_URL || 'https://dashscope.aliyuncs.com/compatible-mode/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 || '未设置'}, BASE_URL=${BASE_URL}`); 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服务', 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, headers: req.headers, queries: req.queries })); // 解决函数计算中可能的路径映射问题 if (req.path) { // 检查是否有需要处理的特殊路径 const path = req.path; // 针对FC环境的路径调整,确保能够匹配到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); };