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;
      }
    }
Behavior1/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Tool has no description.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness1/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Tool has no description.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness1/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Tool has no description.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Tool has no description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose1/5

Does the description clearly state what the tool does and how it differs from similar tools?

Tool has no description.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines1/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Tool has no description.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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