get_conversation_analytics
Analyze Cursor chat history to gain insights into coding patterns, file activity, and programming language usage. Use projectPath for project-specific analytics, and include file and language breakdowns for detailed follow-up analysis.
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 |
|---|---|---|---|
| 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 |
| 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) | |
| scope | No | Analysis scope: all conversations, recent only, or project-specific. Use "project" with projectPath for focused project analysis. | all |
Implementation Reference
- src/tools/analytics-tools.ts:44-125 (handler)The main handler function that executes the core logic of the get_conversation_analytics tool: connects to the database, applies filters based on input scope/project/recent, retrieves conversation summaries, calculates overview statistics and optional breakdowns (files, languages, temporal, size), and returns structured analytics data.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 defining the input parameters for getConversationAnalytics, including 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 (with added outputMode), and handler wrapper that calls the core getConversationAnalytics 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'}` }] }; } } );