grep_count
Count pattern matches in files or directories using regex or plain text, with options for case sensitivity, whole words, per-file results, and file extensions.
Instructions
Count the number of matches for a pattern
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| pattern | Yes | Regular expression pattern or plain text to count | |
| target | Yes | File or directory path to search in | |
| case_sensitive | No | Whether the search should be case sensitive | |
| whole_words | No | Match whole words only | |
| by_file | No | Show count per file when searching directories | |
| file_extensions | No | Only search files with these extensions |
Implementation Reference
- src/index.ts:350-424 (handler)The handler function for the 'grep_count' tool. It validates the input path, constructs the grep command with the '-c' flag for counting matches, handles options like case sensitivity, whole words, recursion for directories, file filters, executes the command using executeGrep helper, and formats the output.async ({ pattern, target, case_sensitive, whole_words, by_file, file_extensions }) => { // Validate target path const pathValidation = validatePath(target); if (!pathValidation.isValid) { return { content: [ { type: "text", text: `Error: ${pathValidation.error}`, }, ], }; } const args = ['grep']; // Add count option args.push('-c'); // 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 if target is directory if (pathValidation.isDirectory) { args.push('-r'); // Add filename display for directory searches if (by_file) { args.push('-H'); } } // Add file extension filters if (file_extensions && file_extensions.length > 0 && pathValidation.isDirectory) { file_extensions.forEach(ext => { args.push('--include', `*.${ext}`); }); } // Add target path args.push(target); try { const result = await executeGrep(args); return { content: [ { type: "text", text: `Pattern: ${pattern}\nExit Code: ${result.exitCode}\n\nMatch Counts:\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:342-349 (schema)Zod schema defining the input parameters for the 'grep_count' tool, including pattern, target path, and various search options.{ pattern: z.string().describe("Regular expression pattern or plain text to count"), target: z.string().describe("File or 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"), by_file: z.boolean().optional().default(false).describe("Show count per file when searching directories"), file_extensions: z.array(z.string()).optional().describe("Only search files with these extensions"), },
- src/index.ts:339-425 (registration)Registration of the 'grep_count' tool on the MCP server using server.tool(), specifying name, description, input schema, and handler function.server.tool( "grep_count", "Count the number of matches for a pattern", { pattern: z.string().describe("Regular expression pattern or plain text to count"), target: z.string().describe("File or 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"), by_file: z.boolean().optional().default(false).describe("Show count per file when searching directories"), file_extensions: z.array(z.string()).optional().describe("Only search files with these extensions"), }, async ({ pattern, target, case_sensitive, whole_words, by_file, file_extensions }) => { // Validate target path const pathValidation = validatePath(target); if (!pathValidation.isValid) { return { content: [ { type: "text", text: `Error: ${pathValidation.error}`, }, ], }; } const args = ['grep']; // Add count option args.push('-c'); // 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 if target is directory if (pathValidation.isDirectory) { args.push('-r'); // Add filename display for directory searches if (by_file) { args.push('-H'); } } // Add file extension filters if (file_extensions && file_extensions.length > 0 && pathValidation.isDirectory) { file_extensions.forEach(ext => { args.push('--include', `*.${ext}`); }); } // Add target path args.push(target); try { const result = await executeGrep(args); return { content: [ { type: "text", text: `Pattern: ${pattern}\nExit Code: ${result.exitCode}\n\nMatch Counts:\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)Shared helper function to execute the grep command safely using child_process.spawn, capturing stdout, stderr, and exit code. Used by grep_count and other tools.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)Shared helper function to validate if a path exists and determine if it's a directory. Used by grep_count and other tools for input validation.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}` }; } }