search_files
Find files and directories by name pattern across subdirectories. Search recursively from a starting path with case-insensitive matching for partial names.
Instructions
Recursively search for files and directories matching a pattern. Searches through all subdirectories from the starting path. The search is case-insensitive and matches partial names. Returns full paths to all matching items. Great for finding files when you don't know their exact location. Only searches within allowed directories.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Root path to start searching from | |
| pattern | Yes | Pattern to match against filenames and directories | |
| excludePatterns | No | Patterns to exclude from search results |
Implementation Reference
- src/index.ts:606-680 (handler)The main handler for the 'search_files' tool. Validates input using SearchFilesArgsSchema, performs recursive search starting from the given path, matches filenames case-insensitively against the pattern, supports excludePatterns using minimatch globs, collects full paths of matches, and returns formatted results or 'No matches found'.
case 'search_files': { const parsed = SearchFilesArgsSchema.safeParse(a) if (!parsed.success) { throw new FileSystemError(`Invalid arguments for ${name}`, 'INVALID_ARGS', undefined, { errors: parsed.error.format(), }) } const validPath = await validatePath(parsed.data.path, config) const patternLower = parsed.data.pattern.toLowerCase() const results: string[] = [] async function search(currentPath: string) { try { const entries = await fs.readdir(currentPath, { withFileTypes: true }) for (const entry of entries) { const fullPath = path.join(currentPath, entry.name) try { await validatePath(fullPath, config) const relativePath = path.relative(validPath, fullPath) // Check if the path should be excluded const shouldExclude = parsed.data && parsed.data.excludePatterns.some((excludePattern) => { const globPattern = excludePattern.includes('*') ? excludePattern : `**/${excludePattern}**` return minimatch(relativePath, globPattern, { nocase: true }) }) if (shouldExclude) { continue } // Check if the name matches the search pattern if (entry.name.toLowerCase().includes(patternLower)) { results.push(fullPath) } // Recursively search subdirectories if (entry.isDirectory()) { await search(fullPath) } } catch (error) { // Skip paths we can't access or validate continue } } } catch (error) { // Skip directories we can't read return } } await search(validPath) await logger.debug(`Search complete: ${parsed.data.pattern}`, { resultCount: results.length, }) endMetric() return { content: [ { type: 'text', text: results.length > 0 ? `Found ${results.length} matches:\n${results.join('\n')}` : 'No matches found', }, ], } } - src/index.ts:133-141 (schema)Zod schema defining the input parameters for the search_files tool: required path (root to search from), pattern (string to match in names), and optional excludePatterns array.
const SearchFilesArgsSchema = z.object({ path: z.string().describe('Root path to start searching from'), pattern: z.string().describe('Pattern to match against filenames and directories'), excludePatterns: z .array(z.string()) .optional() .default([]) .describe('Patterns to exclude from search results'), }) - src/index.ts:306-315 (registration)Registers the search_files tool in the ListTools response, providing name, detailed description, and inputSchema converted from SearchFilesArgsSchema.
{ name: 'search_files', description: 'Recursively search for files and directories matching a pattern. ' + 'Searches through all subdirectories from the starting path. The search ' + 'is case-insensitive and matches partial names. Returns full paths to all ' + "matching items. Great for finding files when you don't know their exact location. " + 'Only searches within allowed directories.', inputSchema: zodToJsonSchema(SearchFilesArgsSchema) as ToolInput, },