grep_files_with_matches
Search and list files containing a specific pattern in a target directory. Supports regex, case sensitivity, whole word matching, file extensions, and exclusion patterns for precise results.
Instructions
List only the names of files that contain the pattern
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| case_sensitive | No | Whether the search should be case sensitive | |
| exclude_patterns | No | Exclude files matching these patterns | |
| file_extensions | No | Only search files with these extensions | |
| pattern | Yes | Regular expression pattern or plain text to search for | |
| target | Yes | Directory path to search in | |
| whole_words | No | Match whole words only |
Implementation Reference
- src/index.ts:440-524 (handler)The main handler function for the 'grep_files_with_matches' tool. It validates the input directory, builds grep command arguments using '-l' to list only filenames with matches, '-r' for recursive search, and other options, then executes it using the executeGrep helper and formats the response.// Validate target path const pathValidation = validatePath(target); if (!pathValidation.isValid) { return { content: [ { type: "text", text: `Error: ${pathValidation.error}`, }, ], }; } if (!pathValidation.isDirectory) { return { content: [ { type: "text", text: `Error: Target must be a directory for this operation`, }, ], }; } const args = ['grep']; // List filenames only args.push('-l'); // Use extended regex args.push('-E'); args.push(pattern); // Add case sensitivity option if (!case_sensitive) { args.push('-i'); } // Add whole words option if (whole_words) { args.push('-w'); } // Add recursive search args.push('-r'); // Add file extension filters if (file_extensions && file_extensions.length > 0) { file_extensions.forEach(ext => { args.push('--include', `*.${ext}`); }); } // Add exclusion patterns if (exclude_patterns && exclude_patterns.length > 0) { exclude_patterns.forEach(excludePattern => { args.push('--exclude', excludePattern); }); } // Add target path args.push(target); try { const result = await executeGrep(args); return { content: [ { type: "text", text: `Pattern: ${pattern}\nExit Code: ${result.exitCode}\n\nFiles containing matches:\n${result.stdout}${result.stderr ? `\n\nErrors:\n${result.stderr}` : ''}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error executing grep: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } }
- src/index.ts:432-439 (schema)Zod schema defining the input parameters for the 'grep_files_with_matches' tool.pattern: z.string().describe("Regular expression pattern or plain text to search for"), target: z.string().describe("Directory path to search in"), case_sensitive: z.boolean().optional().default(false).describe("Whether the search should be case sensitive"), whole_words: z.boolean().optional().default(false).describe("Match whole words only"), file_extensions: z.array(z.string()).optional().describe("Only search files with these extensions"), exclude_patterns: z.array(z.string()).optional().describe("Exclude files matching these patterns"), }, async ({ pattern, target, case_sensitive, whole_words, file_extensions, exclude_patterns }) => {
- src/index.ts:429-525 (registration)The server.tool call that registers the 'grep_files_with_matches' tool with MCP server, including name, description, schema, and handler."grep_files_with_matches", "List only the names of files that contain the pattern", { pattern: z.string().describe("Regular expression pattern or plain text to search for"), target: z.string().describe("Directory path to search in"), case_sensitive: z.boolean().optional().default(false).describe("Whether the search should be case sensitive"), whole_words: z.boolean().optional().default(false).describe("Match whole words only"), file_extensions: z.array(z.string()).optional().describe("Only search files with these extensions"), exclude_patterns: z.array(z.string()).optional().describe("Exclude files matching these patterns"), }, async ({ pattern, target, case_sensitive, whole_words, file_extensions, exclude_patterns }) => { // Validate target path const pathValidation = validatePath(target); if (!pathValidation.isValid) { return { content: [ { type: "text", text: `Error: ${pathValidation.error}`, }, ], }; } if (!pathValidation.isDirectory) { return { content: [ { type: "text", text: `Error: Target must be a directory for this operation`, }, ], }; } const args = ['grep']; // List filenames only args.push('-l'); // Use extended regex args.push('-E'); args.push(pattern); // Add case sensitivity option if (!case_sensitive) { args.push('-i'); } // Add whole words option if (whole_words) { args.push('-w'); } // Add recursive search args.push('-r'); // Add file extension filters if (file_extensions && file_extensions.length > 0) { file_extensions.forEach(ext => { args.push('--include', `*.${ext}`); }); } // Add exclusion patterns if (exclude_patterns && exclude_patterns.length > 0) { exclude_patterns.forEach(excludePattern => { args.push('--exclude', excludePattern); }); } // Add target path args.push(target); try { const result = await executeGrep(args); return { content: [ { type: "text", text: `Pattern: ${pattern}\nExit Code: ${result.exitCode}\n\nFiles containing matches:\n${result.stdout}${result.stderr ? `\n\nErrors:\n${result.stderr}` : ''}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error executing grep: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } );
- src/index.ts:21-60 (helper)Helper function used by all grep tools to safely spawn and execute the grep process, capturing stdout, stderr, and exit code.async function executeGrep(args: string[]): Promise<{ stdout: string; stderr: string; exitCode: number }> { return new Promise((resolve) => { // Ensure we're only calling grep with safe arguments if (!args.includes('grep')) { args.unshift('grep'); } const child = spawn('grep', args.slice(1), { stdio: ['pipe', 'pipe', 'pipe'], shell: false, }); let stdout = ''; let stderr = ''; child.stdout.on('data', (data) => { stdout += data.toString(); }); child.stderr.on('data', (data) => { stderr += data.toString(); }); child.on('close', (code) => { resolve({ stdout, stderr, exitCode: code || 0, }); }); child.on('error', (error) => { resolve({ stdout: '', stderr: error.message, exitCode: 1, }); }); }); }
- src/index.ts:63-74 (helper)Helper function to validate if a path exists and whether it is a directory, used in the handler.function validatePath(path: string): { isValid: boolean; isDirectory: boolean; error?: string } { try { const resolvedPath = resolve(path); if (!existsSync(resolvedPath)) { return { isValid: false, isDirectory: false, error: `Path does not exist: ${path}` }; } const stats = statSync(resolvedPath); return { isValid: true, isDirectory: stats.isDirectory() }; } catch (error) { return { isValid: false, isDirectory: false, error: `Invalid path: ${path}` }; } }