find_related_conversations
Discover conversations related to a specific discussion by analyzing shared files, folders, programming languages, size, or timing. Use this tool to identify similar problem-solving sessions, trace idea evolution, or find discussions about the same codebase.
Instructions
Find conversations related to a reference conversation based on shared files, folders, programming languages, similar size, or temporal proximity. Use this to discover related discussions, find conversations about the same codebase/project, identify similar problem-solving sessions, or trace the evolution of ideas across multiple conversations.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| referenceConversationId | Yes | ID of the conversation to find related conversations for | |
| relationshipTypes | No | Types of relationships to consider when finding related conversations | |
| maxResults | No | Maximum number of related conversations to return (1-50) | |
| minScore | No | Minimum similarity score threshold (0.0-1.0) | |
| includeScoreBreakdown | No | Include detailed breakdown of how similarity scores were calculated | |
| outputMode | No | Output format: "json" for formatted JSON (default), "compact-json" for minified JSON | json |
Implementation Reference
- src/server.ts:266-295 (registration)MCP server registration of the 'find_related_conversations' tool, including input schema validation and thin wrapper handler that formats the response.server.tool( 'find_related_conversations', 'Find conversations related to a reference conversation based on shared files, folders, programming languages, similar size, or temporal proximity. Use this to discover related discussions, find conversations about the same codebase/project, identify similar problem-solving sessions, or trace the evolution of ideas across multiple conversations.', { referenceConversationId: z.string().min(1).describe('ID of the conversation to find related conversations for'), relationshipTypes: z.array(z.enum(['files', 'folders', 'languages', 'size', 'temporal'])).optional().default(['files']).describe('Types of relationships to consider when finding related conversations'), maxResults: z.number().min(1).max(50).optional().default(10).describe('Maximum number of related conversations to return (1-50)'), minScore: z.number().min(0).max(1).optional().default(0.1).describe('Minimum similarity score threshold (0.0-1.0)'), includeScoreBreakdown: z.boolean().optional().default(false).describe('Include detailed breakdown of how similarity scores were calculated'), outputMode: z.enum(['json', 'compact-json']).optional().default('json').describe('Output format: "json" for formatted JSON (default), "compact-json" for minified JSON') }, async (input) => { try { const result = await findRelatedConversations(input); return { content: [{ type: 'text', text: formatResponse(result, input.outputMode) }] }; } catch (error) { return { content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : 'Unknown error occurred'}` }] }; } } );
- src/tools/analytics-tools.ts:130-199 (handler)Primary handler function that connects to the database, retrieves summaries for the reference conversation and all others, extracts languages if needed, and delegates relationship computation to the utility function.export async function findRelatedConversations( input: FindRelatedConversationsInput ): Promise<RelatedConversationsResult> { const reader = new CursorDatabaseReader(); try { await reader.connect(); // Get reference conversation summary const referenceSummary = await reader.getConversationSummary(input.referenceConversationId, { includeFirstMessage: true, includeCodeBlockCount: true, includeFileList: true, includeAttachedFolders: true, maxFirstMessageLength: 150 }); if (!referenceSummary) { throw new DatabaseError(`Reference conversation ${input.referenceConversationId} not found`); } // Get all conversation IDs for comparison const allConversationIds = await reader.getConversationIds({ format: 'both', minLength: 100 }); // Get summaries for all conversations const allSummaries = await reader.getConversationSummariesForAnalytics(allConversationIds); // Extract languages from reference conversation if needed let referenceLanguages: string[] = []; if (input.relationshipTypes.includes('languages')) { const conversationsWithCode = await reader.getConversationsWithCodeBlocks([input.referenceConversationId]); if (conversationsWithCode.length > 0) { referenceLanguages = extractLanguagesFromCodeBlocks(conversationsWithCode[0].codeBlocks); } } // Find related conversations const related = findRelatedConversationsUtil( referenceSummary, allSummaries, allConversationIds, { relationshipTypes: input.relationshipTypes, maxResults: input.maxResults, minScore: input.minScore, includeScoreBreakdown: input.includeScoreBreakdown } ); return { reference: { composerId: referenceSummary.composerId, files: referenceSummary.relevantFiles, folders: referenceSummary.attachedFolders, languages: referenceLanguages, messageCount: referenceSummary.messageCount, size: referenceSummary.conversationSize }, related }; } catch (error) { throw new DatabaseError(`Failed to find related conversations: ${error instanceof Error ? error.message : 'Unknown error'}`); } finally { reader.close(); } }
- src/tools/analytics-tools.ts:30-36 (schema)Zod schema definition for input validation of the findRelatedConversations tool (used for TypeScript typing).export const findRelatedConversationsSchema = z.object({ referenceConversationId: z.string().min(1), relationshipTypes: z.array(z.enum(['files', 'folders', 'languages', 'size', 'temporal'])).optional().default(['files']), maxResults: z.number().min(1).max(50).optional().default(10), minScore: z.number().min(0).max(1).optional().default(0.1), includeScoreBreakdown: z.boolean().optional().default(false) });
- src/utils/relationships.ts:33-76 (helper)Core utility function (aliased as findRelatedConversationsUtil) that iterates over all conversation summaries, computes relationship scores (files, folders, etc.), and returns top related conversations sorted by composite score.export function findRelatedConversations( referenceSummary: ConversationSummary, allSummaries: ConversationSummary[], conversationIds: string[], options: RelationshipOptions ): RelatedConversation[] { const related: RelatedConversation[] = []; // Get reference conversation index for temporal calculations const referenceIndex = conversationIds.indexOf(referenceSummary.composerId); for (const summary of allSummaries) { // Skip the reference conversation itself if (summary.composerId === referenceSummary.composerId) { continue; } const relationships = calculateRelationships( referenceSummary, summary, conversationIds, referenceIndex, options.relationshipTypes ); const score = calculateCompositeScore(relationships, options.relationshipTypes); if (score >= options.minScore) { related.push({ composerId: summary.composerId, relationshipScore: score, relationships, summary: summary.firstMessage || 'No preview available', scoreBreakdown: options.includeScoreBreakdown ? calculateScoreBreakdown(relationships, options.relationshipTypes) : undefined }); } } // Sort by score and limit results return related .sort((a, b) => b.relationshipScore - a.relationshipScore) .slice(0, options.maxResults); }