edit_item
Modify tasks or projects in OmniFocus by updating names, notes, due dates, tags, status, and more. Supports editing via ID or name for flexibility.
Instructions
Edit a task or project in OmniFocus
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| addTags | No | Tags to add to the task | |
| id | No | The ID of the task or project to edit | |
| itemType | Yes | Type of item to edit ('task' or 'project') | |
| name | No | The name of the task or project to edit (as fallback if ID not provided) | |
| newDeferDate | No | New defer date in ISO format (YYYY-MM-DD or full ISO date); set to empty string to clear | |
| newDueDate | No | New due date in ISO format (YYYY-MM-DD or full ISO date); set to empty string to clear | |
| newEstimatedMinutes | No | New estimated minutes | |
| newFlagged | No | Set flagged status (set to false for no flag, true for flag) | |
| newFolderName | No | New folder to move the project to | |
| newName | No | New name for the item | |
| newNote | No | New note for the item | |
| newProjectStatus | No | New status for projects | |
| newSequential | No | Whether the project should be sequential | |
| newStatus | No | New status for tasks (incomplete, completed, dropped) | |
| removeTags | No | Tags to remove from the task | |
| replaceTags | No | Tags to replace all existing tags with |
Implementation Reference
- src/tools/definitions/editItem.ts:30-96 (handler)MCP tool handler function that validates input, calls the primitive editItem function, handles success/error responses.export async function handler(args: z.infer<typeof schema>, extra: RequestHandlerExtra) { try { // Validate that either id or name is provided if (!args.id && !args.name) { return { content: [{ type: "text" as const, text: "Either id or name must be provided to edit an item." }], isError: true }; } // Call the editItem function const result = await editItem(args as EditItemParams); if (result.success) { // Item was edited successfully const itemTypeLabel = args.itemType === 'task' ? 'Task' : 'Project'; let changedText = ''; if (result.changedProperties) { changedText = ` (${result.changedProperties})`; } return { content: [{ type: "text" as const, text: `✅ ${itemTypeLabel} "${result.name}" updated successfully${changedText}.` }] }; } else { // Item editing failed let errorMsg = `Failed to update ${args.itemType}`; if (result.error) { if (result.error.includes("Item not found")) { errorMsg = `${args.itemType.charAt(0).toUpperCase() + args.itemType.slice(1)} not found`; if (args.id) errorMsg += ` with ID "${args.id}"`; if (args.name) errorMsg += `${args.id ? ' or' : ' with'} name "${args.name}"`; errorMsg += '.'; } else { errorMsg += `: ${result.error}`; } } return { content: [{ type: "text" as const, text: errorMsg }], isError: true }; } } catch (err: unknown) { const error = err as Error; console.error(`Tool execution error: ${error.message}`); return { content: [{ type: "text" as const, text: `Error updating ${args.itemType}: ${error.message}` }], isError: true }; } }
- Zod schema defining the input parameters and structure for the edit_item tool.export const schema = z.object({ id: z.string().optional().describe("The ID of the task or project to edit"), name: z.string().optional().describe("The name of the task or project to edit (as fallback if ID not provided)"), itemType: z.enum(['task', 'project']).describe("Type of item to edit ('task' or 'project')"), // Common editable fields newName: z.string().optional().describe("New name for the item"), newNote: z.string().optional().describe("New note for the item"), newDueDate: z.string().optional().describe("New due date in ISO format (YYYY-MM-DD or full ISO date); set to empty string to clear"), newDeferDate: z.string().optional().describe("New defer date in ISO format (YYYY-MM-DD or full ISO date); set to empty string to clear"), newFlagged: z.boolean().optional().describe("Set flagged status (set to false for no flag, true for flag)"), newEstimatedMinutes: z.number().optional().describe("New estimated minutes"), // Task-specific fields newStatus: z.enum(['incomplete', 'completed', 'dropped']).optional().describe("New status for tasks (incomplete, completed, dropped)"), addTags: z.array(z.string()).optional().describe("Tags to add to the task"), removeTags: z.array(z.string()).optional().describe("Tags to remove from the task"), replaceTags: z.array(z.string()).optional().describe("Tags to replace all existing tags with"), // Project-specific fields newSequential: z.boolean().optional().describe("Whether the project should be sequential"), newFolderName: z.string().optional().describe("New folder to move the project to"), newProjectStatus: z.enum(['active', 'completed', 'dropped', 'onHold']).optional().describe("New status for projects") });
- src/server.ts:53-58 (registration)Registration of the 'edit_item' tool with the MCP server using its schema and handler.server.tool( "edit_item", "Edit a task or project in OmniFocus", editItemTool.schema.shape, editItemTool.handler );
- src/tools/primitives/editItem.ts:426-507 (handler)Core primitive function that generates AppleScript and executes it via osascript to perform the actual editing in OmniFocus.export async function editItem(params: EditItemParams): Promise<{ success: boolean, id?: string, name?: string, changedProperties?: string, error?: string }> { let tempFile: string | undefined; try { // Generate AppleScript const script = generateAppleScript(params); console.error("Executing AppleScript for editing (V2)..."); console.error(`Item type: ${params.itemType}, ID: ${params.id || 'not provided'}, Name: ${params.name || 'not provided'}`); // Log a preview of the script for debugging (first few lines) const scriptPreview = script.split('\n').slice(0, 10).join('\n') + '\n...'; console.error("AppleScript preview:\n", scriptPreview); // Write script to temporary file to avoid shell escaping issues tempFile = join(tmpdir(), `edit_omnifocus_${Date.now()}.applescript`); writeFileSync(tempFile, script); // Execute AppleScript from file const { stdout, stderr } = await execAsync(`osascript ${tempFile}`); // Clean up temp file try { unlinkSync(tempFile); } catch (cleanupError) { console.error("Failed to clean up temp file:", cleanupError); } if (stderr) { console.error("AppleScript stderr:", stderr); } console.error("AppleScript stdout:", stdout); // Parse the result try { const result = JSON.parse(stdout); // Return the result return { success: result.success, id: result.id, name: result.name, changedProperties: result.changedProperties, error: result.error }; } catch (parseError) { console.error("Error parsing AppleScript result:", parseError); return { success: false, error: `Failed to parse result: ${stdout}` }; } } catch (error: any) { // Clean up temp file if it exists if (tempFile) { try { unlinkSync(tempFile); } catch (cleanupError) { // Ignore cleanup errors } } console.error("Error in editItem execution:", error); // Include more detailed error information if (error.message && error.message.includes('syntax error')) { console.error("This appears to be an AppleScript syntax error. Review the script generation logic."); } return { success: false, error: error?.message || "Unknown error in editItem" }; } }
- TypeScript interface defining parameters for the editItem primitive function.export interface EditItemParams { id?: string; // ID of the task or project to edit name?: string; // Name of the task or project to edit (as fallback if ID not provided) itemType: 'task' | 'project'; // Type of item to edit // Common editable fields newName?: string; // New name for the item newNote?: string; // New note for the item newDueDate?: string; // New due date in ISO format (empty string to clear) newDeferDate?: string; // New defer date in ISO format (empty string to clear) newFlagged?: boolean; // New flagged status (false to remove flag, true to add flag) newEstimatedMinutes?: number; // New estimated minutes // Task-specific fields newStatus?: TaskStatus; // New status for tasks (incomplete, completed, dropped) addTags?: string[]; // Tags to add to the task removeTags?: string[]; // Tags to remove from the task replaceTags?: string[]; // Tags to replace all existing tags with // Project-specific fields newSequential?: boolean; // Whether the project should be sequential newFolderName?: string; // New folder to move the project to newProjectStatus?: ProjectStatus; // New status for projects }