Local semantic code search for Claude Code (MCP) using EmbeddingGemma, FAISS, and AST/tree-sitter chunking. 100% local embeddings and indexing.
The server defines 4 tools with reasonable structure and naming, but has significant gaps in schema documentation, parameter descriptions, and error handling guidance. Tool names follow verb-noun convention (search_code, index_directory, get_project_info, list_projects) which is good. However, parameter validation rules and output schemas are not visible in the provided code. The search_code tool has an exceptionally detailed description (600+ chars) with WHEN TO USE/WHEN NOT TO USE guidance, but other tools have minimal descriptions. Error responses are not documented. Output schemas are referenced in descriptions but not formally defined in JSON Schema format. The code shows use of global state (_embedder, _index_manager, _current_project) which violates stateless request handling patterns required by current MCP spec.
Get information about an indexed project including statistics, indexed files, and index metadata.
Index a directory of Python code for semantic search. Parses files, extracts semantic chunks, generates embeddings, and builds FAISS index for future searches.
List all indexed projects with their metadata and statistics.
PREFERRED: Use this tool for code analysis and understanding tasks. Provides semantic search using EmbeddingGemma-300m model for intelligent code discovery based on functionality rather than just text patterns. WHEN TO USE: - Understanding how specific functionality is implemented - Finding similar patterns across the codebase - Discovering related functions/classes by behavior - Searching for code that handles specific use cases - Analyzing architectural patterns and relationships WHEN NOT TO USE: - Simple exact text/pattern matching (use generic grep/search tools instead) - Searching non-Python files (this tool only works with Python codebases) - When the codebase hasn't been indexed yet (use index_directory first)
Output schemas not formally documented. Tool descriptions reference results (e.g., 'statistics, indexed files, metadata') but no JSON Schema definition of return structure is visible. LLMs cannot plan downstream tool usage without knowing what fields to extract.
Parameter descriptions are incomplete or vague. For index_directory: 'batch_size' lacks a recommended range or default. For search_code: 'max_age_minutes' has a default (5) but no upper/lower bounds documented. For get_project_info and list_projects: no parameters are shown, making it unclear if filtering/sorting is supported.
index_directory and get_project_info descriptions are under 50 characters, too brief to guide LLM selection. 'Index a directory of Python code for semantic search' and 'Get information about an indexed project' lack WHEN TO USE guidance and prerequisites. Compare to search_code's detailed guidance.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | F | 44 | <=2025-11-25 | v2 |
| 2026-03-09 | F | 0 | - | v1 |
No error recovery guidance documented. If index_directory fails due to missing Python files, invalid path, or embedding errors, the description does not hint at recovery steps (e.g., 'Verify the path exists and contains .py files'). Similarly, search_code does not document what to do if the index is stale or corrupted.
Stateful global variables (_embedder, _index_manager, _searcher, _current_project, _model_preload_task_started) violate MCP spec statelessness principle. Each request should be independent; current implementation relies on module-level state that persists across invocations, risking inconsistency in concurrent or distributed scenarios.
search_code accepts a 'search_mode' parameter documented as 'Currently supports semantic mode only', which means the parameter is effectively a no-op. This should either accept an enum with a single value (semantic) or be removed entirely to avoid confusing LLMs into trying other modes.
list_projects has no input parameters, yet no description clarifies what sorting or filtering is available. Does it return all projects, paginated results, or sorted by most recently indexed? This ambiguity forces LLMs to guess or make multiple discovery calls.
Pagination not addressed. search_code returns up to 'k' results (default 5, max recommended 20) but no mechanism for retrieving additional results. If 'k=20' returns exactly 20 results, the LLM cannot determine if there are more matches without increasing 'k' unboundedly. Add a 'next_cursor' or 'has_more' field to response schema.