todoist_label_stats
Analyze label usage statistics in Todoist to identify patterns and optimize task organization.
Instructions
Get usage statistics for all labels in Todoist
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/handlers/label-handlers.ts:207-289 (handler)Core handler function that fetches all labels and tasks from Todoist, computes detailed usage statistics for each label (total tasks, completed count, completion percentage, most recent usage, color), sorts by total usage descending, applies caching, and returns a formatted multi-line report.export async function handleGetLabelStats( todoistClient: TodoistApi ): Promise<string> { const cacheKey = "labels:stats"; const cached = labelStatsCache.get(cacheKey); let sortedStats: LabelStatistics[]; if (cached) { sortedStats = cached; } else { try { const [labelsResponse, tasksResponse] = await Promise.all([ todoistClient.getLabels(), todoistClient.getTasks(), ]); const labels = extractArrayFromResponse(labelsResponse) as TodoistLabel[]; const tasks = extractArrayFromResponse(tasksResponse) as Array<{ labels?: string[]; isCompleted?: boolean; createdAt?: string; }>; const stats = labels.map((label) => { const tasksWithLabel = tasks.filter((task) => task.labels?.includes(label.name) ); const completedTasks = tasksWithLabel.filter( (task) => task.isCompleted ).length; const mostRecentTask = tasksWithLabel .filter((task) => task.createdAt) .sort((a, b) => { const dateA = new Date(a.createdAt!).getTime(); const dateB = new Date(b.createdAt!).getTime(); return dateB - dateA; })[0]; return { label: label.name, totalTasks: tasksWithLabel.length, completedTasks, completionRate: tasksWithLabel.length > 0 ? Math.round((completedTasks / tasksWithLabel.length) * 100) : 0, color: label.color, mostRecentUse: mostRecentTask?.createdAt || null, }; }); sortedStats = stats.sort((a, b) => b.totalTasks - a.totalTasks); labelStatsCache.set(cacheKey, sortedStats); } catch (error) { throw new TodoistAPIError( "Failed to fetch label statistics", error instanceof Error ? error : undefined ); } } if (sortedStats.length === 0) { return "No labels found to generate statistics."; } const statsReport = sortedStats .map((stat) => { const lastUsed = stat.mostRecentUse ? new Date(stat.mostRecentUse).toLocaleDateString() : "Never"; return `• ${stat.label} (${stat.color || "default"}) - Total tasks: ${stat.totalTasks} - Completed: ${stat.completedTasks} (${stat.completionRate}%) - Last used: ${lastUsed}`; }) .join("\n\n"); return `Label Usage Statistics:\n\n${statsReport}`; }
- src/tools/label-tools.ts:95-102 (schema)MCP Tool definition including name, description, and input schema (empty object as no input parameters are required).export const GET_LABEL_STATS_TOOL: Tool = { name: "todoist_label_stats", description: "Get usage statistics for all labels in Todoist", inputSchema: { type: "object", properties: {}, }, };
- src/index.ts:282-287 (registration)Dispatcher registration in the main CallToolRequest handler: validates input with isGetLabelStatsArgs and invokes the handleGetLabelStats function.case "todoist_label_stats": if (!isGetLabelStatsArgs(args)) { throw new Error("Invalid arguments for todoist_label_stats"); } result = await handleGetLabelStats(apiClient); break;
- src/type-guards.ts:258-262 (schema)Type guard function for input validation, confirming args is a non-null object (matches empty inputSchema).export function isGetLabelStatsArgs( args: unknown ): args is Record<string, never> { return typeof args === "object" && args !== null; }
- src/tools/label-tools.ts:104-110 (registration)Includes the tool in the LABEL_TOOLS array, which is aggregated into ALL_TOOLS for server tool listing.export const LABEL_TOOLS = [ GET_LABELS_TOOL, CREATE_LABEL_TOOL, UPDATE_LABEL_TOOL, DELETE_LABEL_TOOL, GET_LABEL_STATS_TOOL, ];