Skip to main content
Glama

duplicate_task

Copy a ClickUp task to the same or different list while preserving all original properties. Use task ID or name with optional destination list specification.

Instructions

Create a copy of a task in the same or different list. Valid parameter combinations:

  1. Use taskId + optional (listId or listName) - preferred

  2. Use taskName + sourceListName + optional (listId or listName)

The duplicate preserves the original task's properties.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
taskIdNoID of task to duplicate (preferred). Use this instead of taskName if you have it.
taskNameNoName of task to duplicate. When using this, you MUST provide sourceListName.
sourceListNameNoREQUIRED with taskName: List containing the original task.
listIdNoID of list for the duplicate (optional). Defaults to same list as original.
listNameNoName of list for the duplicate. Only use if you don't have listId.

Implementation Reference

  • src/server.ts:67-93 (registration)
    Tool registration in ListToolsRequestSchema handler. duplicateTaskTool is included in the tools list at line 76.
    server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ workspaceHierarchyTool, createTaskTool, getTaskTool, getTasksTool, updateTaskTool, moveTaskTool, duplicateTaskTool, deleteTaskTool, createBulkTasksTool, updateBulkTasksTool, moveBulkTasksTool, deleteBulkTasksTool, createListTool, createListInFolderTool, getListTool, updateListTool, deleteListTool, createFolderTool, getFolderTool, updateFolderTool, deleteFolderTool ] }; });
  • src/server.ts:108-109 (registration)
    Dispatch registration in CallToolRequestSchema switch statement.
    case "duplicate_task": return handleDuplicateTask(params);
  • Input schema definition for the duplicate_task tool.
    inputSchema: { type: "object", properties: { taskId: { type: "string", description: "ID of task to duplicate (preferred). Use this instead of taskName if you have it." }, taskName: { type: "string", description: "Name of task to duplicate. When using this, you MUST provide sourceListName." }, sourceListName: { type: "string", description: "REQUIRED with taskName: List containing the original task." }, listId: { type: "string", description: "ID of list for the duplicate (optional). Defaults to same list as original." }, listName: { type: "string", description: "Name of list for the duplicate. Only use if you don't have listId." } }, required: []
  • Primary handler function for duplicate_task, called from server.ts CallTool dispatch. Resolves task and list IDs, invokes taskService.duplicateTask, formats MCP response.
    export async function handleDuplicateTask(parameters: any) { const { taskId, taskName, sourceListName, listId, listName } = parameters; let targetTaskId = taskId; let sourceListId: string | undefined; // If sourceListName is provided, find the source list ID if (sourceListName) { const hierarchy = await workspaceService.getWorkspaceHierarchy(); const listInfo = workspaceService.findIDByNameInHierarchy(hierarchy, sourceListName, 'list'); if (!listInfo) { throw new Error(`Source list "${sourceListName}" not found`); } sourceListId = listInfo.id; } // If no taskId but taskName is provided, look up the task ID if (!targetTaskId && taskName) { // Find the task in the source list if specified, otherwise search all tasks if (sourceListId) { const tasks = await taskService.getTasks(sourceListId); const foundTask = tasks.find(t => t.name.toLowerCase() === taskName.toLowerCase()); if (!foundTask) { throw new Error(`Task "${taskName}" not found in list "${sourceListName}"`); } targetTaskId = foundTask.id; } else { // Without a source list, we need to search more broadly throw new Error("When using taskName, sourceListName must be provided to find the task"); } } if (!targetTaskId) { throw new Error("Either taskId or taskName (with sourceListName) must be provided"); } let targetListId = listId; // If no listId but listName is provided, look up the list ID if (!targetListId && listName) { const hierarchy = await workspaceService.getWorkspaceHierarchy(); const listInfo = workspaceService.findIDByNameInHierarchy(hierarchy, listName, 'list'); if (!listInfo) { throw new Error(`Target list "${listName}" not found`); } targetListId = listInfo.id; } // Duplicate the task const task = await taskService.duplicateTask(targetTaskId, targetListId); // Format response return { content: [{ type: "text", text: JSON.stringify({ id: task.id, name: task.name, url: task.url, duplicated: true, due_date: task.due_date ? formatDueDate(Number(task.due_date)) : undefined, list: task.list.name, space: task.space.name, folder: task.folder?.name }, null, 2) }] }; }
  • TaskService.duplicateTask helper method: fetches original task, creates copy with '(Copy)' suffix in target list (or same), handles priority mapping, calls ClickUp API.
    async duplicateTask(taskId: string, listId?: string): Promise<ClickUpTask> { this.logOperation('duplicateTask', { taskId, listId }); try { // First, get the original task const originalTask = await this.getTask(taskId); // Priority mapping: convert string priority to numeric value if needed let priorityValue = null; if (originalTask.priority) { // If priority.id exists and is numeric, use that if (originalTask.priority.id) { priorityValue = parseInt(originalTask.priority.id); // Ensure it's in the valid range 1-4 if (isNaN(priorityValue) || priorityValue < 1 || priorityValue > 4) { priorityValue = null; } } } // Prepare data for the new task const newTaskData: CreateTaskData = { name: `${originalTask.name} (Copy)`, description: originalTask.description, status: originalTask.status?.status, priority: priorityValue, due_date: originalTask.due_date ? new Date(originalTask.due_date).getTime() : undefined, assignees: originalTask.assignees?.map(a => a.id) || [] }; // Create the new task in the specified list or original list const targetListId = listId || originalTask.list.id; return await this.createTask(targetListId, newTaskData); } catch (error) { throw this.handleError(error, 'Failed to duplicate task'); } }

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/windalfin/clickup-mcp-server'

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