search_identifiers
Find code identifiers across project files to locate definitions and references with file paths, line numbers, and surrounding context for code navigation.
Instructions
Search for identifiers in code files. Get back a list of matching identifiers with their file, line number, and context. When searching, just use the identifier name without any special characters, prefixes or suffixes. The search is case-insensitive.
Args: project_root: Root directory of the project to search. (must be an absolute path!) query: Search query (identifier name) max_results: Maximum number of results to return context_lines: Number of lines of context to show include_definitions: Whether to include definition occurrences include_references: Whether to include reference occurrences
Returns: Dictionary containing search results or error message
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| project_root | Yes | ||
| query | Yes | ||
| max_results | No | ||
| context_lines | No | ||
| include_definitions | No | ||
| include_references | No |
Implementation Reference
- repomap_server.py:177-270 (handler)The handler function implementing the 'search_identifiers' tool logic. It is registered via the @mcp.tool() decorator. Searches project files for identifier matches using RepoMap to extract tags (defs/refs), filters and sorts them, and provides context snippets.@mcp.tool() async def search_identifiers( project_root: str, query: str, max_results: int = 50, context_lines: int = 2, include_definitions: bool = True, include_references: bool = True ) -> Dict[str, Any]: """Search for identifiers in code files. Get back a list of matching identifiers with their file, line number, and context. When searching, just use the identifier name without any special characters, prefixes or suffixes. The search is case-insensitive. Args: project_root: Root directory of the project to search. (must be an absolute path!) query: Search query (identifier name) max_results: Maximum number of results to return context_lines: Number of lines of context to show include_definitions: Whether to include definition occurrences include_references: Whether to include reference occurrences Returns: Dictionary containing search results or error message """ if not os.path.isdir(project_root): return {"error": f"Project root directory not found: {project_root}"} try: # Initialize RepoMap with search-specific settings repo_map = RepoMap( root=project_root, token_counter_func=lambda text: count_tokens(text, "gpt-4"), file_reader_func=read_text, output_handler_funcs={'info': log.info, 'warning': log.warning, 'error': log.error}, verbose=False, exclude_unranked=True ) # Find all source files in the project all_files = find_src_files(project_root) # Get all tags (definitions and references) for all files all_tags = [] for file_path in all_files: rel_path = str(Path(file_path).relative_to(project_root)) tags = repo_map.get_tags(file_path, rel_path) all_tags.extend(tags) # Filter tags based on search query and options matching_tags = [] query_lower = query.lower() for tag in all_tags: if query_lower in tag.name.lower(): if (tag.kind == "def" and include_definitions) or \ (tag.kind == "ref" and include_references): matching_tags.append(tag) # Sort by relevance (definitions first, then references) matching_tags.sort(key=lambda x: (x.kind != "def", x.name.lower().find(query_lower))) # Limit results matching_tags = matching_tags[:max_results] # Format results with context results = [] for tag in matching_tags: file_path = str(Path(project_root) / tag.rel_fname) # Calculate context range based on context_lines parameter start_line = max(1, tag.line - context_lines) end_line = tag.line + context_lines context_range = list(range(start_line, end_line + 1)) context = repo_map.render_tree( file_path, tag.rel_fname, context_range ) if context: results.append({ "file": tag.rel_fname, "line": tag.line, "name": tag.name, "kind": tag.kind, "context": context }) return {"results": results} except Exception as e: log.exception(f"Error searching identifiers in project '{project_root}': {e}") return {"error": f"Error searching identifiers: {str(e)}"}
- repomap_server.py:177-177 (registration)The @mcp.tool() decorator registers the search_identifiers function as an MCP tool.@mcp.tool()
- repomap_server.py:178-200 (schema)The function signature and docstring define the input schema (parameters) and output format for the tool, used by FastMCP for validation.async def search_identifiers( project_root: str, query: str, max_results: int = 50, context_lines: int = 2, include_definitions: bool = True, include_references: bool = True ) -> Dict[str, Any]: """Search for identifiers in code files. Get back a list of matching identifiers with their file, line number, and context. When searching, just use the identifier name without any special characters, prefixes or suffixes. The search is case-insensitive. Args: project_root: Root directory of the project to search. (must be an absolute path!) query: Search query (identifier name) max_results: Maximum number of results to return context_lines: Number of lines of context to show include_definitions: Whether to include definition occurrences include_references: Whether to include reference occurrences Returns: Dictionary containing search results or error message """
- repomap_server.py:16-25 (helper)Helper function to find all source files in the project directory, used by search_identifiers to discover files to index.def find_src_files(directory: str) -> List[str]: if not os.path.isdir(directory): return [directory] if os.path.isfile(directory) else [] src_files = [] for r, d, f_list in os.walk(directory): d[:] = [d_name for d_name in d if not d_name.startswith('.') and d_name not in {'node_modules', '__pycache__', 'venv', 'env'}] for f in f_list: if not f.startswith('.'): src_files.append(os.path.join(r, f)) return src_files