Skip to main content
Glama

search_directory

Search for regex patterns in files within a specified directory, including optional recursive search, line context, and file inclusion/exclusion filters. Use to locate matches efficiently across multiple files.

Instructions

Search for regex patterns across all files in a directory.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
directory_pathYesAbsolute path to the directory to search
excludeNoGlob pattern for files/directories to exclude
includeNoGlob pattern for files to include (e.g., "*.ts", "*.js")
lines_afterNoNumber of lines to show after each match
lines_beforeNoNumber of lines to show before each match
recursiveNoSearch recursively in subdirectories
regexpYesRegular expression pattern to search for

Implementation Reference

  • The execute handler for the 'search_directory' tool. It validates the directory, defines inner helper functions for searching files and directories, and performs recursive regex search with context lines, include/exclude globs.
    execute: async ({ directory_path, regexp, recursive, lines_before, lines_after, include, exclude }) => { const absolutePath = validateAbsolutePath(directory_path, 'directory_path'); validateDirectoryExists(absolutePath); try { const regex = new RegExp(regexp); const results: string[] = []; let totalMatches = 0; function searchInFile(filePath: string): void { try { const content = fs.readFileSync(filePath, 'utf-8'); const lines = content.split('\n'); const fileMatches: string[] = []; lines.forEach((line, index) => { if (regex.test(line)) { const lineNumber = index + 1; const startLine = Math.max(1, lineNumber - (lines_before || 0)); const endLine = Math.min(lines.length, lineNumber + (lines_after || 0)); const contextLines = lines.slice(startLine - 1, endLine); const context = contextLines.map((ctxLine, ctxIndex) => { const ctxLineNumber = startLine + ctxIndex; const marker = ctxLineNumber === lineNumber ? '>' : ' '; return `${marker} ${ctxLineNumber} | ${ctxLine}`; }).join('\n'); fileMatches.push(`Match at line ${lineNumber}:\n${context}`); totalMatches++; } }); if (fileMatches.length > 0) { results.push(`File: ${filePath}\n${fileMatches.join('\n\n')}`); } } catch (error: any) { // Skip files that can't be read results.push(`Warning: Could not read file ${filePath}: ${error.message}`); } } function matchesPattern(filename: string, pattern?: string): boolean { if (!pattern) return true; // Simple glob matching (could be enhanced with a proper glob library) const regexPattern = pattern.replace(/\*/g, '.*').replace(/\?/g, '.'); return new RegExp(`^${regexPattern}$`).test(filename); } function searchDirectory(dirPath: string): void { const items = fs.readdirSync(dirPath); items.forEach(item => { const itemPath = path.join(dirPath, item); const stats = fs.statSync(itemPath); if (stats.isDirectory()) { if (recursive && !(exclude && matchesPattern(item, exclude))) { searchDirectory(itemPath); } } else if (stats.isFile()) { const includeMatch = !include || matchesPattern(item, include); const excludeMatch = exclude && matchesPattern(item, exclude); if (includeMatch && !excludeMatch) { searchInFile(itemPath); } } }); } searchDirectory(absolutePath); if (totalMatches === 0) { return `No matches found for pattern "${regexp}" in directory "${absolutePath}".`; } return `Found ${totalMatches} match(es) in ${results.length} file(s):\n\n${results.join('\n\n')}`; } catch (error: any) { if (error instanceof UserError) throw error; throw new UserError(`Error searching directory "${absolutePath}": ${error.message}`); } }
  • Zod schema defining the input parameters for the search_directory tool, including directory path, regex, recursion flag, context lines, and glob patterns for include/exclude.
    parameters: z.object({ directory_path: z.string().describe('Absolute path to the directory to search'), regexp: z.string().describe('Regular expression pattern to search for'), recursive: z.boolean().optional().default(false).describe('Search recursively in subdirectories'), lines_before: z.number().int().min(0).optional().describe('Number of lines to show before each match'), lines_after: z.number().int().min(0).optional().describe('Number of lines to show after each match'), include: z.string().optional().describe('Glob pattern for files to include (e.g., "*.ts", "*.js")'), exclude: z.string().optional().describe('Glob pattern for files/directories to exclude') }),
  • src/index.ts:519-519 (registration)
    The server.addTool call registering the search_directory tool.
    server.addTool({
  • Inner helper function that recursively traverses the directory structure, applies include/exclude filters, and calls searchInFile on matching files.
    function searchDirectory(dirPath: string): void { const items = fs.readdirSync(dirPath); items.forEach(item => { const itemPath = path.join(dirPath, item); const stats = fs.statSync(itemPath); if (stats.isDirectory()) { if (recursive && !(exclude && matchesPattern(item, exclude))) { searchDirectory(itemPath); } } else if (stats.isFile()) { const includeMatch = !include || matchesPattern(item, include); const excludeMatch = exclude && matchesPattern(item, exclude); if (includeMatch && !excludeMatch) { searchInFile(itemPath); } } }); }
  • Helper function to match filenames against simple glob patterns for include/exclude filtering.
    function matchesPattern(filename: string, pattern?: string): boolean { if (!pattern) return true; // Simple glob matching (could be enhanced with a proper glob library) const regexPattern = pattern.replace(/\*/g, '.*').replace(/\?/g, '.'); return new RegExp(`^${regexPattern}$`).test(filename); }

Other Tools

Related Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/pwilkin/mcp-file-edit'

If you have feedback or need assistance with the MCP directory API, please join our Discord server