Skip to main content
Glama
windalfin

ClickUp MCP Server

by windalfin

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');
      }
    }
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It discloses that the duplicate preserves original properties, which is useful behavioral context. However, it doesn't cover permissions, error conditions, rate limits, or what happens to subtasks/attachments. For a mutation tool with zero annotation coverage, this leaves significant gaps in behavioral understanding.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is appropriately sized with three sentences. The first states the purpose, the second outlines parameter combinations, and the third adds behavioral context. It's front-loaded with the core action, though the parameter combination list could be slightly more concise.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given this is a mutation tool with no annotations and no output schema, the description should do more to explain behavioral aspects like what exactly gets copied (e.g., due dates, assignees), error scenarios, or response format. The parameter guidance is helpful, but overall completeness is adequate with clear gaps for a tool that modifies data.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all parameters thoroughly. The description adds value by explaining valid parameter combinations and preferences (e.g., taskId is 'preferred'), which helps the agent choose between approaches. However, it doesn't add deep semantic context beyond what's in the schema descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Create a copy') and resource ('a task'), specifying it can be in the same or different list. It distinguishes from siblings like create_task by focusing on duplication rather than creation from scratch, though it doesn't explicitly name alternatives.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear guidance on when to use specific parameter combinations (taskId vs taskName approaches) and indicates taskId is 'preferred.' However, it doesn't explicitly state when to use this tool versus alternatives like create_task or move_task, nor does it mention prerequisites or exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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