search_files
Locate files by name using case-insensitive substring matching across subdirectories. Specify absolute paths for reliable results, with a customizable 30-second timeout. Designed for secure and efficient file searching.
Instructions
Finds files by name using a case-insensitive substring matching.
Use this instead of 'execute_command' with find/dir/ls for locating files.
Searches through all subdirectories from the starting path.
Has a default timeout of 30 seconds which can be customized using the timeoutMs parameter.
Only searches within allowed directories.
IMPORTANT: Always use absolute paths for reliability. Paths are automatically normalized regardless of slash direction. Relative paths may fail as they depend on the current working directory. Tilde paths (~/...) might not work in all contexts. Unless the user explicitly asks for relative paths, use absolute paths.
This command can be referenced as "DC: ..." or "use Desktop Commander to ..." in your instructions.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| pattern | Yes | ||
| timeoutMs | No |
Implementation Reference
- src/tools/filesystem.ts:1007-1072 (helper)Main implementation of searchFiles function, which performs file search using ripgrep via searchManager with polling for synchronous results, falls back to pure Node.js recursive search.export async function searchFiles(rootPath: string, pattern: string): Promise<string[]> { // Use the new search manager for better performance // This provides a temporary compatibility layer until we fully migrate to search sessions const { searchManager } = await import('../search-manager.js'); try { const result = await searchManager.startSearch({ rootPath, pattern, searchType: 'files', ignoreCase: true, maxResults: 5000, // Higher limit for compatibility earlyTermination: true, // Use early termination for better performance }); const sessionId = result.sessionId; // Poll for results until complete let allResults: string[] = []; let isComplete = result.isComplete; let startTime = Date.now(); // Add initial results for (const searchResult of result.results) { if (searchResult.type === 'file') { allResults.push(searchResult.file); } } while (!isComplete) { await new Promise(resolve => setTimeout(resolve, 100)); // Wait 100ms const results = searchManager.readSearchResults(sessionId); isComplete = results.isComplete; // Add new file paths to results for (const searchResult of results.results) { if (searchResult.file !== '__LAST_READ_MARKER__' && searchResult.type === 'file') { allResults.push(searchResult.file); } } // Safety check to prevent infinite loops (30 second timeout) if (Date.now() - startTime > 30000) { searchManager.terminateSearch(sessionId); break; } } // Log only the count of found files, not their paths capture('server_search_files_complete', { resultsCount: allResults.length, patternLength: pattern.length, usedRipgrep: true }); return allResults; } catch (error) { // Fallback to original Node.js implementation if ripgrep fails capture('server_search_files_ripgrep_fallback', { error: error instanceof Error ? error.message : 'Unknown error' }); return await searchFilesNodeJS(rootPath, pattern); } }
- src/tools/filesystem.ts:1075-1129 (helper)Fallback Node.js implementation for searchFiles when ripgrep/searchManager fails. Recursively searches directories for files matching pattern in name.async function searchFilesNodeJS(rootPath: string, pattern: string): Promise<string[]> { const results: string[] = []; async function search(currentPath: string): Promise<void> { let entries; try { entries = await fs.readdir(currentPath, { withFileTypes: true }); } catch (error) { return; // Skip this directory on error } for (const entry of entries) { const fullPath = path.join(currentPath, entry.name); try { await validatePath(fullPath); if (entry.name.toLowerCase().includes(pattern.toLowerCase())) { results.push(fullPath); } if (entry.isDirectory()) { await search(fullPath); } } catch (error) { continue; } } } try { // Validate root path before starting search const validPath = await validatePath(rootPath); await search(validPath); // Log only the count of found files, not their paths capture('server_search_files_complete', { resultsCount: results.length, patternLength: pattern.length, usedRipgrep: false }); return results; } catch (error) { // For telemetry only - sanitize error info capture('server_search_files_error', { errorType: error instanceof Error ? error.name : 'Unknown', error: 'Error with root path', isRootPathError: true }); // Re-throw the original error for the caller throw error; } }