@taazkareem/clickup-mcp-server 0.4.72 → 0.4.74

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.
@@ -7,6 +7,7 @@
7
7
  */
8
8
  import { clickUpServices } from '../services/shared.js';
9
9
  import config from '../config.js';
10
+ import { sponsorService } from '../utils/sponsor-service.js';
10
11
  // Use shared services instance
11
12
  const { list: listService, workspace: workspaceService } = clickUpServices;
12
13
  /**
@@ -14,7 +15,19 @@ const { list: listService, workspace: workspaceService } = clickUpServices;
14
15
  */
15
16
  export const createListTool = {
16
17
  name: "create_list",
17
- description: "Create a new list directly in a ClickUp space (not in a folder). You MUST provide either spaceId or spaceName. For creating lists inside folders, use create_list_in_folder instead.",
18
+ description: `Purpose: Create a new list directly in a ClickUp space (not in a folder).
19
+
20
+ Valid Usage:
21
+ 1. Provide spaceId + list name (preferred)
22
+ 2. Provide spaceName + list name
23
+
24
+ Requirements:
25
+ - name: REQUIRED
26
+ - EITHER spaceId OR spaceName: REQUIRED
27
+
28
+ Notes:
29
+ - For creating lists inside folders, use create_list_in_folder instead
30
+ - Optional fields include content, dueDate, priority, assignee, and status`,
18
31
  inputSchema: {
19
32
  type: "object",
20
33
  properties: {
@@ -59,7 +72,21 @@ export const createListTool = {
59
72
  */
60
73
  export const createListInFolderTool = {
61
74
  name: "create_list_in_folder",
62
- description: "Create a new list within a ClickUp folder. You MUST provide either: 1) folderId alone, or 2) folderName WITH either spaceName or spaceId. Folder names may not be unique across spaces, which is why space information is required when using folderName.",
75
+ description: `Purpose: Create a new list within a ClickUp folder.
76
+
77
+ Valid Usage:
78
+ 1. Provide folderId + list name (preferred)
79
+ 2. Provide folderName + (spaceId OR spaceName) + list name
80
+
81
+ Requirements:
82
+ - name: REQUIRED
83
+ - EITHER folderId OR (folderName + space information): REQUIRED
84
+ - When using folderName, EITHER spaceId OR spaceName is REQUIRED
85
+
86
+ Notes:
87
+ - Folder names may not be unique across spaces, which is why space information
88
+ is required when using folderName
89
+ - Optional fields include content and status`,
63
90
  inputSchema: {
64
91
  type: "object",
65
92
  properties: {
@@ -100,7 +127,18 @@ export const createListInFolderTool = {
100
127
  */
101
128
  export const getListTool = {
102
129
  name: "get_list",
103
- description: "Retrieve details about a specific ClickUp list. You MUST provide either listId or listName. Using listId is more reliable as list names might not be unique.",
130
+ description: `Purpose: Retrieve details about a specific ClickUp list.
131
+
132
+ Valid Usage:
133
+ 1. Provide listId (preferred)
134
+ 2. Provide listName
135
+
136
+ Requirements:
137
+ - EITHER listId OR listName: REQUIRED
138
+
139
+ Notes:
140
+ - Using listId is more reliable as list names might not be unique
141
+ - Returns list details including name, content, and space information`,
104
142
  inputSchema: {
105
143
  type: "object",
106
144
  properties: {
@@ -121,7 +159,19 @@ export const getListTool = {
121
159
  */
122
160
  export const updateListTool = {
123
161
  name: "update_list",
124
- description: "Update an existing ClickUp list's properties. You MUST provide either listId or listName, and at least one field to update (name, content, or status).",
162
+ description: `Purpose: Update an existing ClickUp list's properties.
163
+
164
+ Valid Usage:
165
+ 1. Provide listId + update fields (preferred)
166
+ 2. Provide listName + update fields
167
+
168
+ Requirements:
169
+ - EITHER listId OR listName: REQUIRED
170
+ - At least one field to update (name, content, or status): REQUIRED
171
+
172
+ Notes:
173
+ - Using listId is more reliable as list names might not be unique
174
+ - Only specified fields will be updated`,
125
175
  inputSchema: {
126
176
  type: "object",
127
177
  properties: {
@@ -154,7 +204,19 @@ export const updateListTool = {
154
204
  */
155
205
  export const deleteListTool = {
156
206
  name: "delete_list",
157
- description: "Permanently delete a ClickUp list and all its tasks. You MUST provide either listId or listName. WARNING: This action cannot be undone.",
207
+ description: `Purpose: Permanently delete a ClickUp list and all its tasks.
208
+
209
+ Valid Usage:
210
+ 1. Provide listId (preferred and safest)
211
+ 2. Provide listName
212
+
213
+ Requirements:
214
+ - EITHER listId OR listName: REQUIRED
215
+
216
+ ⚠️ CRITICAL WARNING:
217
+ - This action CANNOT be undone
218
+ - All tasks within the list will also be permanently deleted
219
+ - Using listName is risky as names may not be unique`,
158
220
  inputSchema: {
159
221
  type: "object",
160
222
  properties: {
@@ -222,24 +284,20 @@ export async function handleCreateList(parameters) {
222
284
  try {
223
285
  // Create the list
224
286
  const newList = await listService.createList(targetSpaceId, listData);
225
- return {
226
- content: [{
227
- type: "text",
228
- text: JSON.stringify({
229
- id: newList.id,
230
- name: newList.name,
231
- content: newList.content,
232
- space: {
233
- id: newList.space.id,
234
- name: newList.space.name
235
- },
236
- message: `List "${newList.name}" created successfully`
237
- }, null, 2)
238
- }]
239
- };
287
+ return sponsorService.createResponse({
288
+ id: newList.id,
289
+ name: newList.name,
290
+ content: newList.content,
291
+ space: {
292
+ id: newList.space.id,
293
+ name: newList.space.name
294
+ },
295
+ url: `https://app.clickup.com/${config.clickupTeamId}/v/l/${newList.id}`,
296
+ message: `List "${name}" created successfully`
297
+ }, true);
240
298
  }
241
299
  catch (error) {
242
- throw new Error(`Failed to create list: ${error.message}`);
300
+ return sponsorService.createErrorResponse(`Failed to create list: ${error.message}`);
243
301
  }
244
302
  }
245
303
  /**
@@ -290,24 +348,24 @@ export async function handleCreateListInFolder(parameters) {
290
348
  try {
291
349
  // Create the list in the folder
292
350
  const newList = await listService.createListInFolder(targetFolderId, listData);
293
- return {
294
- content: [{
295
- type: "text",
296
- text: JSON.stringify({
297
- id: newList.id,
298
- name: newList.name,
299
- content: newList.content,
300
- space: {
301
- id: newList.space.id,
302
- name: newList.space.name
303
- },
304
- message: `List "${newList.name}" created successfully in folder`
305
- }, null, 2)
306
- }]
307
- };
351
+ return sponsorService.createResponse({
352
+ id: newList.id,
353
+ name: newList.name,
354
+ content: newList.content,
355
+ folder: {
356
+ id: newList.folder.id,
357
+ name: newList.folder.name
358
+ },
359
+ space: {
360
+ id: newList.space.id,
361
+ name: newList.space.name
362
+ },
363
+ url: `https://app.clickup.com/${config.clickupTeamId}/v/l/${newList.id}`,
364
+ message: `List "${name}" created successfully in folder "${newList.folder.name}"`
365
+ }, true);
308
366
  }
309
367
  catch (error) {
310
- throw new Error(`Failed to create list in folder: ${error.message}`);
368
+ return sponsorService.createErrorResponse(`Failed to create list in folder: ${error.message}`);
311
369
  }
312
370
  }
313
371
  /**
@@ -331,25 +389,19 @@ export async function handleGetList(parameters) {
331
389
  try {
332
390
  // Get the list
333
391
  const list = await listService.getList(targetListId);
334
- return {
335
- content: [{
336
- type: "text",
337
- text: JSON.stringify({
338
- id: list.id,
339
- name: list.name,
340
- content: list.content,
341
- space: {
342
- id: list.space.id,
343
- name: list.space.name
344
- },
345
- status: list.status,
346
- url: `https://app.clickup.com/${config.clickupTeamId}/v/l/${list.id}`
347
- }, null, 2)
348
- }]
349
- };
392
+ return sponsorService.createResponse({
393
+ id: list.id,
394
+ name: list.name,
395
+ content: list.content,
396
+ space: {
397
+ id: list.space.id,
398
+ name: list.space.name
399
+ },
400
+ url: `https://app.clickup.com/${config.clickupTeamId}/v/l/${list.id}`
401
+ }, true);
350
402
  }
351
403
  catch (error) {
352
- throw new Error(`Failed to retrieve list: ${error.message}`);
404
+ return sponsorService.createErrorResponse(`Failed to retrieve list: ${error.message}`);
353
405
  }
354
406
  }
355
407
  /**
@@ -385,26 +437,20 @@ export async function handleUpdateList(parameters) {
385
437
  try {
386
438
  // Update the list
387
439
  const updatedList = await listService.updateList(targetListId, updateData);
388
- return {
389
- content: [{
390
- type: "text",
391
- text: JSON.stringify({
392
- id: updatedList.id,
393
- name: updatedList.name,
394
- content: updatedList.content,
395
- space: {
396
- id: updatedList.space.id,
397
- name: updatedList.space.name
398
- },
399
- status: updatedList.status,
400
- url: `https://app.clickup.com/${config.clickupTeamId}/v/l/${updatedList.id}`,
401
- message: `List "${updatedList.name}" updated successfully`
402
- }, null, 2)
403
- }]
404
- };
440
+ return sponsorService.createResponse({
441
+ id: updatedList.id,
442
+ name: updatedList.name,
443
+ content: updatedList.content,
444
+ space: {
445
+ id: updatedList.space.id,
446
+ name: updatedList.space.name
447
+ },
448
+ url: `https://app.clickup.com/${config.clickupTeamId}/v/l/${updatedList.id}`,
449
+ message: `List "${updatedList.name}" updated successfully`
450
+ }, true);
405
451
  }
406
452
  catch (error) {
407
- throw new Error(`Failed to update list: ${error.message}`);
453
+ return sponsorService.createErrorResponse(`Failed to update list: ${error.message}`);
408
454
  }
409
455
  }
410
456
  /**
@@ -431,17 +477,12 @@ export async function handleDeleteList(parameters) {
431
477
  const listName = list.name;
432
478
  // Delete the list
433
479
  await listService.deleteList(targetListId);
434
- return {
435
- content: [{
436
- type: "text",
437
- text: JSON.stringify({
438
- message: `List "${listName}" deleted successfully`,
439
- url: `https://app.clickup.com/${config.clickupTeamId}/v/l/${targetListId}`
440
- }, null, 2)
441
- }]
442
- };
480
+ return sponsorService.createResponse({
481
+ success: true,
482
+ message: `List "${listName || targetListId}" deleted successfully`
483
+ }, true);
443
484
  }
444
485
  catch (error) {
445
- throw new Error(`Failed to delete list: ${error.message}`);
486
+ return sponsorService.createErrorResponse(`Failed to delete list: ${error.message}`);
446
487
  }
447
488
  }
@@ -0,0 +1,284 @@
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: `Purpose: Create multiple tasks in a list efficiently.
70
+
71
+ Valid Usage:
72
+ 1. An array of tasks with required properties + listId (preferred)
73
+ 2. An array of tasks with required properties + listName
74
+
75
+ Requirements:
76
+ - tasks: REQUIRED (array of tasks, each with at least a name)
77
+ - EITHER listId OR listName: REQUIRED
78
+
79
+ Notes:
80
+ - Configure batch size and concurrency via options for performance
81
+ - Each task should have a name with emoji prefix
82
+ - All tasks will be created in the same list`,
83
+ inputSchema: {
84
+ type: "object",
85
+ properties: {
86
+ listId: {
87
+ type: "string",
88
+ description: "ID of list for new tasks (preferred). Use this instead of listName if you have it."
89
+ },
90
+ listName: {
91
+ type: "string",
92
+ description: "Name of list for new tasks. Only use if you don't have listId."
93
+ },
94
+ tasks: {
95
+ type: "array",
96
+ description: "Array of tasks to create. Each task must have at least a name.",
97
+ items: {
98
+ type: "object",
99
+ properties: {
100
+ name: {
101
+ type: "string",
102
+ description: "Task name with emoji prefix"
103
+ },
104
+ description: {
105
+ type: "string",
106
+ description: "Plain text description"
107
+ },
108
+ markdown_description: {
109
+ type: "string",
110
+ description: "Markdown description (overrides plain text)"
111
+ },
112
+ status: {
113
+ type: "string",
114
+ description: "Task status (uses list default if omitted)"
115
+ },
116
+ priority: {
117
+ type: "number",
118
+ description: "Priority 1-4 (1=urgent, 4=low)"
119
+ },
120
+ dueDate: {
121
+ type: "string",
122
+ description: "Due date. Supports Unix timestamps (in milliseconds) and natural language expressions like '1 hour from now', 'tomorrow', 'next week', etc."
123
+ }
124
+ },
125
+ required: ["name"]
126
+ }
127
+ },
128
+ options: bulkOptionsSchema
129
+ },
130
+ required: ["tasks"]
131
+ }
132
+ };
133
+ /**
134
+ * Tool definition for updating multiple tasks at once
135
+ */
136
+ export const updateBulkTasksTool = {
137
+ name: "update_bulk_tasks",
138
+ description: `Purpose: Update multiple tasks efficiently in a single operation.
139
+
140
+ Valid Usage:
141
+ 1. For each task, provide taskId (preferred)
142
+ 2. For each task, provide taskName + listName
143
+
144
+ Requirements:
145
+ - tasks: REQUIRED (array of tasks to update)
146
+ - For each task entry, EITHER taskId OR (taskName + listName) is REQUIRED
147
+ - At least one update field per task (name, description, status, priority, dueDate)
148
+
149
+ Notes:
150
+ - Only specified fields will be updated for each task
151
+ - Configure batch size and concurrency via options for performance
152
+ - Each task can have different fields to update`,
153
+ inputSchema: {
154
+ type: "object",
155
+ properties: {
156
+ tasks: {
157
+ type: "array",
158
+ description: "Array of tasks to update",
159
+ items: {
160
+ type: "object",
161
+ properties: {
162
+ ...taskIdentifierSchema,
163
+ name: {
164
+ type: "string",
165
+ description: "New name with emoji prefix"
166
+ },
167
+ description: {
168
+ type: "string",
169
+ description: "New plain text description"
170
+ },
171
+ markdown_description: {
172
+ type: "string",
173
+ description: "New markdown description"
174
+ },
175
+ status: {
176
+ type: "string",
177
+ description: "New status"
178
+ },
179
+ priority: {
180
+ type: ["number", "null"],
181
+ enum: [1, 2, 3, 4, null],
182
+ description: "New priority (1-4 or null)"
183
+ },
184
+ dueDate: {
185
+ type: "string",
186
+ description: "New due date. Supports Unix timestamps (in milliseconds) and natural language expressions like '1 hour from now', 'tomorrow', etc."
187
+ }
188
+ }
189
+ }
190
+ },
191
+ options: bulkOptionsSchema
192
+ },
193
+ required: ["tasks"]
194
+ }
195
+ };
196
+ /**
197
+ * Tool definition for moving multiple tasks at once
198
+ */
199
+ export const moveBulkTasksTool = {
200
+ name: "move_bulk_tasks",
201
+ description: `Purpose: Move multiple tasks to a different list efficiently.
202
+
203
+ Valid Usage:
204
+ 1. For each task, provide taskId + target list (preferred)
205
+ 2. For each task, provide taskName + listName + target list
206
+
207
+ Requirements:
208
+ - tasks: REQUIRED (array of tasks to move)
209
+ - EITHER targetListId OR targetListName: REQUIRED
210
+ - For each task entry, EITHER taskId OR (taskName + listName) is REQUIRED
211
+
212
+ Notes:
213
+ - Configure batch size and concurrency via options for performance
214
+ - All tasks will be moved to the same destination list
215
+
216
+ ⚠️ Warning:
217
+ - Task statuses may reset if destination list has different status options
218
+ - Using taskName without listName will fail as tasks may have identical names across lists`,
219
+ inputSchema: {
220
+ type: "object",
221
+ properties: {
222
+ tasks: {
223
+ type: "array",
224
+ description: "Array of tasks to move",
225
+ items: {
226
+ type: "object",
227
+ properties: {
228
+ ...taskIdentifierSchema
229
+ }
230
+ }
231
+ },
232
+ targetListId: {
233
+ type: "string",
234
+ description: "ID of destination list (preferred). Use instead of targetListName if available."
235
+ },
236
+ targetListName: {
237
+ type: "string",
238
+ description: "Name of destination list. Only use if you don't have targetListId."
239
+ },
240
+ options: bulkOptionsSchema
241
+ },
242
+ required: ["tasks"]
243
+ }
244
+ };
245
+ /**
246
+ * Tool definition for deleting multiple tasks at once
247
+ */
248
+ export const deleteBulkTasksTool = {
249
+ name: "delete_bulk_tasks",
250
+ description: `Purpose: PERMANENTLY DELETE multiple tasks at once.
251
+
252
+ Valid Usage:
253
+ 1. For each task, provide taskId (preferred and safest)
254
+ 2. For each task, provide taskName + listName
255
+
256
+ Requirements:
257
+ - tasks: REQUIRED (array of tasks to delete)
258
+ - For each task entry, EITHER taskId OR (taskName + listName) is REQUIRED
259
+
260
+ Notes:
261
+ - Configure batch size and concurrency via options for performance
262
+
263
+ ⚠️ CRITICAL WARNING:
264
+ - This action CANNOT be undone for any of the tasks
265
+ - Using taskName without listName is dangerous as names may not be unique
266
+ - Always provide listName when using taskName for safer targeting`,
267
+ inputSchema: {
268
+ type: "object",
269
+ properties: {
270
+ tasks: {
271
+ type: "array",
272
+ description: "Array of tasks to delete",
273
+ items: {
274
+ type: "object",
275
+ properties: {
276
+ ...taskIdentifierSchema
277
+ }
278
+ }
279
+ },
280
+ options: bulkOptionsSchema
281
+ },
282
+ required: ["tasks"]
283
+ }
284
+ };