runAndExtract
Execute terminal commands and extract specific information from output using natural language prompts. Optimizes token usage by retrieving only relevant data.
Instructions
Execute terminal commands and intelligently extract specific information from their output. Supports cross-platform command execution with security controls.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| terminalCommand | Yes | Shell command to execute. Must be non-interactive (no user input prompts). Navigation commands (cd, pushd, etc.) are not allowed - use workingDirectory instead. | |
| extractionPrompt | Yes | Natural language description of what information to extract from the command output. Examples: "Show me the raw output", "Summarize the results", "Extract all error messages", "Find version numbers", "List all files", "Did the command succeed?", "Are there any warnings?" | |
| workingDirectory | Yes | Full absolute path where command should be executed (e.g., "C:\Users\username\project", "/home/user/project"). Must be within configured security boundaries. |
Implementation Reference
- src/tools/runAndExtract.ts:33-99 (handler)Main execution handler for the runAndExtract tool. Validates inputs (terminalCommand, extractionPrompt, workingDirectory), validates directory path and command security, executes the shell command via execa, processes output through an LLM using the extraction prompt, saves the session for follow-up questions, and returns the extracted information.
async execute(args: any): Promise<MCPToolResponse> { try { this.logOperation('Terminal execution started', { command: args.terminalCommand, workingDirectory: args.workingDirectory }); // Validate required fields const fieldError = this.validateRequiredFields(args, ['terminalCommand', 'extractionPrompt', 'workingDirectory']); if (fieldError) { return this.createErrorResponse(fieldError); } // Validate working directory const dirValidation = await PathValidator.validateWorkingDirectory(args.workingDirectory); if (!dirValidation.valid) { return this.createErrorResponse(dirValidation.error!); } // Validate command security const commandValidation = CommandValidator.validateCommand(args.terminalCommand); if (!commandValidation.valid) { return this.createErrorResponse(commandValidation.error!); } // Log warnings if any if (commandValidation.warnings) { for (const warning of commandValidation.warnings) { Logger.warn(`${warning}`); } } // Execute command const executionResult = await this.executeCommand( args.terminalCommand, dirValidation.resolvedPath! ); // Process output with LLM const extractedInfo = await this.processOutputWithLLM( args.terminalCommand, executionResult.output, executionResult.exitCode, args.extractionPrompt ); // Save session for follow-up questions await SessionManager.saveTerminalSession({ command: args.terminalCommand, output: executionResult.output, exitCode: executionResult.exitCode, extractionPrompt: args.extractionPrompt, extractedInfo, timestamp: new Date().toISOString(), workingDirectory: dirValidation.resolvedPath! }); this.logOperation('Terminal execution completed successfully'); return this.createSuccessResponse(extractedInfo); } catch (error) { this.logOperation('Terminal execution failed', { error }); return this.createErrorResponse( `Terminal execution failed: ${error instanceof Error ? error.message : String(error)}` ); } } - src/tools/runAndExtract.ts:14-31 (schema)Input schema for runAndExtract tool. Requires three string fields: terminalCommand (shell command to execute), extractionPrompt (natural language description of what to extract), and workingDirectory (absolute path for execution).
readonly inputSchema = { type: 'object', properties: { terminalCommand: { type: 'string', description: 'Shell command to execute. Must be non-interactive (no user input prompts). Navigation commands (cd, pushd, etc.) are not allowed - use workingDirectory instead.' }, extractionPrompt: { type: 'string', description: 'Natural language description of what information to extract from the command output. Examples: "Show me the raw output", "Summarize the results", "Extract all error messages", "Find version numbers", "List all files", "Did the command succeed?", "Are there any warnings?"' }, workingDirectory: { type: 'string', description: 'Full absolute path where command should be executed (e.g., "C:\\Users\\username\\project", "/home/user/project"). Must be within configured security boundaries.' } }, required: ['terminalCommand', 'extractionPrompt', 'workingDirectory'] }; - src/server.ts:60-63 (registration)Registration of RunAndExtractTool in the server's setupTools() method. The tool is instantiated as new RunAndExtractTool() and added to the tools map, making it available to MCP clients.
private setupTools(): void { const toolInstances = [ new AskAboutFileTool(), new RunAndExtractTool(), - src/tools/runAndExtract.ts:101-134 (helper)Private helper executeCommand that runs the shell command using execa with shell:true, cross-platform support, configurable timeout, and captures both stdout and stderr. Handles timeout errors and returns partial results on failure.
private async executeCommand(command: string, workingDirectory: string): Promise<{ output: string; exitCode: number; success: boolean; }> { const config = ConfigurationManager.getConfig(); try { const result = await execa(command, { shell: true, cwd: workingDirectory, timeout: config.security.commandTimeout, all: true, // Capture both stdout and stderr reject: false // Don't throw on non-zero exit codes }); return { output: result.all || result.stdout || result.stderr || '', exitCode: result.exitCode || 0, success: result.exitCode === 0 }; } catch (error: any) { if (error.timedOut) { throw new Error(`Command timed out after ${config.security.commandTimeout}ms. This may indicate an interactive command or infinite loop.`); } // Return partial results if available return { output: error.all || error.stdout || error.stderr || `Command failed: ${error.message}`, exitCode: error.exitCode || 1, success: false }; } } - src/tools/runAndExtract.ts:136-177 (helper)Private helper processOutputWithLLM that sends the command output to an LLM provider for intelligent extraction. Uses createTerminalExtractionPrompt to build the prompt with instructions for summarizing/extracting based on the user's natural language extractionPrompt.
private async processOutputWithLLM( command: string, output: string, exitCode: number, extractionPrompt: string ): Promise<string> { const config = ConfigurationManager.getConfig(); const provider = LLMProviderFactory.createProvider(config.llm.provider); const apiKey = this.getApiKey(config.llm.provider, config.llm); const prompt = this.createTerminalExtractionPrompt(output, extractionPrompt, command, exitCode); const response = await provider.processRequest(prompt, config.llm.model, apiKey); if (!response.success) { throw new Error(`LLM processing failed: ${response.error}`); } return response.content; } private createTerminalExtractionPrompt( commandOutput: string, extractionPrompt: string, terminalCommand: string, exitCode: number ): string { return `You are an expert at summarizing terminal command output and extracting specific information. Command executed: ${terminalCommand} Exit code: ${exitCode} Extraction request: ${extractionPrompt} Instructions: - Focus only on what the user specifically requested - Be concise and well-formatted - Use markdown formatting for better readability - If the command failed (non-zero exit code), mention this clearly - If there's no relevant information, say so clearly Command output: ${commandOutput}`; }