search
Search through past Claude Code conversations to find previous discussions, decisions, or information from prior interactions across projects.
Instructions
Search through past Claude Code conversations across all projects. Use when the user asks about previous discussions, past decisions, or anything from a prior conversation.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | ||
| project | No | ||
| branch | No | ||
| after | No | ||
| before | No | ||
| limit | No |
Implementation Reference
- src/tools/search.ts:78-163 (handler)The handleSearch function performs the core search logic, including validating the query, checking the indexed session count, performing a hybrid (vector/FTS) search, and formatting the response.
export async function handleSearch( db: Database.Database, params: SearchParams ): Promise<{ content: Array<{ type: string; text: string }> }> { const startTime = Date.now(); // 1. Validate query if (!params.query || params.query.trim().length === 0) { throw new Error("query parameter is required and must be non-empty"); } // 2. Clamp limit const limit = Math.min( params.limit ?? CONFIG.searchDefaultLimit, CONFIG.searchMaxLimit ); // 3. Check indexed session count const indexedCount = getIndexedSessionCount(db); if (indexedCount === 0) { // Count what's on disk const sessionsOnDisk = countSessionsOnDisk(); if (sessionsOnDisk <= CONFIG.autoIndexThreshold) { // Auto-index then search — must wait for background completion await handleIndex(db, { mode: "incremental" }); await waitForIndexComplete(30000); // Fall through — indexedCount will now be non-zero } else { // Too many sessions; require explicit index const response: SearchResponse = { status: "index_required", message: `No sessions have been indexed yet. Found ${sessionsOnDisk} sessions on disk. Run the index tool first.`, sessions_found: sessionsOnDisk, }; return { content: [{ type: "text", text: JSON.stringify(response) }], }; } } // 4. Embed the query with the required prefix const embedder = await getEmbedder(); const embedding = await embedder.embed("query: " + params.query); // 5. Hybrid search (vector + FTS5/BM25 with RRF) const results = vectorSearch(db, { embedding, query: params.query, limit, projectName: params.project, branch: params.branch, after: params.after, before: params.before, }); // 6. Format results const formatted = results.map(formatResult); // 7. Check for stale sessions const currentIndexedCount = getIndexedSessionCount(db); const sessionsOnDiskNow = countSessionsOnDisk(); const unindexedCount = sessionsOnDiskNow - currentIndexedCount; let note: string | undefined; if (unindexedCount > 0) { note = `${unindexedCount} session(s) on disk are not yet indexed. Run the index tool to include them in searches.`; } const queryTimeMs = Date.now() - startTime; const response: SearchResponse = { status: "ok", query: params.query, query_time_ms: queryTimeMs, total_indexed_sessions: currentIndexedCount, result_count: formatted.length, results: formatted, ...(note ? { note } : {}), }; return { content: [{ type: "text", text: JSON.stringify(response) }], }; } - src/server.ts:24-46 (registration)The "search" tool is registered here with the MCP server, defining the input schema using zod and calling the handleSearch handler.
// search tool server.tool( "search", "Search through past Claude Code conversations across all projects. Use when the user asks about previous discussions, past decisions, or anything from a prior conversation.", { query: z.string(), project: z.string().optional(), branch: z.string().optional(), after: z.string().optional(), before: z.string().optional(), limit: z.number().optional(), }, async (args): Promise<ToolResult> => { return handleSearch(db, { query: args.query, project: args.project, branch: args.branch, after: args.after, before: args.before, limit: args.limit, }); } );