shell_grep
Search for text patterns within files using command-line arguments to locate specific content efficiently.
Instructions
Search text patterns in files
Tool call template
This tool declares no required parameters. Add optional parameters from the input schema as needed.
{
"id": 1,
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"arguments": {},
"name": "shell_grep"
}
}Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| args | No | Command arguments |
Implementation Reference
- src/index.ts:45-85 (handler)MCP tool call handler that processes shell_grep by mapping 'shell_grep' to 'shell.grep' config, validating, and executing the 'grep' command via executor.
server.setRequestHandler(CallToolRequestSchema, async (request) => { try { const command = String(request.params?.name || ''); const fullCommand = `shell.${command.replace('shell_', '')}`; // Replace shell_ back to shell. if (!(fullCommand in allowedCommands)) { return { content: [{ type: "text", text: `Unknown command: ${command}` }], isError: true }; } const actualCommand = allowedCommands[fullCommand].command; const args = Array.isArray(request.params?.arguments?.args) ? request.params.arguments.args.map(String) : []; validator.validateCommand(actualCommand, args); const stream = await executor.execute(actualCommand, args); return { content: [{ type: "text", text: await new Promise((resolve, reject) => { const chunks: Buffer[] = []; stream.stdout.on('data', (chunk: Buffer) => chunks.push(chunk)); stream.stdout.on('end', () => resolve(Buffer.concat(chunks).toString())); stream.stdout.on('error', reject); }) }] }; } catch (error) { return { content: [{ type: "text", text: `Command execution failed: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } }); - src/index.ts:27-43 (registration)Registers all shell tools including 'shell_grep' (from 'shell.grep') in the MCP tools list.
server.setRequestHandler(ListToolsRequestSchema, async () => { const tools = Object.entries(allowedCommands).map(([name, config]) => ({ name: name.replace('shell.', 'shell_'), // Replace shell. with shell_ description: config.description, inputSchema: { type: "object", properties: { args: { type: "array", items: { type: "string" }, description: "Command arguments" } } } })); return { tools }; }); - src/index.ts:31-40 (schema)Input schema definition for shell_grep tool: expects an object with 'args' array of strings.
inputSchema: { type: "object", properties: { args: { type: "array", items: { type: "string" }, description: "Command arguments" } } } - src/config/allowlist.ts:66-79 (registration)Allowlist configuration for shell.grep (maps to shell_grep tool), defining command, description, allowed arguments, and timeout.
'shell.grep': { command: 'grep', description: 'Search text patterns in files', allowedArgs: [ '-i', // case-insensitive '-v', // invert match '-n', // show line numbers '-r', // recursive '-l', // show file names only '--color', // colorize '*' // allow patterns and file paths ], timeout: 5000 }, - src/core/executor.ts:31-139 (helper)Core execution helper that spawns the actual 'grep' process for the shell_grep tool using child_process.spawn, handles streaming output.
async execute( command: string, args: string[] = [], options: ExecuteOptions = {} ): Promise<{ stdout: Readable }> { const commandKey = `${command} ${args.join(' ')}`; try { // Check security await this.securityChecker.validateCommand(command, args, options); // Check cache const cached = this.cache.get(commandKey); if (cached) { this.logger.debug('Using cached command result', { command, args }); return this.createStreamFromCache(cached); } // Remove 'shell.' prefix for execution const baseCommand = command.replace('shell.', ''); // Execute command this.logger.debug('Starting command execution', { command, args, options }); const childProcess = spawn(baseCommand, args, { stdio: ['ignore', 'pipe', 'pipe'], timeout: options.timeout, cwd: options.cwd, env: { ...process.env, ...options.env }, signal: options.signal }); this.currentProcess = childProcess; // Error handling childProcess.on('error', (error: Error) => { this.logger.error('Command execution error', { command, args, error: error.message }); throw new ToolError( 'PROCESS_ERROR', 'Command execution error', { command, args, error: error.message } ); }); // Timeout handling if (options.timeout) { setTimeout(() => { if (childProcess.exitCode === null) { this.logger.warn('Command execution timeout', { command, args, timeout: options.timeout }); childProcess.kill(); throw new ToolError( 'TIMEOUT', 'Command execution timeout', { command, args, timeout: options.timeout } ); } }, options.timeout); } if (!childProcess.stdout) { throw new ToolError( 'STREAM_ERROR', 'Unable to get command output stream', { command, args } ); } // Monitor process status childProcess.on('exit', (code, signal) => { this.logger.debug('Command execution completed', { command, args, exitCode: code, signal }); }); return { stdout: childProcess.stdout }; } catch (error) { this.logger.error('Command execution failed', { command, args, error: error instanceof Error ? error.message : String(error) }); throw new ToolError( 'EXECUTION_ERROR', 'Command execution failed', { command, args, error: error instanceof Error ? error.message : String(error) } ); } }