update_todo
Modify todo items by updating fields, searching content, or managing tags to keep tasks organized and current.
Instructions
Update fields on a todo item (supports search and tag ops)
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/tools/update_todo.ts:111-134 (handler)Core handler function that processes the update_todo input, resolves the todo selector, builds the update payload, calls the storage update function, and constructs the tool response.async function handleUpdateTodo( input: UpdateTodoInput ): Promise<CallToolResult> { const selector = input.id !== undefined ? { id: input.id } : { query: input.query }; const outcome = await updateTodoBySelector(toResolveInput(selector), (todo) => buildUpdatePayload(todo, input) ); if (outcome.kind === 'error' || outcome.kind === 'ambiguous') { return outcome.response; } if (outcome.kind === 'no_updates') { return createErrorResponse('E_BAD_REQUEST', 'No fields provided to update'); } return createToolResponse({ ok: true, result: { item: outcome.todo, summary: `Updated todo "${outcome.todo.title}"`, nextActions: ['list_todos', 'complete_todo'], }, }); }
- src/schemas/inputs.ts:200-226 (schema)Defines the input schema for update_todo tool, including selector (by ID or query) and update fields like title, description, status, tags with clear and tagOps support.const updateTodoSelector = buildSelectorSchemas( 'The ID of the todo to update', 'Search text to find a single todo to update' ); const UpdateTodoFieldsSchema = { title: z.string().min(1).max(200).optional().describe('New title'), description: z.string().max(2000).optional().describe('New description'), completed: z.boolean().optional().describe('Completion status'), priority: z .enum(['low', 'normal', 'high']) .optional() .describe('New priority level'), dueDate: IsoDateSchema.optional().describe('New due date (ISO format)'), tags: z.array(TagSchema).max(50).optional().describe('New tags'), clearFields: z .array(z.enum(['description', 'dueDate', 'tags'])) .max(3) .optional() .describe('Fields to clear'), tagOps: TagOpsSchema.optional().describe('Tag modifications to apply'), }; export const UpdateTodoSchema: ZodType<UpdateTodoInput> = z.union([ updateTodoSelector.byId.extend(UpdateTodoFieldsSchema), updateTodoSelector.byQuery.extend(UpdateTodoFieldsSchema), ]);
- src/tools/update_todo.ts:136-157 (registration)Registers the 'update_todo' tool on the MCP server with title, description, input/output schemas, annotations, and the async handler function.export function registerUpdateTodo(server: McpServer): void { server.registerTool( 'update_todo', { title: 'Update Todo', description: 'Update fields on a todo item (supports search and tag ops)', inputSchema: UpdateTodoSchema, outputSchema: DefaultOutputSchema, annotations: { readOnlyHint: false, idempotentHint: true, }, }, async (input) => { try { return await handleUpdateTodo(input); } catch (err) { return createErrorResponse('E_UPDATE_TODO', getErrorMessage(err)); } } ); }
- src/tools/index.ts:9-15 (registration)Imports and calls registerUpdateTodo as part of registering all tools.import { registerUpdateTodo } from './update_todo.js'; export function registerAllTools(server: McpServer): void { registerAddTodo(server); registerAddTodos(server); registerListTodos(server); registerUpdateTodo(server);
- src/lib/storage.ts:170-197 (helper)Helper function that resolves a todo by selector, builds updates via callback, applies the update if changes exist, and returns the outcome used by the handler.export async function updateTodoBySelector( input: ResolveTodoInput, buildUpdates: (todo: Todo) => TodoUpdate | null ): Promise<UpdateTodoOutcome> { return withTodos<UpdateTodoOutcome>((todos) => { const outcome = unwrapResolution(resolveTodoTargetFromTodos(todos, input)); if (outcome.kind !== 'match') { return { todos, result: outcome }; } const updates = buildUpdates(outcome.todo); if (!updates || Object.keys(updates).length === 0) { return { todos, result: { kind: 'no_updates' } }; } const updated = applyUpdateToTodos(todos, outcome.todo.id, updates); if (!updated.result) { return { todos, result: createNotFoundOutcome(outcome.todo.id), }; } return { todos: updated.todos, result: { kind: 'match', todo: updated.result }, }; });