Skip to main content
Glama
guifelix

MCP Todo.txt Integration

batch-operations

Update, delete, or mark tasks as complete in bulk based on priority, context, or project criteria to manage Todo.txt files efficiently.

Instructions

Perform batch operations (update, delete, mark-complete) on tasks matching criteria.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
operationsYes

Implementation Reference

  • The handler function executes batch operations (delete, update, mark-complete) on tasks matching specified criteria. It loads tasks, applies each operation in sequence, saves changes, and returns success message.
    async ({ operations }) => {
        let tasks = await loadTasks();
        for (const operation of operations) {
            if (operation.action === "delete") {
                tasks = tasks.filter(task => {
                    if (!operation.criteria) return true;
                    return !(
                        (operation.criteria.priority && task.priority() === operation.criteria.priority) ||
                        (operation.criteria.context && task.contexts().includes(operation.criteria.context)) ||
                        (operation.criteria.project && task.projects().includes(operation.criteria.project))
                    );
                });
            } else if (operation.action === "update") {
                tasks.forEach(task => {
                    if (operation.criteria) {
                        if (
                            (operation.criteria.priority && task.priority() === operation.criteria.priority) ||
                            (operation.criteria.context && task.contexts().includes(operation.criteria.context)) ||
                            (operation.criteria.project && task.projects().includes(operation.criteria.project))
                        ) {
                            if (operation.updates) {
                                if (operation.updates.priority) {
                                    task.setPriority(operation.updates.priority);
                                }
                                if (operation.updates.addContexts) {
                                    operation.updates.addContexts.forEach((context: string) => task.addContext(context));
                                }
                                if (operation.updates.removeContexts) {
                                    operation.updates.removeContexts.forEach((context: string) => task.removeContext(context));
                                }
                                if (operation.updates.addProjects) {
                                    operation.updates.addProjects.forEach((project: string) => task.addProject(project));
                                }
                                if (operation.updates.removeProjects) {
                                    operation.updates.removeProjects.forEach((project: string) => task.removeProject(project));
                                }
                                if (operation.updates.extensions) {
                                    Object.entries(operation.updates.extensions).forEach(([key, value]) => task.setExtension(key as string, value as string));
                                }
                            }
                        }
                    }
                });
            } else if (operation.action === "mark-complete") {
                tasks.forEach(task => {
                    if (operation.criteria) {
                        if (
                            (operation.criteria.priority && task.priority() === operation.criteria.priority) ||
                            (operation.criteria.context && task.contexts().includes(operation.criteria.context)) ||
                            (operation.criteria.project && task.projects().includes(operation.criteria.project))
                        ) {
                            task.setCompleted(new Date().toISOString().split("T")[0]);
                        }
                    }
                });
            }
        }
        await saveTasks(tasks);
        return {
            content: [
                { type: "text", text: "Batch operations completed successfully." },
            ],
        };
    }
  • Zod schema for the tool's input parameters, defining an array of operations each with action type, optional criteria for matching tasks, and optional updates for 'update' actions.
    {
        operations: z.array(z.object({
            action: z.enum(["update", "delete", "mark-complete"]),
            criteria: z.object({
                priority: z.string().optional(),
                context: z.string().optional(),
                project: z.string().optional(),
            }).optional(),
            updates: z.object({
                priority: z.string().optional(),
                addContexts: z.array(z.string()).optional(),
                removeContexts: z.array(z.string()).optional(),
                addProjects: z.array(z.string()).optional(),
                removeProjects: z.array(z.string()).optional(),
                extensions: z.record(z.string(), z.string()).optional(),
            }).optional(),
        })),
    },
  • src/tools.ts:281-366 (registration)
    MCP server tool registration for 'batch-operations', including name, description, input schema, and handler function.
    server.tool(
        "batch-operations",
        "Perform batch operations (update, delete, mark-complete) on tasks matching criteria.",
        {
            operations: z.array(z.object({
                action: z.enum(["update", "delete", "mark-complete"]),
                criteria: z.object({
                    priority: z.string().optional(),
                    context: z.string().optional(),
                    project: z.string().optional(),
                }).optional(),
                updates: z.object({
                    priority: z.string().optional(),
                    addContexts: z.array(z.string()).optional(),
                    removeContexts: z.array(z.string()).optional(),
                    addProjects: z.array(z.string()).optional(),
                    removeProjects: z.array(z.string()).optional(),
                    extensions: z.record(z.string(), z.string()).optional(),
                }).optional(),
            })),
        },
        async ({ operations }) => {
            let tasks = await loadTasks();
            for (const operation of operations) {
                if (operation.action === "delete") {
                    tasks = tasks.filter(task => {
                        if (!operation.criteria) return true;
                        return !(
                            (operation.criteria.priority && task.priority() === operation.criteria.priority) ||
                            (operation.criteria.context && task.contexts().includes(operation.criteria.context)) ||
                            (operation.criteria.project && task.projects().includes(operation.criteria.project))
                        );
                    });
                } else if (operation.action === "update") {
                    tasks.forEach(task => {
                        if (operation.criteria) {
                            if (
                                (operation.criteria.priority && task.priority() === operation.criteria.priority) ||
                                (operation.criteria.context && task.contexts().includes(operation.criteria.context)) ||
                                (operation.criteria.project && task.projects().includes(operation.criteria.project))
                            ) {
                                if (operation.updates) {
                                    if (operation.updates.priority) {
                                        task.setPriority(operation.updates.priority);
                                    }
                                    if (operation.updates.addContexts) {
                                        operation.updates.addContexts.forEach((context: string) => task.addContext(context));
                                    }
                                    if (operation.updates.removeContexts) {
                                        operation.updates.removeContexts.forEach((context: string) => task.removeContext(context));
                                    }
                                    if (operation.updates.addProjects) {
                                        operation.updates.addProjects.forEach((project: string) => task.addProject(project));
                                    }
                                    if (operation.updates.removeProjects) {
                                        operation.updates.removeProjects.forEach((project: string) => task.removeProject(project));
                                    }
                                    if (operation.updates.extensions) {
                                        Object.entries(operation.updates.extensions).forEach(([key, value]) => task.setExtension(key as string, value as string));
                                    }
                                }
                            }
                        }
                    });
                } else if (operation.action === "mark-complete") {
                    tasks.forEach(task => {
                        if (operation.criteria) {
                            if (
                                (operation.criteria.priority && task.priority() === operation.criteria.priority) ||
                                (operation.criteria.context && task.contexts().includes(operation.criteria.context)) ||
                                (operation.criteria.project && task.projects().includes(operation.criteria.project))
                            ) {
                                task.setCompleted(new Date().toISOString().split("T")[0]);
                            }
                        }
                    });
                }
            }
            await saveTasks(tasks);
            return {
                content: [
                    { type: "text", text: "Batch operations completed successfully." },
                ],
            };
        }
    );

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/guifelix/mcp-server-todotxt'

If you have feedback or need assistance with the MCP directory API, please join our Discord server