get_conversation_analytics
Analyze Cursor chat history to identify coding patterns, file usage, and development activity trends for improved project insights.
Instructions
Get comprehensive analytics and statistics about Cursor chats including usage patterns, file activity, programming language distribution, and temporal trends. BEST PRACTICE: Use projectPath parameter for project-specific analytics - this analyzes only conversations that worked on files in that project, providing much more relevant insights for understanding coding patterns, file usage, and development activity within a specific codebase. WORKFLOW TIP: Always include "files" and "languages" in breakdowns - these contain conversation IDs in their arrays that you can immediately use with get_conversation tool. Use includeConversationDetails=true when you need the full conversation ID list and basic metadata for follow-up analysis.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| scope | No | Analysis scope: all conversations, recent only, or project-specific. Use "project" with projectPath for focused project analysis. | all |
| projectPath | No | **HIGHLY RECOMMENDED** Project/codebase name (e.g., "my-app") or full path for project-scoped analysis. When provided, analyzes only conversations that worked on files in that project, giving much more relevant insights about coding patterns and development activity. | |
| recentDays | No | Number of recent days to analyze (1-365) | |
| includeBreakdowns | No | Types of breakdowns to include in the analysis. IMPORTANT: "files" and "languages" breakdowns contain conversation IDs in their arrays - use these for follow-up analysis! | |
| includeConversationDetails | No | Include full conversation ID list and basic metadata (increases response size significantly) | |
| outputMode | No | Output format: "json" for formatted JSON (default), "compact-json" for minified JSON | json |
Implementation Reference
- src/tools/analytics-tools.ts:44-125 (handler)The main handler function that executes the get_conversation_analytics tool logic, querying the database, calculating analytics breakdowns, and returning structured ConversationAnalytics.export async function getConversationAnalytics( input: GetConversationAnalyticsInput ): Promise<ConversationAnalytics> { const reader = new CursorDatabaseReader(); try { await reader.connect(); // Build filters based on scope const filters: ConversationFilters = { format: 'both', minLength: 100 // Filter out only very small conversations (reduced from 1000) }; if (input.scope === 'project' && input.projectPath) { filters.projectPath = input.projectPath; } // Get conversation IDs const conversationIds = await reader.getConversationIds(filters); // Apply recent filter if needed let filteredIds = conversationIds; if (input.scope === 'recent') { // Take the most recent conversations (ROWID ordering) const recentCount = Math.min(conversationIds.length, Math.floor(conversationIds.length * 0.3)); filteredIds = conversationIds.slice(0, recentCount); } // Get conversation summaries const summaries = await reader.getConversationSummariesForAnalytics(filteredIds); // Calculate overview const overview = calculateOverview(summaries); // Calculate breakdowns const breakdowns: any = {}; if (input.includeBreakdowns.includes('files')) { breakdowns.files = calculateFileBreakdown(summaries); } if (input.includeBreakdowns.includes('languages')) { // Get conversations with code blocks for language analysis const conversationsWithCode = await reader.getConversationsWithCodeBlocks(filteredIds); breakdowns.languages = calculateLanguageBreakdown(conversationsWithCode); } if (input.includeBreakdowns.includes('temporal')) { breakdowns.temporal = calculateTemporalBreakdown(summaries, filteredIds); } if (input.includeBreakdowns.includes('size')) { breakdowns.size = calculateSizeDistribution(summaries); } return { overview, breakdowns, scope: { type: input.scope, projectPath: input.projectPath, recentDays: input.scope === 'recent' ? input.recentDays : undefined, totalScanned: filteredIds.length }, // Only include conversation details when requested (to control response size) conversationIds: input.includeConversationDetails ? filteredIds : [], conversations: input.includeConversationDetails ? summaries.map(s => ({ composerId: s.composerId, messageCount: s.messageCount, size: s.conversationSize, files: s.relevantFiles.slice(0, 2), // Top 2 files only hasCodeBlocks: s.codeBlockCount > 0 })) : [] }; } catch (error) { throw new DatabaseError(`Failed to get conversation analytics: ${error instanceof Error ? error.message : 'Unknown error'}`); } finally { reader.close(); } }
- src/tools/analytics-tools.ts:22-28 (schema)Zod schema definition for GetConversationAnalyticsInput, defining parameters like scope, projectPath, recentDays, includeBreakdowns, and includeConversationDetails.export const getConversationAnalyticsSchema = z.object({ scope: z.enum(['all', 'recent', 'project']).optional().default('all'), projectPath: z.string().optional(), recentDays: z.number().min(1).max(365).optional().default(30), includeBreakdowns: z.array(z.enum(['files', 'languages', 'temporal', 'size'])).optional().default(['files', 'languages']), includeConversationDetails: z.boolean().optional().default(false) });
- src/server.ts:235-264 (registration)MCP server tool registration for 'get_conversation_analytics', including description, input schema, and handler wrapper that calls the analytics function and formats the response.server.tool( 'get_conversation_analytics', 'Get comprehensive analytics and statistics about Cursor chats including usage patterns, file activity, programming language distribution, and temporal trends. **BEST PRACTICE: Use projectPath parameter for project-specific analytics** - this analyzes only conversations that worked on files in that project, providing much more relevant insights for understanding coding patterns, file usage, and development activity within a specific codebase. WORKFLOW TIP: Always include "files" and "languages" in breakdowns - these contain conversation IDs in their arrays that you can immediately use with get_conversation tool. Use includeConversationDetails=true when you need the full conversation ID list and basic metadata for follow-up analysis.', { scope: z.enum(['all', 'recent', 'project']).optional().default('all').describe('Analysis scope: all conversations, recent only, or project-specific. Use "project" with projectPath for focused project analysis.'), projectPath: z.string().optional().describe('**HIGHLY RECOMMENDED** Project/codebase name (e.g., "my-app") or full path for project-scoped analysis. When provided, analyzes only conversations that worked on files in that project, giving much more relevant insights about coding patterns and development activity.'), recentDays: z.number().min(1).max(365).optional().default(30).describe('Number of recent days to analyze (1-365)'), includeBreakdowns: z.array(z.enum(['files', 'languages', 'temporal', 'size'])).optional().default(['files', 'languages']).describe('Types of breakdowns to include in the analysis. IMPORTANT: "files" and "languages" breakdowns contain conversation IDs in their arrays - use these for follow-up analysis!'), includeConversationDetails: z.boolean().optional().default(false).describe('Include full conversation ID list and basic metadata (increases response size significantly)'), 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 getConversationAnalytics(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'}` }] }; } } );