search_files
Locate files and directories in your notes by searching recursively with a case-insensitive pattern, returning full paths for partial matches. Exclude specific glob patterns to refine results.
Instructions
Recursively search for files and directories matching a pattern in your notes directory. The search is case-insensitive and matches partial names. Returns full paths to all matching items. Great for finding notes when you don't know their exact location.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| excludePatterns | No | Glob patterns to exclude from search results | |
| pattern | Yes | The pattern to search for in file and directory names |
Implementation Reference
- src/tools/filesystem.ts:172-210 (handler)Main handler for 'search_files' tool: validates input, invokes searchFiles helper, formats relative paths, returns results or error.export async function handleSearchFiles(notesPath: string, args: SearchFilesArgs): Promise<ToolCallResult> { try { // Validate pattern is provided if (!args.pattern) { throw new Error("'pattern' parameter is required"); } // Always search in the notes directory const results = await searchFiles( notesPath, args.pattern, args.excludePatterns || [] ); if (results.length === 0) { return { content: [{ type: "text", text: "No files found matching the pattern." }] }; } // Format results as relative paths const formattedResults = results.map((filePath: string) => path.relative(notesPath, filePath) ); return { content: [{ type: "text", text: `Found ${results.length} files matching "${args.pattern}":\n\n${formattedResults.join('\n')}` }] }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); return { content: [{ type: "text", text: `Error searching files: ${errorMessage}` }], isError: true }; } }
- src/tools/filesystem.ts:46-67 (schema)Tool definition including input schema for 'search_files'.{ name: "search_files", description: "Recursively search for files and directories matching a pattern in your notes directory. " + "The search is case-insensitive and matches partial names. Returns full paths to all " + "matching items. Great for finding notes when you don't know their exact location.", inputSchema: { type: "object", properties: { pattern: { type: "string", description: "The pattern to search for in file and directory names" }, excludePatterns: { type: "array", items: { type: "string" }, description: "Glob patterns to exclude from search results", default: [] } }, required: ["pattern"] }, },
- search-utils.ts:12-77 (helper)Core recursive file search implementation using minimatch for exclusions, case-insensitive partial name matching.export async function searchFiles(rootPath: string, pattern: string, excludePatterns: string[] = []): Promise<string[]> { const results: string[] = []; // Normalize the search pattern for better matching const normalizedPattern = pattern.toLowerCase(); // Make sure the root path exists try { const rootStats = await fs.stat(rootPath); if (!rootStats.isDirectory()) { console.error(`Search root is not a directory: ${rootPath}`); return []; } } catch (error) { console.error(`Error accessing search root path ${rootPath}:`, error); return []; } async function search(currentPath: string): Promise<void> { try { // Read directory entries const entries = await fs.readdir(currentPath, { withFileTypes: true }); for (const entry of entries) { const fullPath = path.join(currentPath, entry.name); try { // Check if path matches any exclude pattern const relativePath = path.relative(rootPath, fullPath); const shouldExclude = excludePatterns.some(pattern => { const globPattern = pattern.includes('*') ? pattern : `**/${pattern}/**`; return minimatch(relativePath, globPattern, { dot: true }); }); if (shouldExclude) { continue; } // Match the name (case-insensitive) if (entry.name.toLowerCase().includes(normalizedPattern)) { results.push(fullPath); } // Recursively search subdirectories if (entry.isDirectory()) { await search(fullPath); } } catch (error) { // Skip problematic entries console.error(`Error processing ${fullPath}:`, error); continue; } } } catch (error) { console.error(`Error reading directory ${currentPath}:`, error); } } // Start the search await search(rootPath); // Log the number of results found console.error(`Search found ${results.length} results for pattern "${pattern}" in ${rootPath}`); return results; }
- src/tools/index.ts:348-349 (registration)Switch case registration dispatching 'search_files' tool calls to handleSearchFiles.case "search_files": return await handleSearchFiles(notesPath, args);
- src/tools/index.ts:8-17 (registration)Import of handleSearchFiles handler from filesystem module for tool registration.import { ensureDirectory, initializeNotesDirectory, handleSearchFiles, handleReadNote, handleReadMultipleNotes, handleListDirectory, handleCreateDirectory, getFilesystemToolDefinitions } from './filesystem.js';