Skip to main content
Glama

move_bulk_tasks

Move multiple tasks to a different list in ClickUp. Use task IDs or task names with list names. Note that task statuses may reset if the destination list has different status options.

Instructions

Move multiple tasks to a different list efficiently. For each task, you MUST provide either:

  1. taskId alone (preferred)

  2. taskName + listName

WARNING: Task statuses may reset if target list has different status options.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
tasksYesArray of tasks to move
targetListIdNoID of destination list (preferred). Use instead of targetListName if available.
targetListNameNoName of destination list. Only use if you don't have targetListId.

Implementation Reference

  • MCP tool handler for 'move_bulk_tasks'. Validates input, resolves task IDs and target list ID from names if provided, moves each task using taskService.moveTask in a loop, tracks success/failure, returns summary.
    export async function handleMoveBulkTasks(parameters: any) { const { tasks, targetListId, targetListName } = parameters; if (!tasks || !Array.isArray(tasks) || tasks.length === 0) { throw new Error('You must provide a non-empty array of tasks to move'); } let finalTargetListId = targetListId; // If no targetListId but targetListName is provided, look up the list ID if (!finalTargetListId && targetListName) { const listInfo = await findListIDByName(workspaceService, targetListName); if (!listInfo) { throw new Error(`Target list "${targetListName}" not found`); } finalTargetListId = listInfo.id; } if (!finalTargetListId) { throw new Error("Either targetListId or targetListName must be provided"); } const results = { total: tasks.length, successful: 0, failed: 0, failures: [] as any[] }; for (const task of tasks) { try { let taskId = task.taskId; if (!taskId && task.taskName) { if (!task.listName) { throw new Error(`List name is required when using task name for task "${task.taskName}"`); } const listInfo = await findListIDByName(workspaceService, task.listName); if (!listInfo) { throw new Error(`List "${task.listName}" not found`); } const taskList = await taskService.getTasks(listInfo.id); const foundTask = taskList.find(t => t.name.toLowerCase() === task.taskName.toLowerCase()); if (!foundTask) { throw new Error(`Task "${task.taskName}" not found in list "${task.listName}"`); } taskId = foundTask.id; } if (!taskId) { throw new Error("Either taskId or taskName must be provided"); } await taskService.moveTask(taskId, finalTargetListId); results.successful++; } catch (error: any) { results.failed++; results.failures.push({ task: task.taskId || task.taskName, error: error.message }); } } return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] }; }
  • Input schema definition for the move_bulk_tasks tool, specifying parameters for tasks array and target list.
    export const moveBulkTasksTool = { name: "move_bulk_tasks", description: "Move multiple tasks to a different list efficiently. For each task, you MUST provide either:\n1. taskId alone (preferred)\n2. taskName + listName\n\nWARNING: Task statuses may reset if target list has different status options.", inputSchema: { type: "object", properties: { tasks: { type: "array", description: "Array of tasks to move", items: { type: "object", properties: { taskId: { type: "string", description: "Task ID (preferred). Use instead of taskName if available." }, taskName: { type: "string", description: "Task name. Requires listName when used." }, listName: { type: "string", description: "REQUIRED with taskName: List containing the task." } } } }, targetListId: { type: "string", description: "ID of destination list (preferred). Use instead of targetListName if available." }, targetListName: { type: "string", description: "Name of destination list. Only use if you don't have targetListId." } }, required: ["tasks"] } };
  • src/server.ts:67-93 (registration)
    Registration of moveBulkTasksTool in the list of available tools returned by ListToolsRequestHandler.
    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:120-122 (registration)
    Dispatcher case in CallToolRequestHandler that routes 'move_bulk_tasks' calls to handleMoveBulkTasks handler.
    case "move_bulk_tasks": return handleMoveBulkTasks(params as { tasks: any[], targetListId?: string, targetListName?: string }); case "delete_bulk_tasks":
  • Bulk task moving helper method in ClickUpTaskService. Recreates tasks in new list and deletes originals with advanced batching and error handling. (Note: tool handler uses single moveTask loop instead of this bulk method.)
    async moveBulkTasks( tasks: string[], targetListId: string, options?: BulkOperationOptions, progressCallback?: (progress: ProgressInfo) => void ): Promise<BulkOperationResult<ClickUpTask>> { this.logOperation('moveBulkTasks', { taskCount: tasks.length, targetListId, batchSize: options?.batchSize, concurrency: options?.concurrency }); try { // First verify destination list exists const destinationList = await this.listService.getList(targetListId); if (!destinationList) { throw new ClickUpServiceError( `Destination list not found with ID: ${targetListId}`, ErrorCode.NOT_FOUND ); } // Set default options for better performance const bulkOptions: BulkOperationOptions = { batchSize: options?.batchSize ?? 5, // Smaller batch size for better rate limit handling concurrency: options?.concurrency ?? 2, // Lower concurrency to avoid rate limits continueOnError: options?.continueOnError ?? true, // Continue on individual task failures retryCount: options?.retryCount ?? 3, // Retry failed operations ...options }; return await this.bulkProcessor.processBulk( tasks, async (taskId) => { try { // Get the original task const originalTask = await this.getTask(taskId); const currentStatus = originalTask.status?.status; const availableStatuses = destinationList.statuses?.map(s => s.status) || []; // Determine the appropriate status for the destination list let newStatus = availableStatuses.includes(currentStatus || '') ? currentStatus // Keep the same status if available in destination list : destinationList.statuses?.[0]?.status; // Otherwise use the default (first) status // Prepare the task data for the new list const taskData: CreateTaskData = { name: originalTask.name, description: originalTask.description, status: newStatus, priority: originalTask.priority?.priority as any, due_date: originalTask.due_date ? Number(originalTask.due_date) : undefined, assignees: originalTask.assignees?.map(a => a.id) || [] }; // Create new task and delete old one in a single makeRequest call return await this.makeRequest(async () => { // First create the new task const response = await this.client.post<ClickUpTask>( `/list/${targetListId}/task`, taskData ); // Then delete the original task await this.client.delete(`/task/${taskId}`); // Add a property to indicate the task was moved const newTask = { ...response.data, moved: true, originalId: taskId }; return newTask; }); } catch (error) { // Enhance error context for better debugging if (error instanceof ClickUpServiceError) { error.context = { ...error.context, taskId, targetListId, targetListName: destinationList.name }; } throw error; } }, bulkOptions ); } catch (error: any) { const errorMessage = error instanceof ClickUpServiceError ? error.message : `Failed to move tasks in bulk: ${error.message}`; throw new ClickUpServiceError( errorMessage, error instanceof ClickUpServiceError ? error.code : ErrorCode.UNKNOWN, { targetListId, taskCount: tasks.length, error: error instanceof Error ? error.message : String(error) } ); } }

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