Skip to main content
Glama
wrale

mcp-server-tree-sitter

by wrale

find_text

Search for specific text patterns within project files using customizable filters like file type, regex, case sensitivity, and whole-word matching. Supports context lines for better result understanding.

Instructions

Search for text pattern in project files.

Args: project: Project name pattern: Text pattern to search for file_pattern: Optional glob pattern (e.g., "**/*.py") max_results: Maximum number of results case_sensitive: Whether to do case-sensitive matching whole_word: Whether to match whole words only use_regex: Whether to treat pattern as a regular expression context_lines: Number of context lines to include Returns: List of matches with file, line number, and text

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
case_sensitiveNo
context_linesNo
file_patternNo
max_resultsNo
patternYes
projectYes
use_regexNo
whole_wordNo

Implementation Reference

  • The MCP tool handler function for 'find_text', decorated with @mcp_server.tool() for registration. It handles dependency injection, project resolution, and delegates to the core search_text helper.
    def find_text( project: str, pattern: str, file_pattern: Optional[str] = None, max_results: int = 100, case_sensitive: bool = False, whole_word: bool = False, use_regex: bool = False, context_lines: int = 2, ) -> List[Dict[str, Any]]: """Search for text pattern in project files. Args: project: Project name pattern: Text pattern to search for file_pattern: Optional glob pattern (e.g., "**/*.py") max_results: Maximum number of results case_sensitive: Whether to do case-sensitive matching whole_word: Whether to match whole words only use_regex: Whether to treat pattern as a regular expression context_lines: Number of context lines to include Returns: List of matches with file, line number, and text """ from ..tools.search import search_text config = config_manager.get_config() return search_text( project_registry.get_project(project), pattern, file_pattern, max_results if max_results is not None else config.max_results_default, case_sensitive, whole_word, use_regex, context_lines, )
  • Core helper function implementing the text search logic: prepares regex or string patterns, scans files using glob, processes matches with context lines in parallel using ThreadPoolExecutor, and returns structured results.
    def search_text( project: Any, pattern: str, file_pattern: Optional[str] = None, max_results: int = 100, case_sensitive: bool = False, whole_word: bool = False, use_regex: bool = False, context_lines: int = 0, ) -> List[Dict[str, Any]]: """ Search for text pattern in project files. Args: project: Project object pattern: Text pattern to search for file_pattern: Optional glob pattern to filter files (e.g. "**/*.py") max_results: Maximum number of results to return case_sensitive: Whether to do case-sensitive matching whole_word: Whether to match whole words only use_regex: Whether to treat pattern as a regular expression context_lines: Number of context lines to include before/after matches Returns: List of matches with file, line number, and text """ root = project.root_path results: List[Dict[str, Any]] = [] pattern_obj = None # Prepare the pattern if use_regex: try: flags = 0 if case_sensitive else re.IGNORECASE pattern_obj = re.compile(pattern, flags) except re.error as e: raise ValueError(f"Invalid regular expression: {e}") from e elif whole_word: # Escape pattern for use in regex and add word boundary markers pattern_escaped = re.escape(pattern) flags = 0 if case_sensitive else re.IGNORECASE pattern_obj = re.compile(rf"\b{pattern_escaped}\b", flags) elif not case_sensitive: # For simple case-insensitive search pattern = pattern.lower() file_pattern = file_pattern or "**/*" # Process files in parallel def process_file(file_path: Path) -> List[Dict[str, Any]]: file_results = [] try: validate_file_access(file_path, root) with open(file_path, "r", encoding="utf-8", errors="replace") as f: lines = f.readlines() for i, line in enumerate(lines, 1): match = False if pattern_obj: # Using regex pattern match_result = pattern_obj.search(line) match = bool(match_result) elif case_sensitive: # Simple case-sensitive search - check both original and stripped versions match = pattern in line or pattern.strip() in line.strip() else: # Simple case-insensitive search - check both original and stripped versions line_lower = line.lower() pattern_lower = pattern.lower() match = pattern_lower in line_lower or pattern_lower.strip() in line_lower.strip() if match: # Calculate context lines start = max(0, i - 1 - context_lines) end = min(len(lines), i + context_lines) context = [] for ctx_i in range(start, end): ctx_line = lines[ctx_i].rstrip("\n") context.append( { "line": ctx_i + 1, "text": ctx_line, "is_match": ctx_i == i - 1, } ) file_results.append( { "file": str(file_path.relative_to(root)), "line": i, "text": line.rstrip("\n"), "context": context, } ) if len(file_results) >= max_results: break except Exception: # Skip files that can't be read pass return file_results # Collect files to process files_to_process = [] for path in root.glob(file_pattern): if path.is_file(): files_to_process.append(path) # Process files in parallel with concurrent.futures.ThreadPoolExecutor() as executor: futures = [executor.submit(process_file, f) for f in files_to_process] for future in concurrent.futures.as_completed(futures): results.extend(future.result()) if len(results) >= max_results: # Cancel any pending futures for f in futures: f.cancel() break return results[:max_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/wrale/mcp-server-tree-sitter'

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