@taazkareem/clickup-mcp-server 0.4.72 → 0.4.73

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,224 @@
1
+ /**
2
+ * ClickUp MCP Bulk Task Operations
3
+ *
4
+ * This module defines tools for bulk task operations including creating,
5
+ * updating, moving, and deleting multiple tasks at once.
6
+ */
7
+ import { clickUpServices } from '../../services/shared.js';
8
+ import { BulkService } from '../../services/clickup/bulk.js';
9
+ // Initialize services
10
+ const { task: taskService } = clickUpServices;
11
+ const bulkService = new BulkService(taskService);
12
+ //=============================================================================
13
+ // COMMON SCHEMA DEFINITIONS
14
+ //=============================================================================
15
+ // Common schema definitions
16
+ const bulkOptionsSchema = {
17
+ oneOf: [
18
+ {
19
+ type: "object",
20
+ description: "Optional processing settings",
21
+ properties: {
22
+ batchSize: {
23
+ type: "number",
24
+ description: "Tasks per batch (default: 10)"
25
+ },
26
+ concurrency: {
27
+ type: "number",
28
+ description: "Parallel operations (default: 3)"
29
+ },
30
+ continueOnError: {
31
+ type: "boolean",
32
+ description: "Continue if some tasks fail"
33
+ },
34
+ retryCount: {
35
+ type: "number",
36
+ description: "Retry attempts for failures"
37
+ }
38
+ }
39
+ },
40
+ {
41
+ type: "string",
42
+ description: "JSON string representing options. Will be parsed automatically."
43
+ }
44
+ ],
45
+ description: "Processing options (or JSON string representing options)"
46
+ };
47
+ const taskIdentifierSchema = {
48
+ taskId: {
49
+ type: "string",
50
+ description: "Task ID (preferred). Use instead of taskName if available."
51
+ },
52
+ taskName: {
53
+ type: "string",
54
+ description: "Task name. Requires listName when used."
55
+ },
56
+ listName: {
57
+ type: "string",
58
+ description: "REQUIRED with taskName: List containing the task."
59
+ }
60
+ };
61
+ //=============================================================================
62
+ // BULK TASK OPERATION TOOLS
63
+ //=============================================================================
64
+ /**
65
+ * Tool definition for creating multiple tasks at once
66
+ */
67
+ export const createBulkTasksTool = {
68
+ name: "create_bulk_tasks",
69
+ 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.",
70
+ inputSchema: {
71
+ type: "object",
72
+ properties: {
73
+ listId: {
74
+ type: "string",
75
+ description: "ID of list for new tasks (preferred). Use this instead of listName if you have it."
76
+ },
77
+ listName: {
78
+ type: "string",
79
+ description: "Name of list for new tasks. Only use if you don't have listId."
80
+ },
81
+ tasks: {
82
+ type: "array",
83
+ description: "Array of tasks to create. Each task must have at least a name.",
84
+ items: {
85
+ type: "object",
86
+ properties: {
87
+ name: {
88
+ type: "string",
89
+ description: "Task name with emoji prefix"
90
+ },
91
+ description: {
92
+ type: "string",
93
+ description: "Plain text description"
94
+ },
95
+ markdown_description: {
96
+ type: "string",
97
+ description: "Markdown description (overrides plain text)"
98
+ },
99
+ status: {
100
+ type: "string",
101
+ description: "Task status (uses list default if omitted)"
102
+ },
103
+ priority: {
104
+ type: "number",
105
+ description: "Priority 1-4 (1=urgent, 4=low)"
106
+ },
107
+ dueDate: {
108
+ type: "string",
109
+ description: "Due date. Supports Unix timestamps (in milliseconds) and natural language expressions like '1 hour from now', 'tomorrow', 'next week', etc."
110
+ }
111
+ },
112
+ required: ["name"]
113
+ }
114
+ },
115
+ options: bulkOptionsSchema
116
+ },
117
+ required: ["tasks"]
118
+ }
119
+ };
120
+ /**
121
+ * Tool definition for updating multiple tasks at once
122
+ */
123
+ export const updateBulkTasksTool = {
124
+ name: "update_bulk_tasks",
125
+ description: "Update multiple tasks efficiently. For each task, you MUST provide either:\n1. taskId alone (preferred)\n2. taskName + listName\n\nOnly specified fields will be updated for each task.",
126
+ inputSchema: {
127
+ type: "object",
128
+ properties: {
129
+ tasks: {
130
+ type: "array",
131
+ description: "Array of tasks to update",
132
+ items: {
133
+ type: "object",
134
+ properties: {
135
+ ...taskIdentifierSchema,
136
+ name: {
137
+ type: "string",
138
+ description: "New name with emoji prefix"
139
+ },
140
+ description: {
141
+ type: "string",
142
+ description: "New plain text description"
143
+ },
144
+ markdown_description: {
145
+ type: "string",
146
+ description: "New markdown description"
147
+ },
148
+ status: {
149
+ type: "string",
150
+ description: "New status"
151
+ },
152
+ priority: {
153
+ type: ["number", "null"],
154
+ enum: [1, 2, 3, 4, null],
155
+ description: "New priority (1-4 or null)"
156
+ },
157
+ dueDate: {
158
+ type: "string",
159
+ description: "New due date. Supports Unix timestamps (in milliseconds) and natural language expressions like '1 hour from now', 'tomorrow', etc."
160
+ }
161
+ }
162
+ }
163
+ },
164
+ options: bulkOptionsSchema
165
+ },
166
+ required: ["tasks"]
167
+ }
168
+ };
169
+ /**
170
+ * Tool definition for moving multiple tasks at once
171
+ */
172
+ export const moveBulkTasksTool = {
173
+ name: "move_bulk_tasks",
174
+ 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.",
175
+ inputSchema: {
176
+ type: "object",
177
+ properties: {
178
+ tasks: {
179
+ type: "array",
180
+ description: "Array of tasks to move",
181
+ items: {
182
+ type: "object",
183
+ properties: {
184
+ ...taskIdentifierSchema
185
+ }
186
+ }
187
+ },
188
+ targetListId: {
189
+ type: "string",
190
+ description: "ID of destination list (preferred). Use instead of targetListName if available."
191
+ },
192
+ targetListName: {
193
+ type: "string",
194
+ description: "Name of destination list. Only use if you don't have targetListId."
195
+ },
196
+ options: bulkOptionsSchema
197
+ },
198
+ required: ["tasks"]
199
+ }
200
+ };
201
+ /**
202
+ * Tool definition for deleting multiple tasks at once
203
+ */
204
+ export const deleteBulkTasksTool = {
205
+ name: "delete_bulk_tasks",
206
+ description: "⚠️ PERMANENTLY DELETE multiple tasks. This action cannot be undone. For each task, you MUST provide either:\n1. taskId alone (preferred and safest)\n2. taskName + listName (use with caution).",
207
+ inputSchema: {
208
+ type: "object",
209
+ properties: {
210
+ tasks: {
211
+ type: "array",
212
+ description: "Array of tasks to delete",
213
+ items: {
214
+ type: "object",
215
+ properties: {
216
+ ...taskIdentifierSchema
217
+ }
218
+ }
219
+ },
220
+ options: bulkOptionsSchema
221
+ },
222
+ required: ["tasks"]
223
+ }
224
+ };
@@ -0,0 +1,213 @@
1
+ /**
2
+ * ClickUp MCP Task Operation Handlers
3
+ *
4
+ * This module implements the handlers for task operations, both for single task
5
+ * and bulk operations. These handlers are used by the tool definitions.
6
+ */
7
+ import { toTaskPriority } from '../../services/clickup/types.js';
8
+ import { clickUpServices } from '../../services/shared.js';
9
+ import { BulkService } from '../../services/clickup/bulk.js';
10
+ import { parseDueDate } from '../utils.js';
11
+ import { validateTaskIdentification, validateListIdentification, validateTaskUpdateData, validateBulkTasks, parseBulkOptions, resolveTaskIdWithValidation, resolveListIdWithValidation } from './utilities.js';
12
+ // Use shared services instance
13
+ const { task: taskService, list: listService } = clickUpServices;
14
+ // Create a bulk service instance that uses the task service
15
+ const bulkService = new BulkService(taskService);
16
+ //=============================================================================
17
+ // SHARED UTILITY FUNCTIONS
18
+ //=============================================================================
19
+ /**
20
+ * Build task update data from parameters
21
+ */
22
+ function buildUpdateData(params) {
23
+ const updateData = {};
24
+ if (params.name !== undefined)
25
+ updateData.name = params.name;
26
+ if (params.description !== undefined)
27
+ updateData.description = params.description;
28
+ if (params.markdown_description !== undefined)
29
+ updateData.markdown_description = params.markdown_description;
30
+ if (params.status !== undefined)
31
+ updateData.status = params.status;
32
+ if (params.priority !== undefined)
33
+ updateData.priority = toTaskPriority(params.priority);
34
+ if (params.dueDate !== undefined)
35
+ updateData.due_date = parseDueDate(params.dueDate);
36
+ return updateData;
37
+ }
38
+ /**
39
+ * Process a task identification validation, returning the task ID
40
+ */
41
+ async function getTaskId(taskId, taskName, listName) {
42
+ validateTaskIdentification(taskId, taskName, listName);
43
+ return await resolveTaskIdWithValidation(taskId, taskName, listName);
44
+ }
45
+ /**
46
+ * Process a list identification validation, returning the list ID
47
+ */
48
+ async function getListId(listId, listName) {
49
+ validateListIdentification(listId, listName);
50
+ return await resolveListIdWithValidation(listId, listName);
51
+ }
52
+ /**
53
+ * Extract and build task filters from parameters
54
+ */
55
+ function buildTaskFilters(params) {
56
+ const { subtasks, statuses, page, order_by, reverse } = params;
57
+ const filters = {};
58
+ if (subtasks !== undefined)
59
+ filters.subtasks = subtasks;
60
+ if (statuses !== undefined)
61
+ filters.statuses = statuses;
62
+ if (page !== undefined)
63
+ filters.page = page;
64
+ if (order_by !== undefined)
65
+ filters.order_by = order_by;
66
+ if (reverse !== undefined)
67
+ filters.reverse = reverse;
68
+ return filters;
69
+ }
70
+ /**
71
+ * Map tasks for bulk operations, resolving task IDs
72
+ */
73
+ async function mapTaskIds(tasks) {
74
+ return Promise.all(tasks.map(async (task) => {
75
+ validateTaskIdentification(task.taskId, task.taskName, task.listName);
76
+ return await resolveTaskIdWithValidation(task.taskId, task.taskName, task.listName);
77
+ }));
78
+ }
79
+ //=============================================================================
80
+ // SINGLE TASK OPERATIONS
81
+ //=============================================================================
82
+ /**
83
+ * Handler for creating a task
84
+ */
85
+ export async function createTaskHandler(params) {
86
+ const { name, description, markdown_description, status, dueDate } = params;
87
+ if (!name)
88
+ throw new Error("Task name is required");
89
+ // Use our helper function to validate and convert priority
90
+ const priority = toTaskPriority(params.priority);
91
+ const listId = await getListId(params.listId, params.listName);
92
+ return await taskService.createTask(listId, {
93
+ name,
94
+ description,
95
+ markdown_description,
96
+ status,
97
+ priority,
98
+ due_date: dueDate ? parseDueDate(dueDate) : undefined
99
+ });
100
+ }
101
+ /**
102
+ * Handler for updating a task
103
+ */
104
+ export async function updateTaskHandler(params) {
105
+ validateTaskUpdateData(params);
106
+ const taskId = await getTaskId(params.taskId, params.taskName, params.listName);
107
+ return await taskService.updateTask(taskId, buildUpdateData(params));
108
+ }
109
+ /**
110
+ * Handler for moving a task
111
+ */
112
+ export async function moveTaskHandler(params) {
113
+ const taskId = await getTaskId(params.taskId, params.taskName, params.listName);
114
+ const listId = await getListId(params.listId, params.listName);
115
+ return await taskService.moveTask(taskId, listId);
116
+ }
117
+ /**
118
+ * Handler for duplicating a task
119
+ */
120
+ export async function duplicateTaskHandler(params) {
121
+ const taskId = await getTaskId(params.taskId, params.taskName, params.listName);
122
+ let listId;
123
+ if (params.listId || params.listName) {
124
+ listId = await getListId(params.listId, params.listName);
125
+ }
126
+ return await taskService.duplicateTask(taskId, listId);
127
+ }
128
+ /**
129
+ * Handler for getting a task
130
+ */
131
+ export async function getTaskHandler(params) {
132
+ const taskId = await getTaskId(params.taskId, params.taskName, params.listName);
133
+ return await taskService.getTask(taskId);
134
+ }
135
+ /**
136
+ * Handler for getting tasks
137
+ */
138
+ export async function getTasksHandler(params) {
139
+ const listId = await getListId(params.listId, params.listName);
140
+ return await taskService.getTasks(listId, buildTaskFilters(params));
141
+ }
142
+ /**
143
+ * Handler for deleting a task
144
+ */
145
+ export async function deleteTaskHandler(params) {
146
+ const taskId = await getTaskId(params.taskId, params.taskName, params.listName);
147
+ await taskService.deleteTask(taskId);
148
+ return true;
149
+ }
150
+ /**
151
+ * Handler for getting task comments
152
+ */
153
+ export async function getTaskCommentsHandler(params) {
154
+ const taskId = await getTaskId(params.taskId, params.taskName, params.listName);
155
+ const { start, startId } = params;
156
+ return await taskService.getTaskComments(taskId, start, startId);
157
+ }
158
+ //=============================================================================
159
+ // BULK TASK OPERATIONS
160
+ //=============================================================================
161
+ /**
162
+ * Handler for creating multiple tasks
163
+ */
164
+ export async function createBulkTasksHandler(params) {
165
+ validateBulkTasks(params.tasks);
166
+ const listId = await getListId(params.listId, params.listName);
167
+ // Process tasks - prepare data for each task
168
+ const tasks = params.tasks.map(task => {
169
+ const processedTask = { ...task };
170
+ if (task.dueDate) {
171
+ processedTask.due_date = parseDueDate(task.dueDate);
172
+ delete processedTask.dueDate;
173
+ }
174
+ return processedTask;
175
+ });
176
+ const result = await bulkService.createTasks(listId, tasks, parseBulkOptions(params.options));
177
+ return result.successful;
178
+ }
179
+ /**
180
+ * Handler for updating multiple tasks
181
+ */
182
+ export async function updateBulkTasksHandler(params) {
183
+ validateBulkTasks(params.tasks);
184
+ const updates = await Promise.all(params.tasks.map(async (task) => {
185
+ validateTaskUpdateData(task);
186
+ const taskId = await getTaskId(task.taskId, task.taskName, task.listName);
187
+ return { id: taskId, data: buildUpdateData(task) };
188
+ }));
189
+ const result = await bulkService.updateTasks(updates, parseBulkOptions(params.options));
190
+ return result.successful;
191
+ }
192
+ /**
193
+ * Handler for moving multiple tasks
194
+ */
195
+ export async function moveBulkTasksHandler(params) {
196
+ validateBulkTasks(params.tasks);
197
+ if (!params.targetListId && !params.targetListName) {
198
+ throw new Error("Either targetListId or targetListName must be provided");
199
+ }
200
+ const targetListId = await getListId(params.targetListId, params.targetListName);
201
+ const taskIds = await mapTaskIds(params.tasks);
202
+ const result = await bulkService.moveTasks(taskIds, targetListId, parseBulkOptions(params.options));
203
+ return result.successful;
204
+ }
205
+ /**
206
+ * Handler for deleting multiple tasks
207
+ */
208
+ export async function deleteBulkTasksHandler(params) {
209
+ validateBulkTasks(params.tasks);
210
+ const taskIds = await mapTaskIds(params.tasks);
211
+ await bulkService.deleteTasks(taskIds, parseBulkOptions(params.options));
212
+ return taskIds.map(() => true);
213
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * ClickUp MCP Task Tools
3
+ *
4
+ * This module re-exports all task-related tools and handlers.
5
+ */
6
+ // Re-export from main module
7
+ export * from './main.js';
8
+ // Re-export single task operation tools
9
+ export { createTaskTool, getTaskTool, getTasksTool, updateTaskTool, moveTaskTool, duplicateTaskTool, deleteTaskTool, getTaskCommentsTool } from './single-operations.js';
10
+ // Re-export bulk task operation tools
11
+ export { createBulkTasksTool, updateBulkTasksTool, moveBulkTasksTool, deleteBulkTasksTool } from './bulk-operations.js';
12
+ // Re-export handlers
13
+ export {
14
+ // Single task operation handlers
15
+ createTaskHandler, getTaskHandler, getTasksHandler, updateTaskHandler, moveTaskHandler, duplicateTaskHandler, deleteTaskHandler, getTaskCommentsHandler,
16
+ // Bulk task operation handlers
17
+ createBulkTasksHandler, updateBulkTasksHandler, moveBulkTasksHandler, deleteBulkTasksHandler } from './handlers.js';
18
+ // Re-export utilities
19
+ export { formatTaskData, validateTaskIdentification, validateListIdentification, validateTaskUpdateData, validateBulkTasks, parseBulkOptions, resolveTaskIdWithValidation, resolveListIdWithValidation } from './utilities.js';
@@ -0,0 +1,89 @@
1
+ /**
2
+ * ClickUp MCP Task Tools
3
+ *
4
+ * This is the main task module that connects tool definitions to their handlers.
5
+ * The actual implementations are organized in sub-modules for better maintainability.
6
+ */
7
+ import { sponsorService } from '../../utils/sponsor-service.js';
8
+ // Import tool definitions
9
+ import { createTaskTool, getTaskTool, getTasksTool, updateTaskTool, moveTaskTool, duplicateTaskTool, deleteTaskTool, getTaskCommentsTool } from './single-operations.js';
10
+ import { createBulkTasksTool, updateBulkTasksTool, moveBulkTasksTool, deleteBulkTasksTool } from './bulk-operations.js';
11
+ // Import handlers
12
+ import { createTaskHandler, getTaskHandler, getTasksHandler, updateTaskHandler, moveTaskHandler, duplicateTaskHandler, deleteTaskHandler, getTaskCommentsHandler, createBulkTasksHandler, updateBulkTasksHandler, moveBulkTasksHandler, deleteBulkTasksHandler } from './handlers.js';
13
+ //=============================================================================
14
+ // HANDLER WRAPPER UTILITY
15
+ //=============================================================================
16
+ /**
17
+ * Creates a wrapped handler function with standard error handling and response formatting
18
+ */
19
+ function createHandlerWrapper(handler, formatResponse = (result) => result) {
20
+ return async (parameters) => {
21
+ try {
22
+ const result = await handler(parameters);
23
+ return sponsorService.createResponse(formatResponse(result), true);
24
+ }
25
+ catch (error) {
26
+ return sponsorService.createErrorResponse(error, parameters);
27
+ }
28
+ };
29
+ }
30
+ //=============================================================================
31
+ // SINGLE TASK OPERATIONS - HANDLER IMPLEMENTATIONS
32
+ //=============================================================================
33
+ export const handleCreateTask = createHandlerWrapper(createTaskHandler);
34
+ export const handleGetTask = createHandlerWrapper(getTaskHandler);
35
+ export const handleGetTasks = createHandlerWrapper(getTasksHandler, (tasks) => ({
36
+ tasks,
37
+ count: tasks.length
38
+ }));
39
+ export const handleUpdateTask = createHandlerWrapper(updateTaskHandler);
40
+ export const handleMoveTask = createHandlerWrapper(moveTaskHandler);
41
+ export const handleDuplicateTask = createHandlerWrapper(duplicateTaskHandler);
42
+ export const handleDeleteTask = createHandlerWrapper(deleteTaskHandler, () => ({
43
+ success: true,
44
+ message: "Task deleted successfully"
45
+ }));
46
+ export const handleGetTaskComments = createHandlerWrapper(getTaskCommentsHandler, (comments) => ({
47
+ comments,
48
+ count: comments.length
49
+ }));
50
+ //=============================================================================
51
+ // BULK TASK OPERATIONS - HANDLER IMPLEMENTATIONS
52
+ //=============================================================================
53
+ export const handleCreateBulkTasks = createHandlerWrapper(createBulkTasksHandler, (tasks) => ({
54
+ tasks,
55
+ count: tasks.length
56
+ }));
57
+ export const handleUpdateBulkTasks = createHandlerWrapper(updateBulkTasksHandler, (tasks) => ({
58
+ tasks,
59
+ count: tasks.length
60
+ }));
61
+ export const handleMoveBulkTasks = createHandlerWrapper(moveBulkTasksHandler, (tasks) => ({
62
+ tasks,
63
+ count: tasks.length
64
+ }));
65
+ export const handleDeleteBulkTasks = createHandlerWrapper(deleteBulkTasksHandler, (results) => ({
66
+ success: true,
67
+ count: results.length,
68
+ results
69
+ }));
70
+ //=============================================================================
71
+ // TOOL DEFINITIONS AND HANDLERS EXPORT
72
+ //=============================================================================
73
+ // Tool definitions with their handler mappings
74
+ export const taskTools = [
75
+ // Single task operations
76
+ { definition: createTaskTool, handler: handleCreateTask },
77
+ { definition: getTaskTool, handler: handleGetTask },
78
+ { definition: getTasksTool, handler: handleGetTasks },
79
+ { definition: updateTaskTool, handler: handleUpdateTask },
80
+ { definition: moveTaskTool, handler: handleMoveTask },
81
+ { definition: duplicateTaskTool, handler: handleDuplicateTask },
82
+ { definition: deleteTaskTool, handler: handleDeleteTask },
83
+ { definition: getTaskCommentsTool, handler: handleGetTaskComments },
84
+ // Bulk task operations
85
+ { definition: createBulkTasksTool, handler: handleCreateBulkTasks },
86
+ { definition: updateBulkTasksTool, handler: handleUpdateBulkTasks },
87
+ { definition: moveBulkTasksTool, handler: handleMoveBulkTasks },
88
+ { definition: deleteBulkTasksTool, handler: handleDeleteBulkTasks }
89
+ ];