Skip to main content
Glama
execute-command.ts4 kB
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { z } from 'zod'; import { spawn, SpawnOptions } from 'child_process'; /** * Tool: Execute Command * Registers the tool with the MCP server * @param server MCP server instance */ const registerExecuteCommandTool = (server: McpServer) => { server.registerTool( 'execute-command', { title: 'Execute Command', description: "Executes a shell command with advanced options for stdin, timeout, working directory, environment variables, and output handling.", inputSchema: { command: z.string().describe("The shell command to execute."), stdin_data: z.string().optional().describe("Data to be passed to the command's standard input."), timeout: z.number().int().min(0).optional().describe("Optional timeout in milliseconds."), waitForCompletion: z.boolean().optional().default(true).describe("If true, waits for the command to complete. If false, runs it in the background and returns the PID."), working_directory: z.string().optional().describe("Sets the current working directory for the command's execution."), env_vars: z.string().optional().describe("A space-separated string of key=value pairs for environment variables (e.g., 'VAR1=value1 VAR2=value2')."), capture_output: z.boolean().optional().default(true).describe("If false, the command's output will not be captured."), } }, async ({ command, stdin_data, timeout, waitForCompletion, working_directory, env_vars, capture_output, }) => { const processedEnv: NodeJS.ProcessEnv = { ...process.env }; if (env_vars) { env_vars.split(' ').forEach(pair => { const [key, ...valueParts] = pair.split('='); if (key) { processedEnv[key] = valueParts.join('='); } }); } const spawnOptions: SpawnOptions = { cwd: working_directory, env: processedEnv, shell: true, detached: !waitForCompletion, stdio: waitForCompletion ? ['pipe', 'pipe', 'pipe'] : 'ignore', }; if (!waitForCompletion) { const child = spawn(command, spawnOptions); child.unref(); return { content: [{ type: 'text', text: `Command "${command}" started in background with PID: ${child.pid}` }] }; } return new Promise((resolve) => { const child = spawn(command, { ...spawnOptions, timeout }); let stdout = ''; let stderr = ''; if (capture_output) { child.stdout?.on('data', (data) => (stdout += data.toString())); child.stderr?.on('data', (data) => (stderr += data.toString())); } if (stdin_data) { child.stdin?.write(stdin_data); child.stdin?.end(); } child.on('close', (code) => { if (code === 0) { let output = ''; if (capture_output) { if (stdout) output += `STDOUT:\n${stdout}\n`; if (stderr) output += `STDERR:\n${stderr}\n`; } resolve({ content: [{ type: 'text', text: output || 'Command executed successfully with no output.' }] }); } else { let errorMessage = `Command failed with exit code ${code}\n`; if (capture_output) { if (stdout) errorMessage += `STDOUT:\n${stdout}\n`; if (stderr) errorMessage += `STDERR:\n${stderr}\n`; } resolve({ content: [{ type: 'text', text: errorMessage }], isError: true }); } }); child.on('error', (err) => { resolve({ content: [{ type: 'text', text: `Failed to start command: ${err.message}` }], isError: true }); }); }); } ); }; export default registerExecuteCommandTool;

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/Yussefgafer/MyMCP'

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