Skip to main content
Glama
nexon33

Electron Terminal MCP Server

terminal_start

Execute terminal commands within an Electron application to manage sessions and retrieve output programmatically.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
commandYes

Implementation Reference

  • The core handler function for the 'terminal_start' tool. It ensures the Electron-based terminal server is running, executes the provided command via an API call, strips ANSI codes from the output, and returns the session ID, cleaned output, and exit code.
    async ({ command }) => { try { // Check if server is running, start if not if (!(await isServerRunning())) { await startElectronProcess(); } // Create a new session const response = await axios.post(`${apiBaseUrl}/execute`, { command }); const result = response.data; // Clean up terminal output using strip-ansi const cleanOutput = stripAnsi(result.output); return { content: [{ type: "text", text: `Session ID: ${result.sessionId}\n\n ${cleanOutput}`, exitCode: result.exitCode }], //sessionId: result.sessionId }; } catch (error) { return formatErrorResponse(error); } }
  • Input schema for the 'terminal_start' tool, validating a single 'command' parameter as a string using Zod.
    { command: z.string() },
  • index.js:262-289 (registration)
    Registration of the 'terminal_start' tool on the MCP server using server.tool(), including the tool name, input schema, and inline handler function.
    "terminal_start", { command: z.string() }, async ({ command }) => { try { // Check if server is running, start if not if (!(await isServerRunning())) { await startElectronProcess(); } // Create a new session const response = await axios.post(`${apiBaseUrl}/execute`, { command }); const result = response.data; // Clean up terminal output using strip-ansi const cleanOutput = stripAnsi(result.output); return { content: [{ type: "text", text: `Session ID: ${result.sessionId}\n\n ${cleanOutput}`, exitCode: result.exitCode }], //sessionId: result.sessionId }; } catch (error) { return formatErrorResponse(error); } } );
  • Helper function used by the terminal_start handler to check if the underlying Electron server is running by pinging the /health endpoint.
    async function isServerRunning() { try { await axios.get(`${apiBaseUrl}/health`); return true; } catch (error) { return false; } }
  • Helper function called by the terminal_start handler to start the Electron process (terminal server) if not running, using mutex for single instance, spawning electron with specific env, logging, and waiting for readiness.
    async function startElectronProcess() { try { // Try to acquire mutex if (!(await acquireMutex())) { logger.error('Electron process is already running or failed to acquire mutex.'); return; } // Get the path to electron from node_modules const electronExecutable = process.platform === 'win32' ? 'electron.cmd' : 'electron'; const electronPath = path.join(__dirname, 'node_modules', '.bin', electronExecutable); // Set up environment variables const env = { ...process.env, ELECTRON_START_URL: 'http://localhost:3000', ELECTRON_ENABLE_LOGGING: 'true', ELECTRON_ENABLE_STACK_DUMPING: 'true', NODE_ENV: 'development' }; logger.error('Starting Electron process'); // Use npx to run electron, hiding the window with windowsHide and shell: true // Corrected spawn call: path.resolve(__dirname) is now an argument to electronPath //const electronProcess = spawn("cmd.exe", ['/c','/s', electronPath, path.resolve(__dirname)], { const electronProcess = spawn(electronPath, [path.resolve(__dirname)], { detached: true, stdio: ['ignore', 'pipe', 'pipe'], // Keep stdio pipes for logging cwd: process.cwd(), env: env, windowsHide: true, // Ensure the window is hidden shell: true // Use shell to execute npx correctly }); // Log any output from the electron process electronProcess.stdout.on('data', (data) => { logger.error('Electron stdout:', data.toString()); }); electronProcess.stderr.on('data', (data) => { logger.error('Electron stderr:', data.toString()); }); electronProcess.on('error', async (error) => { logger.error('Failed to start Electron:', error); await releaseMutex(); }); electronProcess.on('exit', async (code, signal) => { logger.error(`Electron process exited with code ${code} and signal ${signal}`); await releaseMutex(); }); // Don't unref the process immediately to ensure it starts properly setTimeout(() => { electronProcess.unref(); }, 1000); // Wait for server to be ready return new Promise((resolve, reject) => { let attempts = 0; const maxAttempts = 60; const checkServer = async () => { try { if (await isServerRunning()) { logger.error('Server is now running'); resolve(); } else { attempts++; logger.error(`Waiting for server to start... (attempt ${attempts}/${maxAttempts})`); if (attempts >= maxAttempts) { await releaseMutex(); reject(new Error('Server failed to start within timeout period')); return; } setTimeout(checkServer, 1000); } } catch (error) { logger.error('Error checking server status:', error); attempts++; if (attempts >= maxAttempts) { await releaseMutex(); reject(new Error('Server failed to start within timeout period')); return; } setTimeout(checkServer, 1000); } }; checkServer(); }); } catch (error) { logger.error('Failed to start Electron process:', error); await releaseMutex(); throw error; } }

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/nexon33/console-terminal-mcp-server'

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