update_task
Update an existing task by modifying any of its fields including title, notes, project, due date, tags, or completion status using the task ID.
Instructions
Updates one or more fields of an existing task.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Task ID | |
| title | No | ||
| notes | No | ||
| projectId | No | ||
| projectName | No | ||
| isDone | No | ||
| timeEstimateMins | No | New estimate in minutes | |
| dueDateISO | No | New due date in ISO 8601 format | |
| tagIds | No | ||
| tagNames | No |
Implementation Reference
- src/tools/tasks.ts:182-211 (handler)The MCP tool handler for 'update_task'. Registers the tool with a Zod schema for inputs (id, title, notes, projectId, projectName, isDone, timeEstimateMins, dueDateISO, tagIds, tagNames) and an async handler that resolves project/tag name references, then calls SpClient.updateTask to PATCH the task.
// ── Update task ───────────────────────────────────────────────────────── server.tool( "update_task", "Updates one or more fields of an existing task.", { id: nonEmptyString.describe("Task ID"), title: nonEmptyString.optional(), notes: z.string().optional(), projectId: nonEmptyString.optional(), projectName: nonEmptyString.optional(), isDone: z.boolean().optional(), timeEstimateMins: z.number().optional().describe("New estimate in minutes"), dueDateISO: nonEmptyString.optional().describe("New due date in ISO 8601 format"), tagIds: z.array(nonEmptyString).optional(), tagNames: z.array(nonEmptyString).optional(), }, async ({ id, title, notes, projectId, projectName, isDone, timeEstimateMins, dueDateISO, tagIds, tagNames }) => { const resolved = await resolveTaskWriteIds({ projectId, projectName, tagIds, tagNames }); const task = await SpClient.updateTask(id, { title, notes, projectId: resolved.projectId, isDone, timeEstimate: timeEstimateMins ? timeEstimateMins * 60_000 : undefined, dueDate: parseIsoDateToTimestamp(dueDateISO), tagIds: resolved.tagIds, }); return ok(task); } ); - src/tools/tasks.ts:183-197 (schema)Zod input schema for the update_task tool, defining all optional fields: id, title, notes, projectId, projectName, isDone, timeEstimateMins, dueDateISO, tagIds, tagNames.
server.tool( "update_task", "Updates one or more fields of an existing task.", { id: nonEmptyString.describe("Task ID"), title: nonEmptyString.optional(), notes: z.string().optional(), projectId: nonEmptyString.optional(), projectName: nonEmptyString.optional(), isDone: z.boolean().optional(), timeEstimateMins: z.number().optional().describe("New estimate in minutes"), dueDateISO: nonEmptyString.optional().describe("New due date in ISO 8601 format"), tagIds: z.array(nonEmptyString).optional(), tagNames: z.array(nonEmptyString).optional(), }, - src/sp-client.ts:171-179 (schema)UpdateTaskPayload interface defining the shape of the payload sent to the Super Productivity local API: title, notes, projectId, isDone, timeEstimate, dueDate, tagIds.
export interface UpdateTaskPayload { title?: string; notes?: string; projectId?: string; isDone?: boolean; timeEstimate?: number; dueDate?: number; tagIds?: string[]; } - src/sp-client.ts:231-236 (helper)SpClient.updateTask() - the low-level API call that sends a PATCH request to /tasks/{id} with the UpdateTaskPayload body.
updateTask(id: string, payload: UpdateTaskPayload): Promise<Task> { return request(`/tasks/${id}`, TaskSchema, { method: "PATCH", body: JSON.stringify(payload), }); }, - src/tools/tasks.ts:61-284 (registration)registerTaskTools() function that registers all task-related tools (including update_task) on the McpServer instance. Called from src/index.ts line 16.
export function registerTaskTools(server: McpServer) { server.tool( "health_check", "Checks whether the Super Productivity local REST API is reachable and the renderer is ready.", {}, async () => { const health = await SpClient.health(); return ok(health); } ); // ── List all tasks ────────────────────────────────────────────────────── server.tool( "list_tasks", "Returns tasks from Super Productivity with optional filters.", { query: nonEmptyString.optional().describe("Filter by title text (case-insensitive contains)"), projectId: nonEmptyString.optional().describe("Filter by project ID"), projectName: nonEmptyString.optional().describe("Filter by project name"), tagId: nonEmptyString.optional().describe("Filter by tag ID"), tagName: nonEmptyString.optional().describe("Filter by tag name"), includeDone: z.boolean().optional().describe("Include completed tasks"), source: z.enum(["active", "archived", "all"]).optional().describe("Which task source to query"), }, async ({ query, projectId, projectName, tagId, tagName, includeDone, source }) => { const resolved = await resolveTaskFilterIds({ projectId, projectName, tagId, tagName }); const tasks = await SpClient.getTasks({ query, projectId: resolved.projectId, tagId: resolved.tagId, includeDone, source, }); return ok(tasks); } ); server.tool( "search_tasks", "Searches tasks by title text and optional filters.", { query: nonEmptyString.describe("Text to search for in the task title"), projectId: nonEmptyString.optional().describe("Filter by project ID"), projectName: nonEmptyString.optional().describe("Filter by project name"), tagId: nonEmptyString.optional().describe("Filter by tag ID"), tagName: nonEmptyString.optional().describe("Filter by tag name"), includeDone: z.boolean().optional().describe("Include completed tasks"), source: z.enum(["active", "archived", "all"]).optional().describe("Which task source to query"), }, async ({ query, projectId, projectName, tagId, tagName, includeDone, source }) => { const resolved = await resolveTaskFilterIds({ projectId, projectName, tagId, tagName }); const tasks = await SpClient.getTasks({ query, projectId: resolved.projectId, tagId: resolved.tagId, includeDone, source, }); return ok(tasks); } ); // ── Get single task ───────────────────────────────────────────────────── server.tool( "get_task", "Returns details of a specific task by ID.", { id: z.string().describe("Task ID") }, async ({ id }) => { const task = await SpClient.getTask(id); return ok(task); } ); server.tool( "get_status", "Returns the current task and task-count status.", {}, async () => { const status = await SpClient.getStatus(); return ok(status); } ); server.tool( "get_current_task", "Returns the currently active task, if any.", {}, async () => { const task = await SpClient.getCurrentTask(); return ok(task); } ); // ── Create task ───────────────────────────────────────────────────────── server.tool( "create_task", "Creates a new task in Super Productivity. Extra fields are passed through to the local API if supported by your app version.", { title: nonEmptyString.describe("Task title"), notes: z.string().optional().describe("Additional notes / description"), projectId: nonEmptyString.optional().describe("Project ID to assign the task to"), projectName: nonEmptyString.optional().describe("Project name to assign the task to"), tagIds: z.array(nonEmptyString).optional().describe("List of tag IDs"), tagNames: z.array(nonEmptyString).optional().describe("List of tag names"), timeEstimateMins: z.number().optional().describe("Estimated duration in minutes"), dueDateISO: nonEmptyString.optional().describe("Due date in ISO 8601 format (e.g. 2026-04-23)"), }, async ({ title, notes, projectId, projectName, tagIds, tagNames, timeEstimateMins, dueDateISO }) => { const resolved = await resolveTaskWriteIds({ projectId, projectName, tagIds, tagNames }); const task = await SpClient.createTask({ title, notes, projectId: resolved.projectId, tagIds: resolved.tagIds, timeEstimate: timeEstimateMins ? timeEstimateMins * 60_000 : undefined, dueDate: parseIsoDateToTimestamp(dueDateISO), }); return ok(task); } ); // ── Update task ───────────────────────────────────────────────────────── server.tool( "update_task", "Updates one or more fields of an existing task.", { id: nonEmptyString.describe("Task ID"), title: nonEmptyString.optional(), notes: z.string().optional(), projectId: nonEmptyString.optional(), projectName: nonEmptyString.optional(), isDone: z.boolean().optional(), timeEstimateMins: z.number().optional().describe("New estimate in minutes"), dueDateISO: nonEmptyString.optional().describe("New due date in ISO 8601 format"), tagIds: z.array(nonEmptyString).optional(), tagNames: z.array(nonEmptyString).optional(), }, async ({ id, title, notes, projectId, projectName, isDone, timeEstimateMins, dueDateISO, tagIds, tagNames }) => { const resolved = await resolveTaskWriteIds({ projectId, projectName, tagIds, tagNames }); const task = await SpClient.updateTask(id, { title, notes, projectId: resolved.projectId, isDone, timeEstimate: timeEstimateMins ? timeEstimateMins * 60_000 : undefined, dueDate: parseIsoDateToTimestamp(dueDateISO), tagIds: resolved.tagIds, }); return ok(task); } ); // ── Complete task ─────────────────────────────────────────────────────── server.tool( "complete_task", "Marks a task as done.", { id: z.string().describe("Task ID") }, async ({ id }) => { const task = await SpClient.completeTask(id); return ok(task); } ); server.tool( "start_task", "Starts the specified task and makes it the current task.", { id: z.string().describe("Task ID") }, async ({ id }) => { const task = await SpClient.startTask(id); return ok(task); } ); server.tool( "set_current_task", "Sets the current task explicitly, or clears it when id is null.", { id: z.string().nullable().describe("Task ID, or null to clear the current task") }, async ({ id }) => { const task = await SpClient.setCurrentTask(id); return ok(task); } ); server.tool( "stop_current_task", "Stops tracking the current task.", {}, async () => { const result = await SpClient.stopCurrentTask(); return ok(result); } ); server.tool( "archive_task", "Archives a task.", { id: z.string().describe("Task ID") }, async ({ id }) => { const task = await SpClient.archiveTask(id); return ok(task); } ); server.tool( "restore_task", "Restores an archived task.", { id: z.string().describe("Task ID") }, async ({ id }) => { const task = await SpClient.restoreTask(id); return ok(task); } ); // ── Delete task ───────────────────────────────────────────────────────── server.tool( "delete_task", "Permanently deletes a task.", { id: z.string().describe("Task ID") }, async ({ id }) => { await SpClient.deleteTask(id); return ok({ deleted: id }); } ); }