todoist_tasks_bulk_delete
Delete multiple Todoist tasks simultaneously using filters like project, priority, due date, or content to remove outdated or unwanted items in bulk.
Instructions
Delete multiple tasks at once based on search criteria. Use with caution - this will permanently delete matching tasks.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| project_id | No | Delete tasks from this project ID (optional) | |
| priority | No | Delete tasks with this priority level 1 (highest) to 4 (lowest) (optional) | |
| due_before | No | Delete tasks due before this date (YYYY-MM-DD) (optional) | |
| due_after | No | Delete tasks due after this date (YYYY-MM-DD) (optional) | |
| content_contains | No | Delete tasks containing this text in content (optional) |
Implementation Reference
- src/handlers/task-handlers.ts:799-855 (handler)The primary handler function that fetches all tasks, filters them based on the provided criteria, deletes the matching tasks using the Todoist API, handles individual task deletion errors, supports dry-run mode, and returns a formatted summary of successes and failures.export async function handleBulkDeleteTasks( todoistClient: TodoistApi, args: BulkTaskFilterArgs ): Promise<string> { try { // Clear cache since we're deleting taskCache.clear(); validateBulkSearchCriteria(args.search_criteria); const result = await todoistClient.getTasks(); const allTasks = extractArrayFromResponse<TodoistTask>(result); const matchingTasks = filterTasksByCriteria(allTasks, args.search_criteria); if (matchingTasks.length === 0) { return "No tasks found matching the search criteria."; } const deletedTasks: string[] = []; const errors: string[] = []; for (const task of matchingTasks) { try { await todoistClient.deleteTask(task.id); deletedTasks.push(task.content); } catch (error) { errors.push( `Failed to delete task "${task.content}": ${(error as Error).message}` ); } } const successCount = deletedTasks.length; const errorCount = errors.length; // Check if we're in dry-run mode const isDryRun = process.env.DRYRUN === "true"; const prefix = isDryRun ? "[DRY-RUN] " : ""; let response = `${prefix}Bulk delete completed: ${successCount} deleted, ${errorCount} failed.\n\n`; if (successCount > 0) { response += "Deleted tasks:\n"; response += deletedTasks.map((content) => `- ${content}`).join("\n"); response += "\n\n"; } if (errorCount > 0) { response += "Errors:\n"; response += errors.join("\n"); } return response.trim(); } catch (error) { ErrorHandler.handleAPIError("bulk delete tasks", error); } }
- src/tools/task-tools.ts:364-397 (schema)Defines the Tool object for 'todoist_tasks_bulk_delete' including name, description, and input schema specifying optional filter parameters like project_id, priority, due dates, and content_contains.export const BULK_DELETE_TASKS_TOOL: Tool = { name: "todoist_tasks_bulk_delete", description: "Delete multiple tasks at once based on search criteria. Use with caution - this will permanently delete matching tasks.", inputSchema: { type: "object", properties: { project_id: { type: "string", description: "Delete tasks from this project ID (optional)", }, priority: { type: "number", description: "Delete tasks with this priority level 1 (highest) to 4 (lowest) (optional)", enum: [1, 2, 3, 4], }, due_before: { type: "string", description: "Delete tasks due before this date (YYYY-MM-DD) (optional)", }, due_after: { type: "string", description: "Delete tasks due after this date (YYYY-MM-DD) (optional)", }, content_contains: { type: "string", description: "Delete tasks containing this text in content (optional)", }, }, required: [], }, };
- src/index.ts:226-231 (registration)Registers the tool in the main server request handler switch statement: validates arguments using isBulkTaskFilterArgs type guard and invokes the handleBulkDeleteTasks function.case "todoist_tasks_bulk_delete": if (!isBulkTaskFilterArgs(args)) { throw new Error("Invalid arguments for todoist_tasks_bulk_delete"); } result = await handleBulkDeleteTasks(apiClient, args); break;
- Helper function used by bulk handlers to filter tasks based on project, priority, content_contains, and due date criteria. Handles edge cases like empty content search and date comparisons.function filterTasksByCriteria( tasks: TodoistTask[], criteria: BulkTaskFilterArgs["search_criteria"] ): TodoistTask[] { return tasks.filter((task) => { if (criteria.project_id && task.projectId !== criteria.project_id) return false; const apiPriorityFilter = toApiPriority(criteria.priority); if (apiPriorityFilter !== undefined && task.priority !== apiPriorityFilter) return false; // Fix for issue #34: Handle empty string in content_contains if (criteria.content_contains !== undefined) { // Treat empty or whitespace-only strings as "no match" const searchTerm = criteria.content_contains.trim(); if (searchTerm === "") { // Empty search should match nothing, not everything return false; } if (!task.content.toLowerCase().includes(searchTerm.toLowerCase())) { return false; } } if (criteria.due_before || criteria.due_after) { const taskDate = getDueDateOnly(task.due); if (!taskDate) { return false; } const isBeforeThreshold = !criteria.due_before || taskDate < criteria.due_before; const isAfterThreshold = !criteria.due_after || taskDate > criteria.due_after; if (!isBeforeThreshold || !isAfterThreshold) { return false; } } return true; }); }
- src/tools/task-tools.ts:436-446 (registration)Adds BULK_DELETE_TASKS_TOOL to the TASK_TOOLS export array, which is imported into the main ALL_TOOLS list provided by the MCP server for tool discovery.export const TASK_TOOLS = [ CREATE_TASK_TOOL, GET_TASKS_TOOL, UPDATE_TASK_TOOL, DELETE_TASK_TOOL, COMPLETE_TASK_TOOL, BULK_CREATE_TASKS_TOOL, BULK_UPDATE_TASKS_TOOL, BULK_DELETE_TASKS_TOOL, BULK_COMPLETE_TASKS_TOOL, ];