find_files
Locate files in code repositories by matching glob patterns (e.g., '.py', 'test_.js') using an in-memory file index. Quickly retrieve file paths for analysis or verification without manual search.
Instructions
Find files matching a glob pattern using pre-built file index.
Use when:
- Looking for files by pattern (e.g., "*.py", "test_*.js")
- Searching by filename only (e.g., "README.md" finds all README files)
- Checking if specific files exist in the project
- Getting file lists for further analysis
Pattern matching:
- Supports both full path and filename-only matching
- Uses standard glob patterns (*, ?, [])
- Fast lookup using in-memory file index
- Uses forward slashes consistently across all platforms
Args:
pattern: Glob pattern to match files (e.g., "*.py", "test_*.js", "README.md")
Returns:
List of file paths matching the pattern
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| pattern | Yes |
Input Schema (JSON Schema)
{
"properties": {
"pattern": {
"title": "Pattern",
"type": "string"
}
},
"required": [
"pattern"
],
"title": "find_filesArguments",
"type": "object"
}
Implementation Reference
- src/code_index_mcp/server.py:209-234 (handler)The MCP tool handler for 'find_files', registered with @mcp.tool(). Executes the tool logic by instantiating FileDiscoveryService and calling its find_files method.@mcp.tool() @handle_mcp_tool_errors(return_type='list') def find_files(pattern: str, ctx: Context) -> List[str]: """ Find files matching a glob pattern using pre-built file index. Use when: - Looking for files by pattern (e.g., "*.py", "test_*.js") - Searching by filename only (e.g., "README.md" finds all README files) - Checking if specific files exist in the project - Getting file lists for further analysis Pattern matching: - Supports both full path and filename-only matching - Uses standard glob patterns (*, ?, []) - Fast lookup using in-memory file index - Uses forward slashes consistently across all platforms Args: pattern: Glob pattern to match files (e.g., "*.py", "test_*.js", "README.md") Returns: List of file paths matching the pattern """ return FileDiscoveryService(ctx).find_files(pattern)
- Helper service method in FileDiscoveryService that performs validation and limits results before delegating to the index manager's find_files.def find_files(self, pattern: str, max_results: Optional[int] = None) -> List[str]: """ Find files matching the given pattern using JSON indexing. Args: pattern: Glob pattern to search for (e.g., "*.py", "test_*.js") max_results: Maximum number of results to return (None for no limit) Returns: List of file paths matching the pattern Raises: ValueError: If pattern is invalid or project not set up """ # Business validation self._validate_discovery_request(pattern) # Get files from JSON index files = self._index_manager.find_files(pattern) # Apply max_results limit if specified if max_results and len(files) > max_results: files = files[:max_results] return files
- Core helper function in ShallowIndexManager that implements the actual glob pattern matching logic using compiled regex patterns with fallbacks for case-insensitivity and recursive search.def find_files(self, pattern: str = "*") -> List[str]: with self._lock: if not isinstance(pattern, str): return [] norm = (pattern.strip() or "*").replace('\\\\','/').replace('\\','/') files = self._file_list or [] # Fast path: wildcard all if norm == "*": return list(files) # 1) Exact, case-sensitive exact_regex = self._compile_glob_regex(norm) exact_hits = [f for f in files if exact_regex.match(f) is not None] if exact_hits or '/' in norm: return exact_hits # 2) Recursive **/ fallback (case-sensitive) recursive_pattern = f"**/{norm}" rec_regex = self._compile_glob_regex(recursive_pattern) rec_hits = [f for f in files if rec_regex.match(f) is not None] if rec_hits: return self._dedupe_preserve_order(exact_hits + rec_hits) # 3) Case-insensitive (root only) ci_regex = self._compile_glob_regex(norm, ignore_case=True) ci_hits = [f for f in files if ci_regex.match(f) is not None] if ci_hits: return self._dedupe_preserve_order(exact_hits + rec_hits + ci_hits) # 4) Case-insensitive recursive rec_ci_regex = self._compile_glob_regex(recursive_pattern, ignore_case=True) rec_ci_hits = [f for f in files if rec_ci_regex.match(f) is not None] if rec_ci_hits: return self._dedupe_preserve_order( exact_hits + rec_hits + ci_hits + rec_ci_hits ) return []