toggl_project_summary
Retrieve total hours spent per project within specified date ranges to analyze time allocation and project progress.
Instructions
Get total hours per project for a date range
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| end_date | No | End date (YYYY-MM-DD format) | |
| period | No | Predefined period | |
| start_date | No | Start date (YYYY-MM-DD format) | |
| workspace_id | No | Filter by workspace ID |
Implementation Reference
- src/index.ts:617-659 (handler)Main handler for the 'toggl_project_summary' tool. Fetches time entries based on period or date range, filters by workspace, hydrates with project/workspace names, groups by project, generates summaries for each project, sorts by total time descending, and returns structured JSON.case 'toggl_project_summary': { await ensureCache(); let entries: TimeEntry[]; if (args?.period) { const range = getDateRange(args.period as any); entries = await api.getTimeEntriesForDateRange(range.start, range.end); } else if (args?.start_date && args?.end_date) { const start = new Date(args.start_date as string); const end = new Date(args.end_date as string); entries = await api.getTimeEntriesForDateRange(start, end); } else { // Default to current week entries = await api.getTimeEntriesForWeek(0); } if (args?.workspace_id) { entries = entries.filter(e => e.workspace_id === args.workspace_id); } const hydrated = await cache.hydrateTimeEntries(entries); const byProject = groupEntriesByProject(hydrated); const summaries: any[] = []; byProject.forEach((projectEntries, projectName) => { summaries.push(generateProjectSummary(projectName, projectEntries)); }); // Sort by total hours descending summaries.sort((a, b) => b.total_seconds - a.total_seconds); return { content: [{ type: 'text', text: JSON.stringify({ project_count: summaries.length, total_hours: secondsToHours(summaries.reduce((t, s) => t + s.total_seconds, 0)), projects: summaries }, null, 2) }] }; }
- src/index.ts:265-290 (schema)Input schema definition for the 'toggl_project_summary' tool, specifying parameters for period, date range, and workspace filtering.{ name: 'toggl_project_summary', description: 'Get total hours per project for a date range', inputSchema: { type: 'object', properties: { period: { type: 'string', enum: ['week', 'lastWeek', 'month', 'lastMonth'], description: 'Predefined period' }, start_date: { type: 'string', description: 'Start date (YYYY-MM-DD format)' }, end_date: { type: 'string', description: 'End date (YYYY-MM-DD format)' }, workspace_id: { type: 'number', description: 'Filter by workspace ID' } } }, },
- src/index.ts:137-290 (registration)The tool is registered by including its definition in the 'tools' array returned by ListToolsRequestSchema handler.const tools: Tool[] = [ // Health/authentication { name: 'toggl_check_auth', description: 'Verify Toggl API connectivity and authentication is valid', inputSchema: { type: 'object', properties: {}, required: [] }, }, // Time tracking tools { name: 'toggl_get_time_entries', description: 'Get time entries with optional date range filters. Returns hydrated entries with project/workspace names.', inputSchema: { type: 'object', properties: { period: { type: 'string', enum: ['today', 'yesterday', 'week', 'lastWeek', 'month', 'lastMonth'], description: 'Predefined period to fetch entries for' }, start_date: { type: 'string', description: 'Start date (YYYY-MM-DD format)' }, end_date: { type: 'string', description: 'End date (YYYY-MM-DD format)' }, workspace_id: { type: 'number', description: 'Filter by workspace ID' }, project_id: { type: 'number', description: 'Filter by project ID' } } }, }, { name: 'toggl_get_current_entry', description: 'Get the currently running time entry, if any', inputSchema: { type: 'object', properties: {}, required: [] }, }, { name: 'toggl_start_timer', description: 'Start a new time entry timer', inputSchema: { type: 'object', properties: { description: { type: 'string', description: 'Description of the time entry' }, workspace_id: { type: 'number', description: 'Workspace ID (uses default if not provided)' }, project_id: { type: 'number', description: 'Project ID (optional)' }, task_id: { type: 'number', description: 'Task ID (optional)' }, tags: { type: 'array', items: { type: 'string' }, description: 'Tags for the entry' } } }, }, { name: 'toggl_stop_timer', description: 'Stop the currently running timer', inputSchema: { type: 'object', properties: {}, required: [] }, }, // Reporting tools { name: 'toggl_daily_report', description: 'Generate a daily report with hours by project and workspace', inputSchema: { type: 'object', properties: { date: { type: 'string', description: 'Date for report (YYYY-MM-DD format, defaults to today)' }, format: { type: 'string', enum: ['json', 'text'], description: 'Output format (default: json)' } } }, }, { name: 'toggl_weekly_report', description: 'Generate a weekly report with daily breakdown and project summaries', inputSchema: { type: 'object', properties: { week_offset: { type: 'number', description: 'Week offset from current week (0 = this week, -1 = last week)' }, format: { type: 'string', enum: ['json', 'text'], description: 'Output format (default: json)' } } }, }, { name: 'toggl_project_summary', description: 'Get total hours per project for a date range', inputSchema: { type: 'object', properties: { period: { type: 'string', enum: ['week', 'lastWeek', 'month', 'lastMonth'], description: 'Predefined period' }, start_date: { type: 'string', description: 'Start date (YYYY-MM-DD format)' }, end_date: { type: 'string', description: 'End date (YYYY-MM-DD format)' }, workspace_id: { type: 'number', description: 'Filter by workspace ID' } } }, },
- src/utils.ts:112-124 (helper)Helper function to group hydrated time entries by project name, used in the project summary generation.export function groupEntriesByProject(entries: HydratedTimeEntry[]): Map<string, HydratedTimeEntry[]> { const grouped = new Map<string, HydratedTimeEntry[]>(); entries.forEach(entry => { const key = entry.project_name || 'No Project'; if (!grouped.has(key)) { grouped.set(key, []); } grouped.get(key)!.push(entry); }); return grouped; }
- src/utils.ts:175-195 (helper)Helper function that generates a ProjectSummary object for a given project name and its time entries, calculating totals, billable time, and metadata.export function generateProjectSummary( projectName: string, entries: HydratedTimeEntry[] ): ProjectSummary { const totalSeconds = calculateTotalDuration(entries); const billableSeconds = entries .filter(e => e.billable) .reduce((total, e) => total + (e.duration < 0 ? 0 : e.duration), 0); return { project_id: entries[0]?.project_id, project_name: projectName, client_name: entries[0]?.client_name, workspace_name: entries[0]?.workspace_name || 'Unknown', total_hours: secondsToHours(totalSeconds), total_seconds: totalSeconds, billable_hours: secondsToHours(billableSeconds), billable_seconds: billableSeconds, entry_count: entries.length }; }