execute_command
Run commands in PowerShell, CMD, or Git Bash shells directly on Windows systems using a secure CLI interface. Specify the command, shell type, and working directory for targeted execution.
Instructions
Execute a command in the specified shell (powershell, cmd, or gitbash)
Example usage (PowerShell):
{
"shell": "powershell",
"command": "Get-Process | Select-Object -First 5",
"workingDir": "C:\Users\username"
}
Example usage (CMD):
{
"shell": "cmd",
"command": "dir /b",
"workingDir": "C:\Projects"
}
Example usage (Git Bash):
{
"shell": "gitbash",
"command": "ls -la",
"workingDir": "/c/Users/username"
}
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| command | Yes | Command to execute | |
| shell | Yes | Shell to use for command execution | |
| workingDir | No | Working directory for command execution (optional) |
Input Schema (JSON Schema)
{
"properties": {
"command": {
"description": "Command to execute",
"type": "string"
},
"shell": {
"description": "Shell to use for command execution",
"enum": [
"powershell",
"cmd",
"gitbash"
],
"type": "string"
},
"workingDir": {
"description": "Working directory for command execution (optional)",
"type": "string"
}
},
"required": [
"shell",
"command"
],
"type": "object"
}
Implementation Reference
- src/index.ts:539-692 (handler)Main handler logic for the 'execute_command' tool: parses arguments with Zod, validates command security, spawns child process for specified shell (powershell/cmd/gitbash), captures stdout/stderr, handles timeouts and errors, logs to history, returns structured output with exit code metadata.case "execute_command": { const args = z.object({ shell: z.enum(Object.keys(this.config.shells).filter(shell => this.config.shells[shell as keyof typeof this.config.shells].enabled ) as [string, ...string[]]), command: z.string(), workingDir: z.string().optional() }).parse(request.params.arguments); // Validate command this.validateCommand(args.shell as keyof ServerConfig['shells'], args.command); // Validate working directory if provided let workingDir = args.workingDir ? path.resolve(args.workingDir) : process.cwd(); const shellKey = args.shell as keyof typeof this.config.shells; const shellConfig = this.config.shells[shellKey]; if (this.config.security.restrictWorkingDirectory) { const isAllowedPath = Array.from(this.allowedPaths).some( allowedPath => workingDir.startsWith(allowedPath) ); if (!isAllowedPath) { throw new McpError( ErrorCode.InvalidRequest, `Working directory (${workingDir}) outside allowed paths. Consult the server admin for configuration changes (config.json - restrictWorkingDirectory, allowedPaths).` ); } } // Execute command return new Promise((resolve, reject) => { let shellProcess: ReturnType<typeof spawn>; try { shellProcess = spawn( shellConfig.command, [...shellConfig.args, args.command], { cwd: workingDir, stdio: ['pipe', 'pipe', 'pipe'] } ); } catch (err) { throw new McpError( ErrorCode.InternalError, `Failed to start shell process: ${err instanceof Error ? err.message : String(err)}. Consult the server admin for configuration changes (config.json - shells).` ); } if (!shellProcess.stdout || !shellProcess.stderr) { throw new McpError( ErrorCode.InternalError, 'Failed to initialize shell process streams' ); } let output = ''; let error = ''; shellProcess.stdout.on('data', (data) => { output += data.toString(); }); shellProcess.stderr.on('data', (data) => { error += data.toString(); }); shellProcess.on('close', (code) => { // Prepare detailed result message let resultMessage = ''; if (code === 0) { resultMessage = output || 'Command completed successfully (no output)'; } else { resultMessage = `Command failed with exit code ${code}\n`; if (error) { resultMessage += `Error output:\n${error}\n`; } if (output) { resultMessage += `Standard output:\n${output}`; } if (!error && !output) { resultMessage += 'No error message or output was provided'; } } // Store in history if enabled if (this.config.security.logCommands) { this.commandHistory.push({ command: args.command, output: resultMessage, timestamp: new Date().toISOString(), exitCode: code ?? -1 }); // Trim history if needed if (this.commandHistory.length > this.config.security.maxHistorySize) { this.commandHistory = this.commandHistory.slice(-this.config.security.maxHistorySize); } } resolve({ content: [{ type: "text", text: resultMessage }], isError: code !== 0, metadata: { exitCode: code ?? -1, shell: args.shell, workingDirectory: workingDir } }); }); // Handle process errors (e.g., shell crashes) shellProcess.on('error', (err) => { const errorMessage = `Shell process error: ${err.message}`; if (this.config.security.logCommands) { this.commandHistory.push({ command: args.command, output: errorMessage, timestamp: new Date().toISOString(), exitCode: -1 }); } reject(new McpError( ErrorCode.InternalError, errorMessage )); }); // Set configurable timeout to prevent hanging const timeout = setTimeout(() => { shellProcess.kill(); const timeoutMessage = `Command execution timed out after ${this.config.security.commandTimeout} seconds. Consult the server admin for configuration changes (config.json - commandTimeout).`; if (this.config.security.logCommands) { this.commandHistory.push({ command: args.command, output: timeoutMessage, timestamp: new Date().toISOString(), exitCode: -1 }); } reject(new McpError( ErrorCode.InternalError, timeoutMessage )); }, this.config.security.commandTimeout * 1000); shellProcess.on('close', () => clearTimeout(timeout)); }); }
- src/index.ts:302-322 (schema)Input schema definition for the 'execute_command' tool, specifying shell (from enabled configs), required command, and optional workingDir.inputSchema: { type: "object", properties: { shell: { type: "string", enum: Object.keys(this.config.shells).filter(shell => this.config.shells[shell as keyof typeof this.config.shells].enabled ), description: "Shell to use for command execution" }, command: { type: "string", description: "Command to execute" }, workingDir: { type: "string", description: "Working directory for command execution (optional)" } }, required: ["shell", "command"] }
- src/index.ts:272-323 (registration)Tool registration in the ListTools response, including name 'execute_command', detailed description with examples, and input schema.{ name: "execute_command", description: `Execute a command in the specified shell (powershell, cmd, or gitbash) Example usage (PowerShell): \`\`\`json { "shell": "powershell", "command": "Get-Process | Select-Object -First 5", "workingDir": "C:\\Users\\username" } \`\`\` Example usage (CMD): \`\`\`json { "shell": "cmd", "command": "dir /b", "workingDir": "C:\\Projects" } \`\`\` Example usage (Git Bash): \`\`\`json { "shell": "gitbash", "command": "ls -la", "workingDir": "/c/Users/username" } \`\`\``, inputSchema: { type: "object", properties: { shell: { type: "string", enum: Object.keys(this.config.shells).filter(shell => this.config.shells[shell as keyof typeof this.config.shells].enabled ), description: "Shell to use for command execution" }, command: { type: "string", description: "Command to execute" }, workingDir: { type: "string", description: "Working directory for command execution (optional)" } }, required: ["shell", "command"] } },