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
JavaScript
/**
* 尝试使用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);
});