Skip to main content
Glama

create_bulk_tasks

Create multiple tasks simultaneously in a ClickUp list by providing an array of task details, with optional batch processing and concurrency controls for efficient task management.

Instructions

Create multiple tasks in a list efficiently. You MUST provide:

  1. An array of tasks with required properties

  2. Either listId or listName to specify the target list

Optional: Configure batch size and concurrency for performance.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
listIdNoID of list for new tasks (preferred). Use this instead of listName if you have it.
listNameNoName of list for new tasks. Only use if you don't have listId.
tasksYesArray of tasks to create. Each task must have at least a name.
optionsNoOptional processing settings

Implementation Reference

  • Handler function that processes the create_bulk_tasks tool call. Validates input, resolves list ID if needed, maps tasks to ClickUp format, calls taskService.createBulkTasks, and formats results with success/failure counts.
    export async function handleCreateBulkTasks(parameters: any) { // Validate required parameters const { tasks, listId, listName } = parameters; if (!tasks || !Array.isArray(tasks) || tasks.length === 0) { throw new Error('You must provide a non-empty array of tasks to create'); } let targetListId = listId; // If no listId but listName is provided, look up the list ID if (!targetListId && listName) { const listInfo = await findListIDByName(workspaceService, listName); if (!listInfo) { throw new Error(`List "${listName}" not found`); } targetListId = listInfo.id; } if (!targetListId) { throw new Error("Either listId or listName must be provided"); } const results = { total: tasks.length, successful: 0, failed: 0, failures: [] as any[] }; // Map tasks to ClickUp format const clickupTasks = tasks.map((task: any) => { const taskData: CreateTaskData = { name: task.name, description: task.description, markdown_description: task.markdown_description, status: task.status, priority: task.priority as TaskPriority, due_date: task.dueDate ? parseDueDate(task.dueDate) : undefined }; // Add due_date_time flag if due date is set if (task.dueDate && taskData.due_date) { taskData.due_date_time = true; } return taskData; }); // Create tasks in bulk using the task service try { const bulkResult = await taskService.createBulkTasks(targetListId, { tasks: clickupTasks }); // Update results based on bulk operation outcome results.successful = bulkResult.successfulItems.length; results.failed = bulkResult.failedItems.length; results.failures = bulkResult.failedItems.map(failure => ({ task: failure.item.name, error: failure.error.message })); } catch (error: any) { // If the bulk operation itself fails, mark all tasks as failed results.failed = tasks.length; results.failures = tasks.map(task => ({ task: task.name, error: error.message })); } return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] }; }
  • Tool definition object including name, description, and detailed inputSchema for validating parameters like tasks array, listId/listName, and optional batching options.
    export const createBulkTasksTool = { name: "create_bulk_tasks", description: "Create multiple tasks in a list efficiently. You MUST provide:\n1. An array of tasks with required properties\n2. Either listId or listName to specify the target list\n\nOptional: Configure batch size and concurrency for performance.", inputSchema: { type: "object", properties: { listId: { type: "string", description: "ID of list for new tasks (preferred). Use this instead of listName if you have it." }, listName: { type: "string", description: "Name of list for new tasks. Only use if you don't have listId." }, tasks: { type: "array", description: "Array of tasks to create. Each task must have at least a name.", items: { type: "object", properties: { name: { type: "string", description: "Task name with emoji prefix" }, description: { type: "string", description: "Plain text description" }, markdown_description: { type: "string", description: "Markdown description (overrides plain text)" }, status: { type: "string", description: "Task status (uses list default if omitted)" }, priority: { type: "number", description: "Priority 1-4 (1=urgent, 4=low)" }, dueDate: { type: "string", description: "Due date (Unix timestamp ms)" } }, required: ["name"] } }, options: { type: "object", description: "Optional processing settings", properties: { batchSize: { type: "number", description: "Tasks per batch (default: 10)" }, concurrency: { type: "number", description: "Parallel operations (default: 1)" }, continueOnError: { type: "boolean", description: "Continue if some tasks fail" }, retryCount: { type: "number", description: "Retry attempts for failures" } } } }, required: ["tasks"] } };
  • src/server.ts:99-144 (registration)
    Server request handler switch statement that routes 'create_bulk_tasks' calls to handleCreateBulkTasks. Also registers the tool in the ListTools response at line 78.
    switch (name) { case "get_workspace_hierarchy": return handleGetWorkspaceHierarchy(); case "create_task": return handleCreateTask(params); case "update_task": return handleUpdateTask(params); case "move_task": return handleMoveTask(params); case "duplicate_task": return handleDuplicateTask(params); case "get_task": return handleGetTask(params); case "get_tasks": return handleGetTasks(params); case "delete_task": return handleDeleteTask(params); case "create_bulk_tasks": return handleCreateBulkTasks(params); case "update_bulk_tasks": return handleUpdateBulkTasks(params as { tasks: any[] }); case "move_bulk_tasks": return handleMoveBulkTasks(params as { tasks: any[], targetListId?: string, targetListName?: string }); case "delete_bulk_tasks": return handleDeleteBulkTasks(params as { tasks: any[] }); case "create_list": return handleCreateList(params); case "create_list_in_folder": return handleCreateListInFolder(params); case "get_list": return handleGetList(params); case "update_list": return handleUpdateList(params); case "delete_list": return handleDeleteList(params); case "create_folder": return handleCreateFolder(params); case "get_folder": return handleGetFolder(params); case "update_folder": return handleUpdateFolder(params); case "delete_folder": return handleDeleteFolder(params); default: throw new Error(`Unknown tool: ${name}`); }
  • src/server.ts:70-91 (registration)
    ListToolsRequestSchema handler that returns array of tools including createBulkTasksTool for MCP tool discovery.
    workspaceHierarchyTool, createTaskTool, getTaskTool, getTasksTool, updateTaskTool, moveTaskTool, duplicateTaskTool, deleteTaskTool, createBulkTasksTool, updateBulkTasksTool, moveBulkTasksTool, deleteBulkTasksTool, createListTool, createListInFolderTool, getListTool, updateListTool, deleteListTool, createFolderTool, getFolderTool, updateFolderTool, deleteFolderTool ]
  • Core service method in TaskService that implements bulk task creation using BulkProcessor for batching, concurrency, retries, and error handling. Called by the tool handler.
    async createBulkTasks( listId: string, data: { tasks: Array<CreateTaskData> }, options?: BulkOperationOptions, progressCallback?: (progress: ProgressInfo) => void ): Promise<BulkOperationResult<ClickUpTask>> { this.logOperation('createBulkTasks', { listId, taskCount: data.tasks.length, batchSize: options?.batchSize, concurrency: options?.concurrency }); try { // Validate list exists before proceeding const list = await this.listService.getList(listId).catch(() => null); if (!list) { throw new ClickUpServiceError( `List not found with ID: ${listId}`, 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 }; // Add list validation to progress tracking const wrappedCallback = progressCallback ? (progress: ProgressInfo) => { progress.context = { listId, listName: list.name }; progressCallback(progress); } : undefined; return await this.bulkProcessor.processBulk( data.tasks, async (taskData) => { try { // Ensure task data is properly formatted const sanitizedData = { ...taskData, // Remove any accidentally included list IDs in task data list: undefined, // Ensure name has emoji if missing name: taskData.name.match(/^\p{Emoji}/u) ? taskData.name : '📋 ' + taskData.name }; return await this.createTask(listId, sanitizedData); } catch (error) { // Enhance error context for better debugging if (error instanceof ClickUpServiceError) { error.context = { ...error.context, taskName: taskData.name, listId, listName: list.name }; } throw error; } }, bulkOptions ); } catch (error: any) { const errorMessage = error instanceof ClickUpServiceError ? error.message : `Failed to create tasks in bulk: ${error.message}`; throw new ClickUpServiceError( errorMessage, error instanceof ClickUpServiceError ? error.code : ErrorCode.UNKNOWN, { listId, taskCount: data.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