UNPKG

skilled-feishu-mcp

Version:

A Model Context Protocol (MCP) server that integrates with Feishu's Open Platform APIs

250 lines (200 loc) 7.67 kB
#!/usr/bin/env node /** * 尝试使用HTTP+SSE模式连接skilled-feishu-mcp * 基于MCP官方SDK文档 */ import { Client } from '@modelcontextprotocol/sdk/client/index.js'; import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js'; import { performance } from 'perf_hooks'; import { spawn } from 'child_process'; import fs from 'fs'; // 配置 const IS_DEV_MODE = process.env.NODE_ENV === 'development'; const SERVER_PATH = '/opt/homebrew/bin/skilled-feishu-mcp'; const APP_ID = process.env.FEISHU_APP_ID || 'cli_test_9e11c52b0e1c500e'; const APP_SECRET = process.env.FEISHU_APP_SECRET || 'test_app_secret_for_development'; const HTTP_PORT = 3000; const TIMEOUT_MS = 30000; // 日志文件 const logFile = fs.createWriteStream('mcp_http_test.log'); // 性能指标 const perfMetrics = { serverStartup: 0, clientCreation: 0, connectionTime: 0, listToolsTime: 0, shutdownTime: 0, totalTime: 0 }; /** * 记录日志 */ function log(message, isError = false) { const timestamp = new Date().toISOString(); const logMessage = `[${timestamp}] ${message}`; // 控制台输出 console[isError ? 'error' : 'log'](message); // 写入日志文件 logFile.write(logMessage + '\n'); } /** * 主测试函数 */ async function main() { log('======================================'); log('MCP HTTP+SSE模式测试'); log('======================================'); log(`测试时间: ${new Date().toLocaleString()}`); log(`环境: ${IS_DEV_MODE ? '开发模式' : '生产模式'}`); log(`服务器路径: ${SERVER_PATH}`); let serverProcess = null; try { const startTime = performance.now(); // 1. 启动HTTP服务器 log('\n1. 启动HTTP模式的MCP服务器...'); const serverStartTime = performance.now(); const serverArgs = [ '--http', `--port=${HTTP_PORT}`, `--feishu-app-id=${APP_ID}`, `--feishu-app-secret=${APP_SECRET}`, '--verbose' ]; if (IS_DEV_MODE) { serverArgs.push('--development'); log(' 添加开发模式参数'); } log(` 完整命令: ${SERVER_PATH} ${serverArgs.join(' ')}`); serverProcess = spawn(SERVER_PATH, serverArgs, { env: process.env, stdio: ['ignore', 'pipe', 'pipe'] }); // 监听输出,确定服务器何时准备好 let serverReady = false; const serverReadyPromise = new Promise((resolve, reject) => { const timeout = setTimeout(() => { reject(new Error(`等待服务器启动超时 (${TIMEOUT_MS}ms)`)); }, TIMEOUT_MS); serverProcess.stdout.on('data', (data) => { const text = data.toString().trim(); log(` [stdout] ${text}`); if (text.includes('server started') || text.includes('listening on')) { serverReady = true; clearTimeout(timeout); resolve(); } }); serverProcess.stderr.on('data', (data) => { const text = data.toString().trim(); log(` [stderr] ${text}`); }); serverProcess.on('error', (err) => { clearTimeout(timeout); reject(new Error(`服务器进程启动失败: ${err.message}`)); }); serverProcess.on('exit', (code, signal) => { if (!serverReady) { clearTimeout(timeout); reject(new Error(`服务器进程意外退出,退出码: ${code}, 信号: ${signal}`)); } }); }); // 等待服务器准备好 log(' 等待服务器启动...'); await serverReadyPromise; perfMetrics.serverStartup = performance.now() - serverStartTime; log(` 服务器启动完成 (${perfMetrics.serverStartup.toFixed(2)} ms)`); // 2. 创建客户端 log('\n2. 创建MCP客户端...'); const clientStartTime = performance.now(); const client = new Client({ name: "MCP HTTP Test", version: "1.0.0" }); const transport = new SSEClientTransport({ baseUrl: `http://localhost:${HTTP_PORT}`, }); perfMetrics.clientCreation = performance.now() - clientStartTime; log(` 客户端创建完成 (${perfMetrics.clientCreation.toFixed(2)} ms)`); // 3. 连接服务器 log('\n3. 连接服务器...'); const connectStartTime = performance.now(); try { // 设置超时 const connectionPromise = client.connect(transport); const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error(`连接超时 (${TIMEOUT_MS}ms)`)), TIMEOUT_MS); }); await Promise.race([connectionPromise, timeoutPromise]); perfMetrics.connectionTime = performance.now() - connectStartTime; log(` 连接成功 (${perfMetrics.connectionTime.toFixed(2)} ms)`); } catch (error) { log(` 连接失败: ${error.message}`, true); throw error; } // 4. 获取服务器信息 const serverInfo = client.getServerVersion(); log(` 服务器信息: ${serverInfo?.name || 'unknown'} v${serverInfo?.version || 'unknown'}`); const serverCapabilities = client.getServerCapabilities(); log(` 服务器功能: ${JSON.stringify(serverCapabilities)}`); // 5. 列出工具 log('\n4. 列出工具...'); const listToolsStartTime = performance.now(); const toolsResponse = await client.listTools({}); perfMetrics.listToolsTime = performance.now() - listToolsStartTime; log(` 工具列出完成 (${perfMetrics.listToolsTime.toFixed(2)} ms)`); log(` 发现 ${toolsResponse.tools.length} 个工具`); if (toolsResponse.tools.length > 0) { log(' 工具列表:'); toolsResponse.tools.forEach((tool, index) => { if (index < 5) { log(` - ${tool.name}: ${tool.description || '无描述'}`); } }); if (toolsResponse.tools.length > 5) { log(` - ... 另外 ${toolsResponse.tools.length - 5} 个工具`); } } // 6. 关闭连接 log('\n5. 关闭连接...'); const shutdownStartTime = performance.now(); await client.close(); perfMetrics.shutdownTime = performance.now() - shutdownStartTime; log(` 连接关闭完成 (${perfMetrics.shutdownTime.toFixed(2)} ms)`); // 总计时间 perfMetrics.totalTime = performance.now() - startTime; // 性能报告 log('\n======================================'); log('性能报告'); log('======================================'); log(`服务器启动时间: ${perfMetrics.serverStartup.toFixed(2)} ms`); log(`客户端创建时间: ${perfMetrics.clientCreation.toFixed(2)} ms`); log(`连接时间: ${perfMetrics.connectionTime.toFixed(2)} ms`); log(`列出工具时间: ${perfMetrics.listToolsTime.toFixed(2)} ms`); log(`关闭连接时间: ${perfMetrics.shutdownTime.toFixed(2)} ms`); log(`总计时间: ${perfMetrics.totalTime.toFixed(2)} ms`); log('\n✅ 测试成功完成!'); } catch (error) { log(`\n❌ 测试失败: ${error.message}`, true); if (error.stack) { log(`\n堆栈跟踪:\n${error.stack}`, true); } process.exit(1); } finally { // 终止服务器进程 if (serverProcess && !serverProcess.killed) { log('\n清理: 终止服务器进程...'); serverProcess.kill('SIGTERM'); } // 关闭日志文件 logFile.end(); } } // 执行主测试函数 main().catch(error => { log(`未捕获错误: ${error.message}`, true); if (error.stack) { log(`堆栈跟踪:\n${error.stack}`, true); } process.exit(1); });