--- title: "MCP Search Server" description: "9 search tools with examples and usage patterns" --- # MCP Search Server Claude-Mem includes a Model Context Protocol (MCP) server that exposes 9 specialized search tools for querying stored observations and sessions. ## Overview - **Location**: `src/servers/search-server.ts` - **Built Output**: `plugin/scripts/search-server.mjs` - **Configuration**: `plugin/.mcp.json` - **Transport**: stdio - **Tools**: 9 specialized search functions - **Citations**: All results use `claude-mem://` URI scheme ## Configuration The MCP server is automatically registered via `plugin/.mcp.json`: ```json { "mcpServers": { "claude-mem-search": { "type": "stdio", "command": "${CLAUDE_PLUGIN_ROOT}/scripts/search-server.mjs" } } } ``` This registers the `claude-mem-search` server with Claude Code, making the 9 search tools available in all sessions. The server is automatically started when Claude Code launches and communicates via stdio transport. ## Search Tools ### 1. search_observations Full-text search across observation titles, narratives, facts, and concepts. **Parameters**: - `query` (required): Search query for FTS5 full-text search - `type`: Filter by observation type(s) (decision, bugfix, feature, refactor, discovery, change) - `concepts`: Filter by concept tags - `files`: Filter by file paths (partial match) - `project`: Filter by project name - `dateRange`: Filter by date range (`{start, end}`) - `orderBy`: Sort order (relevance, date_desc, date_asc) - `limit`: Maximum results (default: 20, max: 100) - `offset`: Number of results to skip - `format`: Output format ("index" for titles/dates only, "full" for complete details) **Example**: ``` search_observations with query="build system" and type="decision" ``` ### 2. search_sessions Full-text search across session summaries, requests, and learnings. **Parameters**: - `query` (required): Search query for FTS5 full-text search - `project`: Filter by project name - `dateRange`: Filter by date range - `orderBy`: Sort order (relevance, date_desc, date_asc) - `limit`: Maximum results (default: 20, max: 100) - `offset`: Number of results to skip - `format`: Output format ("index" or "full") **Example**: ``` search_sessions with query="hooks implementation" ``` ### 3. search_user_prompts Search raw user prompts with full-text search. Use this to find what the user actually said/requested across all sessions. **Parameters**: - `query` (required): Search query for FTS5 full-text search - `project`: Filter by project name - `dateRange`: Filter by date range - `orderBy`: Sort order (relevance, date_desc, date_asc) - `limit`: Maximum results (default: 20, max: 100) - `offset`: Number of results to skip - `format`: Output format ("index" for truncated prompts/dates, "full" for complete prompt text) **Example**: ``` search_user_prompts with query="authentication feature" ``` **Benefits**: - Full context reconstruction from user intent → Claude actions → outcomes - Pattern detection for repeated requests - Improved debugging by tracing from original user words to final implementation ### 4. find_by_concept Find observations tagged with specific concepts. **Parameters**: - `concept` (required): Concept tag to search for - `project`: Filter by project name - `dateRange`: Filter by date range - `orderBy`: Sort order (relevance, date_desc, date_asc) - `limit`: Maximum results (default: 20, max: 100) - `offset`: Number of results to skip - `format`: Output format ("index" or "full") **Example**: ``` find_by_concept with concept="architecture" ``` ### 5. find_by_file Find observations and sessions that reference specific file paths. **Parameters**: - `filePath` (required): File path to search for (supports partial matching) - `project`: Filter by project name - `dateRange`: Filter by date range - `orderBy`: Sort order (relevance, date_desc, date_asc) - `limit`: Maximum results (default: 20, max: 100) - `offset`: Number of results to skip - `format`: Output format ("index" or "full") **Example**: ``` find_by_file with filePath="worker-service.ts" ``` ### 6. find_by_type Find observations by type (decision, bugfix, feature, refactor, discovery, change). **Parameters**: - `type` (required): Observation type(s) to filter by (single type or array) - `project`: Filter by project name - `dateRange`: Filter by date range - `orderBy`: Sort order (relevance, date_desc, date_asc) - `limit`: Maximum results (default: 20, max: 100) - `offset`: Number of results to skip - `format`: Output format ("index" or "full") **Example**: ``` find_by_type with type=["decision", "feature"] ``` ### 7. get_recent_context Get recent session context including summaries and observations for a project. **Parameters**: - `project`: Project name (defaults to current working directory basename) - `limit`: Number of recent sessions to retrieve (default: 3, max: 10) **Example**: ``` get_recent_context with limit=5 ``` ### 8. get_context_timeline Get a unified timeline of context (observations, sessions, and prompts) around a specific point in time. All record types are interleaved chronologically. **Parameters**: - `anchor` (required): Anchor point - observation ID, session ID (e.g., "S123"), or ISO timestamp - `depth_before` (default: 10): Number of records to retrieve before anchor (max: 50) - `depth_after` (default: 10): Number of records to retrieve after anchor (max: 50) - `project`: Filter by project name **Return Format**: Returns `depth_before` records + anchor + `depth_after` records, all interleaved chronologically. Total records: `depth_before + 1 + depth_after`. **Use Case**: Understanding "what was happening when X occurred" **Example**: ``` # Timeline around observation #123 get_context_timeline with anchor=123 and depth_before=5 and depth_after=5 # Timeline around a session get_context_timeline with anchor="S456" and depth_before=10 and depth_after=10 # Timeline around a timestamp get_context_timeline with anchor="2025-11-06T10:30:00Z" and depth_before=15 and depth_after=5 ``` **Response Structure**: ```json { "timeline": [ { "type": "observation", "id": 120, "title": "Context before", "created_at": "2025-11-06T10:25:00Z" }, { "type": "user-prompt", "id": 45, "prompt": "User request", "created_at": "2025-11-06T10:28:00Z" }, { "type": "observation", "id": 123, "title": "Anchor observation", "created_at": "2025-11-06T10:30:00Z", "isAnchor": true }, { "type": "session", "id": "S456", "request": "Session summary", "created_at": "2025-11-06T10:32:00Z" } ], "anchor": { "type": "observation", "id": 123 } } ``` ### 9. get_timeline_by_query Search for observations using natural language and get timeline context around the best match. Combines search + timeline into a single operation. **Parameters**: - `query` (required): Natural language search query to find relevant observations - `mode` (default: "auto"): Operation mode - `"auto"`: Automatically use top search result as timeline anchor - `"interactive"`: Return top N search results for manual anchor selection - `depth_before` (default: 10): Number of timeline records before anchor (max: 50) - `depth_after` (default: 10): Number of timeline records after anchor (max: 50) - `limit` (default: 5): For interactive mode - number of top search results to display (max: 20) - `project`: Filter by project name **Use Case**: Faster context discovery - "show me what happened around when we fixed the authentication bug" **Example - Auto Mode**: ``` # Automatically find and show timeline for "authentication bug" get_timeline_by_query with query="authentication bug" and mode="auto" and depth_before=10 and depth_after=10 ``` **Example - Interactive Mode**: ``` # Show top 5 matches, let user choose anchor get_timeline_by_query with query="authentication bug" and mode="interactive" and limit=5 ``` **Auto Mode Response**: ```json { "search_result": { "id": 123, "title": "Fix authentication bug", "relevance": 0.95 }, "timeline": [ /* timeline records before and after observation 123 */ ] } ``` **Interactive Mode Response**: ```json { "top_results": [ { "id": 123, "title": "Fix authentication bug", "relevance": 0.95, "created_at": "2025-11-06T10:30:00Z" }, { "id": 98, "title": "Authentication refactor", "relevance": 0.82, "created_at": "2025-11-05T14:20:00Z" } ], "message": "Select an observation ID to view its timeline context" } ``` ## Output Formats All search tools support two output formats: ### Index Format (Default) Returns titles, dates, and source URIs only. Uses ~10x fewer tokens than full format. **Always use index format first** to get an overview and identify relevant results. **Example Output**: ``` 1. [decision] Implement graceful session cleanup Date: 2025-10-21 14:23:45 Source: claude-mem://observation/123 2. [feature] Add FTS5 full-text search Date: 2025-10-21 13:15:22 Source: claude-mem://observation/124 ``` ### Full Format Returns complete observation/summary details including narrative, facts, concepts, files, etc. **Only use after reviewing index results** to dive deep into specific items of interest. ## Search Strategy **Recommended Workflow**: 1. **Initial search**: Use default (index) format to see titles, dates, and sources 2. **Review results**: Identify which items are most relevant to your needs 3. **Deep dive**: Only then use `format: "full"` on specific items of interest 4. **Narrow down**: Use filters (type, dateRange, concepts, files) to refine results **Token Efficiency**: - Index format: ~50-100 tokens per result - Full format: ~500-1000 tokens per result - Start with 3-5 results to avoid MCP token limits ## Citations All search results use the `claude-mem://` URI scheme for citations: - `claude-mem://observation/{id}` - References specific observations - `claude-mem://session/{id}` - References specific sessions - `claude-mem://user-prompt/{id}` - References specific user prompts These citations allow Claude to reference specific historical context in responses. ## FTS5 Query Syntax The `query` parameter supports SQLite FTS5 full-text search syntax: - **Simple**: `"error handling"` - **AND**: `"error" AND "handling"` - **OR**: `"bug" OR "fix"` - **NOT**: `"bug" NOT "feature"` - **Phrase**: `"'exact phrase'"` - **Column**: `title:"authentication"` ## Security As of v4.2.3, all FTS5 queries are properly escaped to prevent SQL injection attacks: - Double quotes are escaped: `query.replace(/"/g, '""')` - Comprehensive test suite with 332 injection attack tests - Affects: `search_observations`, `search_sessions`, `search_user_prompts` ## Example Queries ``` # Find all decisions about build system search_observations with query="build system" and type="decision" # Show everything related to worker-service.ts find_by_file with filePath="worker-service.ts" # Search what we learned about hooks search_sessions with query="hooks" # Show observations tagged with 'architecture' find_by_concept with concept="architecture" # Find what user asked about authentication search_user_prompts with query="authentication" # Get recent context for debugging get_recent_context with limit=5 # Timeline around a specific observation get_context_timeline with anchor=123 and depth_before=10 and depth_after=10 # Quick timeline search for authentication work get_timeline_by_query with query="authentication bug" and mode="auto" ``` ## Implementation The MCP search server is implemented using: - `@modelcontextprotocol/sdk` (v1.20.1) - `SessionSearch` service for FTS5 queries - `SessionStore` for database access - `zod-to-json-schema` for parameter validation **Source Code**: `src/servers/search-server.ts` ## Troubleshooting ### Tool Not Available If search tools are not available in Claude Code sessions: 1. Check MCP configuration: ```bash cat plugin/.mcp.json ``` 2. Verify search server is built: ```bash ls -l plugin/scripts/search-server.mjs ``` 3. Rebuild if needed: ```bash npm run build ``` ### Search Returns No Results 1. Check database has data: ```bash sqlite3 ~/.claude-mem/claude-mem.db "SELECT COUNT(*) FROM observations;" ``` 2. Verify FTS5 tables exist: ```bash sqlite3 ~/.claude-mem/claude-mem.db "SELECT name FROM sqlite_master WHERE type='table' AND name LIKE '%_fts';" ``` 3. Test query syntax: ```bash # Simple query should work search_observations with query="test" ``` ### Token Limit Errors If you hit MCP token limits: 1. Use `format: "index"` instead of `format: "full"` 2. Reduce `limit` parameter (try 3-5 instead of 20) 3. Use more specific filters to narrow results 4. Use `offset` to paginate through results