Skip to main content
Glama
server.js7.15 kB
import express from 'express'; import { WebSocketServer } from 'ws'; import { createServer } from 'http'; import path from 'path'; import { fileURLToPath } from 'url'; import cors from 'cors'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const app = express(); const server = createServer(app); const wss = new WebSocketServer({ server }); // 启用CORS app.use(cors()); app.use(express.json()); // 静态文件服务 app.use(express.static(path.join(__dirname, 'public'))); // 存储活跃的会话和连接 const sessions = new Map(); // sessionId -> { output: string, clients: Set<WebSocket> } const clients = new Set(); // 所有连接的WebSocket客户端 // WebSocket连接处理 wss.on('connection', (ws) => { console.log('新的WebSocket连接'); clients.add(ws); // 发送当前所有会话的状态 const sessionList = Array.from(sessions.entries()).map(([id, data]) => ({ sessionId: id, output: data.output, lastUpdate: data.lastUpdate })); ws.send(JSON.stringify({ type: 'session_list', sessions: sessionList })); ws.on('message', (message) => { try { const data = JSON.parse(message.toString()); console.log('收到消息:', data); switch (data.type) { case 'subscribe_session': // 订阅特定会话 const sessionId = data.sessionId; if (sessions.has(sessionId)) { sessions.get(sessionId).clients.add(ws); // 发送该会话的完整输出 ws.send(JSON.stringify({ type: 'session_output', sessionId: sessionId, output: sessions.get(sessionId).output, isComplete: false })); } break; case 'unsubscribe_session': // 取消订阅特定会话 const unsubSessionId = data.sessionId; if (sessions.has(unsubSessionId)) { sessions.get(unsubSessionId).clients.delete(ws); } break; } } catch (error) { console.error('处理WebSocket消息错误:', error); } }); ws.on('close', () => { console.log('WebSocket连接关闭'); clients.delete(ws); // 从所有会话中移除该客户端 sessions.forEach(session => { session.clients.delete(ws); }); }); ws.on('error', (error) => { console.error('WebSocket错误:', error); }); }); // REST API端点 - 接收MCP服务器的输出 app.post('/api/session/start', (req, res) => { const { sessionId, command } = req.body; if (!sessionId) { return res.status(400).json({ error: '缺少sessionId' }); } // 创建新会话 sessions.set(sessionId, { output: '', command: command || '', clients: new Set(), lastUpdate: new Date().toISOString(), isActive: true }); console.log(`新会话开始: ${sessionId}, 命令: ${command}`); // 通知所有客户端有新会话 const sessionData = { sessionId, command, lastUpdate: sessions.get(sessionId).lastUpdate }; clients.forEach(client => { if (client.readyState === 1) { // WebSocket.OPEN client.send(JSON.stringify({ type: 'new_session', session: sessionData })); } }); res.json({ success: true, sessionId }); }); app.post('/api/session/output', (req, res) => { const { sessionId, output, isComplete = false } = req.body; if (!sessionId) { return res.status(400).json({ error: '缺少sessionId' }); } if (!sessions.has(sessionId)) { return res.status(404).json({ error: '会话不存在' }); } // 更新会话输出 const session = sessions.get(sessionId); session.output += output || ''; session.lastUpdate = new Date().toISOString(); session.isActive = !isComplete; console.log(`会话 ${sessionId} 输出更新, 长度: ${output?.length || 0}, 完成: ${isComplete}`); // 发送给订阅该会话的客户端 session.clients.forEach(client => { if (client.readyState === 1) { // WebSocket.OPEN client.send(JSON.stringify({ type: 'session_output', sessionId, output: output || '', fullOutput: session.output, isComplete, lastUpdate: session.lastUpdate })); } }); res.json({ success: true }); }); app.post('/api/session/end', (req, res) => { const { sessionId } = req.body; if (!sessionId) { return res.status(400).json({ error: '缺少sessionId' }); } if (sessions.has(sessionId)) { const session = sessions.get(sessionId); session.isActive = false; session.lastUpdate = new Date().toISOString(); console.log(`会话结束: ${sessionId}`); // 通知订阅的客户端 session.clients.forEach(client => { if (client.readyState === 1) { client.send(JSON.stringify({ type: 'session_ended', sessionId, lastUpdate: session.lastUpdate })); } }); } res.json({ success: true }); }); // 获取所有会话 app.get('/api/sessions', (req, res) => { const sessionList = Array.from(sessions.entries()).map(([id, data]) => ({ sessionId: id, command: data.command, outputLength: data.output.length, lastUpdate: data.lastUpdate, isActive: data.isActive })); res.json({ sessions: sessionList }); }); // 获取特定会话的完整输出 app.get('/api/session/:sessionId', (req, res) => { const sessionId = req.params.sessionId; if (!sessions.has(sessionId)) { return res.status(404).json({ error: '会话不存在' }); } const session = sessions.get(sessionId); res.json({ sessionId, command: session.command, output: session.output, lastUpdate: session.lastUpdate, isActive: session.isActive }); }); // 主页路由 app.get('/', (req, res) => { res.sendFile(path.join(__dirname, 'public', 'index.html')); }); const PORT = process.env.PORT || 3000; server.listen(PORT, () => { console.log(`MCP实时输出查看器运行在 http://localhost:${PORT}`); console.log('WebSocket服务器已启动'); }); // 优雅关闭 process.on('SIGINT', () => { console.log('正在关闭服务器...'); server.close(() => { console.log('服务器已关闭'); process.exit(0); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sfz009900/kalilinuxmcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server