Skip to main content
Glama

run_command

Execute terminal commands securely with defined controls like allowed commands, timeout, and output size limits via the MCP Terminal Server.

Instructions

Run a terminal command with security controls.

Input Schema

NameRequiredDescriptionDefault
allowedCommandsNoOptional list of allowed command executables
commandYesThe command to execute
maxOutputSizeNoMaximum output size in bytes (default: 1MB)
timeoutMsNoMaximum execution time in milliseconds (default: 30 seconds)

Input Schema (JSON Schema)

{ "properties": { "allowedCommands": { "description": "Optional list of allowed command executables", "items": { "type": "string" }, "type": "array" }, "command": { "description": "The command to execute", "type": "string" }, "maxOutputSize": { "description": "Maximum output size in bytes (default: 1MB)", "type": "number" }, "timeoutMs": { "description": "Maximum execution time in milliseconds (default: 30 seconds)", "type": "number" } }, "required": [ "command" ], "type": "object" }

Implementation Reference

  • index.ts:99-191 (handler)
    Executes the 'run_command' tool: validates input with Zod schema, performs security checks on the command (allowed commands, no shell operators), spawns a child process with shell, captures stdout/stderr with size limits, enforces timeout, and returns structured result including exit code and timings.
    if (name === 'run_command') { const { command, allowedCommands, timeoutMs, maxOutputSize } = CommandArgumentsSchema.parse(args) // Validate command if allowedCommands is specified if (allowedCommands) { // Split command into parts const parts = command.split(/\s+/) if (!parts.length) { throw new Error('Empty command') } // Check if base command is allowed const baseCmd = parts[0] // Check for shell operators that could be used for command injection const shellOperators = ['&&', '||', '|', ';', '`'] if (shellOperators.some((op) => command.includes(op))) { throw new Error('Shell operators not allowed') } if (!allowedCommands.includes(baseCmd)) { throw new Error(`Command '${baseCmd}' not allowed`) } } const startTime = new Date() const result = await new Promise<CommandResult>((resolve, reject) => { // Create subprocess const process = spawn(command, [], { shell: true }) let stdout = '' let stderr = '' let totalSize = 0 // Handle stdout process.stdout.on('data', (data: Buffer) => { totalSize += data.length if (totalSize > (maxOutputSize || DEFAULT_MAX_OUTPUT)) { process.kill() reject(new Error(`Output size exceeded ${maxOutputSize || DEFAULT_MAX_OUTPUT} bytes`)) } stdout += data.toString() }) // Handle stderr process.stderr.on('data', (data: Buffer) => { totalSize += data.length if (totalSize > (maxOutputSize || DEFAULT_MAX_OUTPUT)) { process.kill() reject(new Error(`Output size exceeded ${maxOutputSize || DEFAULT_MAX_OUTPUT} bytes`)) } stderr += data.toString() }) // Handle process completion process.on('close', (code: number) => { resolve({ exitCode: code || 0, stdout, stderr, startTime: startTime.toISOString(), endTime: new Date().toISOString(), }) }) // Handle process errors process.on('error', (err: Error) => { reject(err) }) // Set timeout const timeoutId = setTimeout(() => { process.kill() reject( new Error(`Command execution timed out after ${timeoutMs || DEFAULT_TIMEOUT_MS}ms`) ) }, timeoutMs || DEFAULT_TIMEOUT_MS) // Clear timeout on process exit process.on('exit', () => { clearTimeout(timeoutId) }) }) return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], } } else {
  • Zod schema used to validate and parse the arguments for the 'run_command' tool, including command, optional allowedCommands (array of strings), timeoutMs, and maxOutputSize with appropriate constraints.
    const CommandArgumentsSchema = z.object({ command: z.string().min(1, 'Command cannot be empty'), allowedCommands: z.preprocess((val) => { if (typeof val === 'string') { try { return JSON.parse(val) } catch { return val } } return val }, z.array(z.string()).optional()), timeoutMs: z.number().min(1).max(300000).optional(), // max 5 minutes maxOutputSize: z .number() .min(1) .max(5 * 1024 * 1024) .optional(), // max 5MB })
  • index.ts:52-84 (registration)
    Registers the 'run_command' tool in the MCP server by handling ListToolsRequest and providing the tool's name, description, and inputSchema.
    server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: 'run_command', description: 'Run a terminal command with security controls.', inputSchema: { type: 'object', properties: { command: { type: 'string', description: 'The command to execute', }, allowedCommands: { type: 'array', items: { type: 'string' }, description: 'Optional list of allowed command executables', }, timeoutMs: { type: 'number', description: 'Maximum execution time in milliseconds (default: 30 seconds)', }, maxOutputSize: { type: 'number', description: 'Maximum output size in bytes (default: 1MB)', }, }, required: ['command'], }, }, ], } })
  • TypeScript interface defining the structure of the result returned by the run_command execution.
    interface CommandResult { exitCode: number stdout: string stderr: string startTime: string endTime: string }
  • Default constants used by the run_command handler for timeout and maximum output size.
    const DEFAULT_TIMEOUT_MS = 30000 // 30 seconds const DEFAULT_MAX_OUTPUT = 1024 * 1024 // 1MB

Other Tools

Related 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/RinardNick/mcp-terminal'

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