@taazkareem/clickup-mcp-server
Version:
ClickUp MCP Server - Integrate ClickUp tasks with AI through Model Context Protocol
339 lines (338 loc) • 15.2 kB
JavaScript
/**
* SPDX-FileCopyrightText: © 2025 Talib Kareem <taazkareem@icloud.com>
* SPDX-License-Identifier: MIT
*
* ClickUp MCP Bulk Task Operations
*
* This module defines tools for bulk task operations including creating,
* updating, moving, and deleting multiple tasks at once.
*/
import { clickUpServices } from '../../services/shared.js';
import { BulkService } from '../../services/clickup/bulk.js';
// Initialize services
const { task: taskService } = clickUpServices;
const bulkService = new BulkService(taskService);
//=============================================================================
// COMMON SCHEMA DEFINITIONS
//=============================================================================
// Common schema definitions
const bulkOptionsSchema = {
oneOf: [
{
type: "object",
description: "Optional processing settings",
properties: {
batchSize: {
type: "number",
description: "Tasks per batch (default: 10)"
},
concurrency: {
type: "number",
description: "Parallel operations (default: 3)"
},
continueOnError: {
type: "boolean",
description: "Continue if some tasks fail"
},
retryCount: {
type: "number",
description: "Retry attempts for failures"
}
}
},
{
type: "string",
description: "JSON string representing options. Will be parsed automatically."
}
],
description: "Processing options (or JSON string representing options)"
};
const taskIdentifierSchema = {
taskId: {
type: "string",
description: "Task ID (preferred). Automatically detects and handles both regular task IDs (9 characters) and custom IDs (like 'DEV-1234', 'PROJ-456')."
},
taskName: {
type: "string",
description: "Task name. Requires listName when used."
},
listName: {
type: "string",
description: "REQUIRED with taskName: List containing the task."
},
customTaskId: {
type: "string",
description: "Custom task ID (e.g., 'DEV-1234'). This parameter is now optional since taskId automatically handles custom IDs. Use only for explicit custom ID lookup or backward compatibility."
}
};
//=============================================================================
// BULK TASK OPERATION TOOLS
//=============================================================================
/**
* Tool definition for creating multiple tasks at once
*/
export const createBulkTasksTool = {
name: "create_bulk_tasks",
description: `Creates multiple tasks in one list. Use listId (preferred) or listName + array of tasks (each needs name). Configure batch size/concurrency via options. Tasks can have custom fields as {id, value} array and assignees as array of user IDs, emails, or usernames.`,
inputSchema: {
type: "object",
properties: {
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. Supports Unix timestamps (in milliseconds) and natural language expressions like '1 hour from now', 'tomorrow', 'next week', etc."
},
tags: {
type: "array",
items: {
type: "string"
},
description: "Optional array of tag names to assign to the task. The tags must already exist in the space."
},
custom_fields: {
type: "array",
items: {
type: "object",
properties: {
id: {
type: "string",
description: "ID of the custom field"
},
value: {
description: "Value for the custom field. Type depends on the field type."
}
},
required: ["id", "value"]
},
description: "Optional array of custom field values to set on the task."
},
assignees: {
type: "array",
items: {
oneOf: [
{ type: "number" },
{ type: "string" }
]
},
description: "Optional array of assignee user IDs (numbers), emails, or usernames to assign to the task."
}
},
required: ["name"]
}
},
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."
},
options: bulkOptionsSchema
},
required: ["tasks"]
}
};
/**
* Tool definition for updating multiple tasks
*/
export const updateBulkTasksTool = {
name: "update_bulk_tasks",
description: `Updates multiple tasks efficiently. For each task: use taskId (preferred) or taskName + listName. At least one update field per task. Supports assignees as array of user IDs, emails, or usernames. Configure batch size/concurrency via options. WARNING: taskName without listName will fail.`,
inputSchema: {
type: "object",
properties: {
tasks: {
type: "array",
description: "Array of tasks to update",
items: {
type: "object",
properties: {
taskId: {
type: "string",
description: "Task ID (preferred). Automatically detects and handles both regular task IDs (9 characters) and custom IDs (like 'DEV-1234', 'PROJ-456')."
},
taskName: {
type: "string",
description: "Task name. Requires listName when used."
},
listName: {
type: "string",
description: "REQUIRED with taskName: List containing the task."
},
customTaskId: {
type: "string",
description: "Custom task ID (e.g., 'DEV-1234'). Only use if you want to explicitly force custom ID lookup. In most cases, use taskId which auto-detects ID format."
},
name: {
type: "string",
description: "New name with emoji prefix"
},
description: {
type: "string",
description: "New plain text description"
},
markdown_description: {
type: "string",
description: "New markdown description"
},
status: {
type: "string",
description: "New status"
},
priority: {
type: "string",
nullable: true,
enum: ["1", "2", "3", "4", null],
description: "New priority (1-4 or null)"
},
dueDate: {
type: "string",
description: "New due date. Supports Unix timestamps (in milliseconds) and natural language expressions like '1 hour from now', 'tomorrow', etc."
},
custom_fields: {
type: "array",
items: {
type: "object",
properties: {
id: {
type: "string",
description: "ID of the custom field"
},
value: {
description: "Value for the custom field. Type depends on the field type."
}
},
required: ["id", "value"]
},
description: "Optional array of custom field values to set on the task."
},
assignees: {
type: "array",
items: {
oneOf: [
{ type: "number" },
{ type: "string" }
]
},
description: "Optional array of assignee user IDs (numbers), emails, or usernames to assign to the task."
}
}
}
},
options: bulkOptionsSchema
},
required: ["tasks"]
}
};
/**
* Tool definition for moving multiple tasks
*/
export const moveBulkTasksTool = {
name: "move_bulk_tasks",
description: `Moves multiple tasks to one list. For each task: use taskId (preferred) or taskName + listName. Target list: use targetListId/Name. Configure batch size/concurrency via options. WARNING: Task statuses may reset, taskName needs listName.`,
inputSchema: {
type: "object",
properties: {
tasks: {
type: "array",
description: "Array of tasks to move",
items: {
type: "object",
properties: {
taskId: {
type: "string",
description: "Task ID (preferred). Automatically detects and handles both regular task IDs (9 characters) and custom IDs (like 'DEV-1234', 'PROJ-456')."
},
taskName: {
type: "string",
description: "Task name. Requires listName when used."
},
listName: {
type: "string",
description: "REQUIRED with taskName: List containing the task."
},
customTaskId: {
type: "string",
description: "Custom task ID (e.g., 'DEV-1234'). Only use if you want to explicitly force custom ID lookup. In most cases, use taskId which auto-detects ID format."
}
}
}
},
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."
},
options: bulkOptionsSchema
},
required: ["tasks"]
}
};
/**
* Tool definition for deleting multiple tasks
*/
export const deleteBulkTasksTool = {
name: "delete_bulk_tasks",
description: `PERMANENTLY deletes multiple tasks. For each task: use taskId (preferred/safest) or taskName + listName. Configure batch size/concurrency via options. WARNING: Cannot be undone, taskName without listName is dangerous.`,
inputSchema: {
type: "object",
properties: {
tasks: {
type: "array",
description: "Array of tasks to delete",
items: {
type: "object",
properties: {
taskId: {
type: "string",
description: "Task ID (preferred). Automatically detects and handles both regular task IDs (9 characters) and custom IDs (like 'DEV-1234', 'PROJ-456')."
},
taskName: {
type: "string",
description: "Task name. Requires listName when used."
},
listName: {
type: "string",
description: "REQUIRED with taskName: List containing the task."
},
customTaskId: {
type: "string",
description: "Custom task ID (e.g., 'DEV-1234'). Only use if you want to explicitly force custom ID lookup. In most cases, use taskId which auto-detects ID format."
}
}
}
},
options: bulkOptionsSchema
},
required: ["tasks"]
}
};