search_conversations
Search historical conversation logs using keywords, file patterns, time ranges, or tags to retrieve relevant project discussions and maintain context across AI sessions.
Instructions
搜索历史对话记录
支持: • 关键词搜索 • 文件名模式搜索 • 时间范围筛选 • 标签过滤
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| keywords | No | 关键词搜索 | |
| filePattern | No | 文件名模式搜索 | |
| days | No | 最近N天 | |
| project | No | 项目过滤(默认当前) | |
| tags | No | 标签过滤 | |
| limit | No | 结果数量限制 |
Implementation Reference
- src/tools/conversationLogger.ts:117-181 (handler)Main handler function for search_conversations tool. Validates input, searches conversations in specified or all projects, aggregates results, handles errors.async searchConversations(params: unknown): Promise<{ content: Array<{ type: string; text: string }> }> { try { const validatedParams = validateSearchConversations(params); const { project } = validatedParams; let searchResults = ''; let totalResults = 0; if (project) { const projectResults = await this.searchInProject(project, validatedParams); searchResults += projectResults.content; totalResults += projectResults.count; } else { const projects = await this.fileManager.listProjects(); for (const proj of projects) { if (totalResults >= validatedParams.limit) break; const projectResults = await this.searchInProject(proj, { ...validatedParams, limit: validatedParams.limit - totalResults }); if (projectResults.content) { searchResults += `\n## 项目: ${proj}\n${projectResults.content}`; totalResults += projectResults.count; } } } if (totalResults === 0) { return { content: [ { type: 'text', text: '🔍 未找到匹配的对话记录。\n\n请尝试调整搜索条件:\n- 检查项目名称是否正确\n- 尝试更广泛的关键词\n- 扩大时间范围' } ] }; } return { content: [ { type: 'text', text: `🔍 找到 ${totalResults} 条匹配的对话记录:\n\n${searchResults}` } ] }; } catch (error) { const errorMessage = error instanceof ValidationError ? `参数验证失败: ${error.message}` : error instanceof SearchError ? `搜索失败: ${error.message} (查询: ${error.query})` : `搜索对话时出错: ${String(error)}`; return { content: [ { type: 'text', text: `❌ ${errorMessage}` } ] }; } }
- src/validation/schemas.ts:36-49 (schema)Zod schema definition for SearchConversations input validation and transformation.export const SearchConversationsSchema = z.object({ project: z.string().optional(), keywords: z.array(z.string()).optional(), filePattern: z.string().optional(), // 文件名模式搜索 days: z.number().int().positive().optional(), platform: PlatformSchema, tags: z.array(z.string()).optional(), limit: z.number().int().positive().max(100).optional() }).transform((data) => ({ ...data, keywords: data.keywords || [], tags: data.tags || [], limit: data.limit || CONSTANTS.DEFAULT_SEARCH_LIMIT }));
- src/index.ts:80-114 (registration)Tool registration in MCP listTools handler, defining name, description, and inputSchema.name: 'search_conversations', description: '搜索历史对话记录\n\n支持:\n• 关键词搜索\n• 文件名模式搜索\n• 时间范围筛选\n• 标签过滤', inputSchema: { type: 'object', properties: { keywords: { type: 'array', items: { type: 'string' }, description: '关键词搜索' }, filePattern: { type: 'string', description: '文件名模式搜索' }, days: { type: 'number', description: '最近N天' }, project: { type: 'string', description: '项目过滤(默认当前)' }, tags: { type: 'array', items: { type: 'string' }, description: '标签过滤' }, limit: { type: 'number', description: '结果数量限制', default: 10 } } } },
- src/index.ts:164-165 (registration)Dispatch handler in MCP callTool that routes to the conversationLogger.searchConversations method.case 'search_conversations': return await this.conversationLogger.searchConversations(args || {});
- Core helper method that searches within a specific project directory for matching conversation log files.private async searchInProject(project: string, params: SearchConversationsParams): Promise<{ content: string; count: number }> { // Search in the ai-logs directory structure (no daily-logs subdirectory) const projectDir = await this.fileManager.getProjectDir(project); try { const { promises: fs } = await import('fs'); const files = await fs.readdir(projectDir); let content = ''; let count = 0; for (const file of files.slice(0, params.limit)) { if (file.endsWith('.md')) { const filePath = join(projectDir, file); const fileContent = await this.fileManager.readFile(filePath); if (this.matchesSearchCriteria(fileContent, params)) { content += `### ${file.replace('.md', '')}\n`; content += this.extractRelevantSections(fileContent, params); content += '\n'; count++; } } } return { content, count }; } catch (error) { throw new SearchError(`搜索项目 ${project} 失败`, String(error)); } }