Skip to main content
Glama
safurrier

MCP Filesystem Server

search_files

Search for files and directories matching a pattern recursively. Supports content matching, exclusion rules, and custom output formats (text or JSON). Ideal for locating specific data within complex filesystems.

Instructions

Recursively search for files and directories matching a pattern.

Args: path: Starting directory pattern: Glob pattern to match against filenames recursive: Whether to search subdirectories exclude_patterns: Optional patterns to exclude content_match: Optional text to search within files max_results: Maximum number of results to return format: Output format ('text' or 'json') ctx: MCP context Returns: Search results

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
content_matchNo
exclude_patternsNo
formatNotext
max_resultsNo
pathYes
patternYes
recursiveNo

Implementation Reference

  • Core handler implementation for the search_files tool. Performs glob-based file discovery with optional content matching, respecting security constraints and limits.
    async def search_files( self, root_path: Union[str, Path], pattern: str, recursive: bool = True, exclude_patterns: Optional[List[str]] = None, content_match: Optional[str] = None, max_results: int = 1000, encoding: str = "utf-8", ) -> List[Dict]: """Search for files matching pattern and/or containing text. Args: root_path: Starting directory for search pattern: Glob pattern to match against filenames recursive: Whether to search subdirectories exclude_patterns: Optional patterns to exclude content_match: Optional text to search within files max_results: Maximum number of results to return encoding: Text encoding for content matching Returns: List of matching file information Raises: ValueError: If root_path is outside allowed directories """ # Find files matching the pattern matching_files = await self.validator.find_matching_files( root_path, pattern, recursive, exclude_patterns ) results = [] # If we don't need to match content, just return file info if content_match is None: for file_path in matching_files[:max_results]: try: # Skip directories if pattern matched them if file_path.is_dir(): continue info = FileInfo(file_path) results.append(info.to_dict()) except (PermissionError, FileNotFoundError): # Skip files we can't access pass return results # If we need to match content, check each file for file_path in matching_files: if len(results) >= max_results: break try: # Skip directories if file_path.is_dir(): continue # Skip very large files for content matching (>10MB) if file_path.stat().st_size > 10_000_000: continue # Check if file contains the search text try: content = await anyio.to_thread.run_sync( file_path.read_text, encoding ) if content_match in content: info = FileInfo(file_path) results.append(info.to_dict()) except UnicodeDecodeError: # Skip binary files pass except (PermissionError, FileNotFoundError): # Skip files we can't access pass return results
  • MCP tool registration using @mcp.tool() decorator. Defines input parameters, delegates execution to operations.search_files, and handles output formatting in text or JSON.
    async def search_files( path: str, pattern: str, ctx: Context, recursive: bool = True, exclude_patterns: Optional[List[str]] = None, content_match: Optional[str] = None, max_results: int = 100, format: str = "text", ) -> str: """Recursively search for files and directories matching a pattern. Args: path: Starting directory pattern: Glob pattern to match against filenames recursive: Whether to search subdirectories exclude_patterns: Optional patterns to exclude content_match: Optional text to search within files max_results: Maximum number of results to return format: Output format ('text' or 'json') ctx: MCP context Returns: Search results """ try: components = get_components() results = await components["operations"].search_files( path, pattern, recursive, exclude_patterns, content_match, max_results ) if format.lower() == "json": return json.dumps(results, indent=2) # Format as text if not results: return "No matching files found" lines = [] for item in results: is_dir = item.get("is_directory", False) type_label = "[DIR]" if is_dir else "[FILE]" size = f" ({item['size']:,} bytes)" if not is_dir else "" lines.append(f"{type_label} {item['path']}{size}") return f"Found {len(results)} matching files:\n\n" + "\n".join(lines) except Exception as e: return f"Error searching files: {str(e)}"
  • Helper function in PathValidator that performs secure glob-based file discovery, validating paths against allowed directories and applying exclude patterns.
    async def find_matching_files( self, root_path: Union[str, Path], pattern: str, recursive: bool = True, exclude_patterns: Optional[List[str]] = None, ) -> List[Path]: """Find files matching a pattern within allowed directories. Args: root_path: Starting directory for search pattern: Glob pattern to match against filenames recursive: Whether to search subdirectories exclude_patterns: Optional patterns to exclude Returns: List of matching file paths Raises: ValueError: If root_path is outside allowed directories """ abs_path, allowed = await self.validate_path(root_path) if not allowed: raise ValueError(f"Search path outside allowed directories: {root_path}") if not abs_path.is_dir(): raise ValueError(f"Search path is not a directory: {abs_path}") results = [] exclude_regexes = [] # Compile exclude patterns if provided if exclude_patterns: for exclude in exclude_patterns: try: exclude_regexes.append(re.compile(exclude)) except re.error: logger.warning(f"Invalid exclude pattern: {exclude}") # Use glob for pattern matching glob_pattern = "**/" + pattern if recursive else pattern for matched_path in abs_path.glob(glob_pattern): # Skip if matched by exclude pattern path_str = str(matched_path) excluded = False for exclude_re in exclude_regexes: if exclude_re.search(path_str): excluded = True break if not excluded: # Verify path is still allowed (e.g., in case of symlinks) if self.is_path_allowed(matched_path): results.append(matched_path) return results

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/safurrier/mcp-filesystem'

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