Skip to main content
Glama
masx200

Persistent Terminal MCP Server

by masx200
index.js5.33 kB
#!/usr/bin/env node import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { PersistentTerminalMcpServer } from "./mcp-server.js"; import { RestApiServer } from "./rest-api.js"; import { fileURLToPath } from "url"; import { realpathSync } from "fs"; export { PersistentTerminalMcpServer } from "./mcp-server.js"; export { TerminalManager } from "./terminal-manager.js"; export { WebUIManager } from "./web-ui-manager.js"; export { WebUIServer } from "./web-ui-server.js"; export { RestApiServer } from "./rest-api.js"; /** * 日志输出函数 - 只在调试模式下输出到 stderr * MCP 使用 stdio 进行 JSON-RPC 通信,所以日志必须输出到 stderr */ function log(message) { if (process.env.MCP_DEBUG === "true") { // 使用 stderr 避免污染 stdio JSON-RPC 通道 process.stderr.write(`[MCP-DEBUG] ${message}\n`); } } /** * 持久化终端 MCP 服务器主入口 */ async function main() { log("Starting Persistent Terminal MCP Server..."); // 创建 MCP 服务器实例 const mcpServer = new PersistentTerminalMcpServer(); const server = mcpServer.getServer(); // 自动启动 REST API 服务器(如果启用) let restApiServer; if (process.env.AUTO_START_REST_SERVER === "true") { try { const terminalManager = mcpServer.getTerminalManager(); restApiServer = new RestApiServer(terminalManager); const restPort = parseInt(process.env.REST_PORT || "3001"); const restHost = process.env.REST_HOST || "localhost"; await restApiServer.start(restPort, restHost); log(`REST API server auto-started on ${restHost}:${restPort}`); // 自动打开终端管理 UI if (process.env.AUTO_START_TERMINAL_UI === "true") { try { const webUiManager = mcpServer.getWebUiManager(); const autoOpenBrowser = process.env.AUTO_OPEN_BROWSER === "true"; const webUiHost = process.env.WEB_UI_HOST || "localhost"; const uiOptions = { autoOpen: autoOpenBrowser, host: webUiHost, terminalManager: terminalManager, }; const uiResult = await webUiManager.start(uiOptions); log(`Terminal UI auto-started on ${uiResult.url}`); if (autoOpenBrowser && uiResult.autoOpened) { log("Browser opened automatically"); } else if (!autoOpenBrowser) { log("Browser auto-open disabled by AUTO_OPEN_BROWSER setting"); } if (webUiHost === "0.0.0.0") { log("Web UI listening on all interfaces (0.0.0.0)"); } } catch (uiError) { process.stderr.write( `[MCP-ERROR] Failed to auto-start terminal UI: ${uiError}\n`, ); } } } catch (error) { process.stderr.write( `[MCP-ERROR] Failed to auto-start REST API server: ${error}\n`, ); } } // 创建 stdio 传输层 const transport = new StdioServerTransport(); // 连接服务器和传输层 await server.connect(transport); log("Persistent Terminal MCP Server started successfully"); log("Server capabilities:"); log("- create_terminal: Create new persistent terminal sessions"); log("- write_terminal: Send input to terminal sessions"); log("- read_terminal: Read output from terminal sessions"); log("- list_terminals: List all active terminal sessions"); log("- kill_terminal: Terminate terminal sessions"); log(""); log("Resources available:"); log("- terminal://list: List of all terminals"); log("- terminal://output/{terminalId}: Terminal output"); log("- terminal://stats: Manager statistics"); log(""); log("Prompts available:"); log("- terminal-usage-guide: Usage guide"); log("- terminal-troubleshooting: Troubleshooting guide"); // 处理优雅关闭 const shutdown = async () => { log("Received shutdown signal, cleaning up..."); try { // 关闭 REST API 服务器(如果已启动) if (restApiServer) { await restApiServer.stop(); log("REST API server stopped"); } await mcpServer.shutdown(); await transport.close(); process.exit(0); } catch (error) { // 错误信息输出到 stderr,避免污染 stdio process.stderr.write(`[MCP-ERROR] Error during shutdown: ${error}\n`); process.exit(1); } }; process.on("SIGINT", shutdown); process.on("SIGTERM", shutdown); process.on("SIGHUP", shutdown); // 处理未捕获的异常 process.on("uncaughtException", (error) => { process.stderr.write(`[MCP-ERROR] Uncaught exception: ${error}\n`); shutdown(); }); process.on("unhandledRejection", (reason, promise) => { process.stderr.write( `[MCP-ERROR] Unhandled rejection at: ${promise}, reason: ${reason}\n`, ); shutdown(); }); } // 启动服务器 const scriptPath = fileURLToPath(import.meta.url); const entryArg = process.argv[1]; if (entryArg) { let entryPath = entryArg; try { entryPath = realpathSync(entryArg); } catch { // 保留原始路径用于比较(例如当文件已经被删除时) } if (entryPath === scriptPath) { main().catch((error) => { process.stderr.write(`[MCP-ERROR] Failed to start server: ${error}\n`); process.exit(1); }); } } //# sourceMappingURL=index.js.map

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/masx200/persistent-terminal-mcp'

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