@chykalophia/clickup-mcp-server 3.4.0 → 4.1.2
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.
- package/build/clickup-client/attachments-enhanced.js +4 -1
- package/build/clickup-client/attachments-enhanced.js.map +1 -1
- package/build/clickup-client/auth.js.map +1 -1
- package/build/clickup-client/chat-enhanced.js +3 -1
- package/build/clickup-client/chat-enhanced.js.map +1 -1
- package/build/clickup-client/checklists.js.map +1 -1
- package/build/clickup-client/comments-enhanced.js +4 -3
- package/build/clickup-client/comments-enhanced.js.map +1 -1
- package/build/clickup-client/comments.js +2 -1
- package/build/clickup-client/comments.js.map +1 -1
- package/build/clickup-client/custom-fields-enhanced.js +7 -7
- package/build/clickup-client/custom-fields-enhanced.js.map +1 -1
- package/build/clickup-client/dependencies-enhanced.js.map +1 -1
- package/build/clickup-client/docs-enhanced.d.ts +1 -1
- package/build/clickup-client/docs-enhanced.js +35 -7
- package/build/clickup-client/docs-enhanced.js.map +1 -1
- package/build/clickup-client/docs.js +6 -6
- package/build/clickup-client/docs.js.map +1 -1
- package/build/clickup-client/folders.js.map +1 -1
- package/build/clickup-client/goals-enhanced.js.map +1 -1
- package/build/clickup-client/index.js +2 -2
- package/build/clickup-client/index.js.map +1 -1
- package/build/clickup-client/lists.js.map +1 -1
- package/build/clickup-client/secure-client.js +7 -6
- package/build/clickup-client/secure-client.js.map +1 -1
- package/build/clickup-client/tasks.d.ts +41 -0
- package/build/clickup-client/tasks.js +128 -2
- package/build/clickup-client/tasks.js.map +1 -1
- package/build/clickup-client/time-tracking-enhanced.js +2 -6
- package/build/clickup-client/time-tracking-enhanced.js.map +1 -1
- package/build/clickup-client/views-enhanced.js.map +1 -1
- package/build/clickup-client/webhooks-enhanced.js +4 -3
- package/build/clickup-client/webhooks-enhanced.js.map +1 -1
- package/build/index-efficiency-simple.js +81 -50
- package/build/index-efficiency-simple.js.map +1 -1
- package/build/index-enhanced.js +1 -0
- package/build/index-enhanced.js.map +1 -1
- package/build/index.js +1 -0
- package/build/index.js.map +1 -1
- package/build/resources/checklist-resources.js +1 -0
- package/build/resources/checklist-resources.js.map +1 -1
- package/build/resources/comment-resources.js +1 -0
- package/build/resources/comment-resources.js.map +1 -1
- package/build/resources/doc-resources.js +1 -0
- package/build/resources/doc-resources.js.map +1 -1
- package/build/resources/folder-resources.js +1 -0
- package/build/resources/folder-resources.js.map +1 -1
- package/build/resources/list-resources.js +1 -0
- package/build/resources/list-resources.js.map +1 -1
- package/build/resources/space-resources.js +1 -0
- package/build/resources/space-resources.js.map +1 -1
- package/build/resources/task-resources.js +1 -0
- package/build/resources/task-resources.js.map +1 -1
- package/build/schemas/attachments-schemas.js +16 -10
- package/build/schemas/attachments-schemas.js.map +1 -1
- package/build/schemas/chat-schemas.d.ts +7 -7
- package/build/schemas/chat-schemas.js +22 -6
- package/build/schemas/chat-schemas.js.map +1 -1
- package/build/schemas/custom-field-schemas.d.ts +80 -80
- package/build/schemas/custom-field-schemas.js +27 -11
- package/build/schemas/custom-field-schemas.js.map +1 -1
- package/build/schemas/dependencies-schemas.d.ts +11 -11
- package/build/schemas/dependencies-schemas.js +14 -11
- package/build/schemas/dependencies-schemas.js.map +1 -1
- package/build/schemas/document-schemas.d.ts +14 -14
- package/build/schemas/document-schemas.js +38 -14
- package/build/schemas/document-schemas.js.map +1 -1
- package/build/schemas/goals-schemas.d.ts +50 -50
- package/build/schemas/goals-schemas.js +4 -1
- package/build/schemas/goals-schemas.js.map +1 -1
- package/build/schemas/task-schemas.d.ts +382 -0
- package/build/schemas/task-schemas.js +115 -0
- package/build/schemas/task-schemas.js.map +1 -0
- package/build/schemas/time-tracking-schemas.d.ts +20 -20
- package/build/schemas/time-tracking-schemas.js +11 -10
- package/build/schemas/time-tracking-schemas.js.map +1 -1
- package/build/schemas/views-schemas.d.ts +2 -2
- package/build/schemas/views-schemas.js +9 -9
- package/build/schemas/views-schemas.js.map +1 -1
- package/build/schemas/webhook-schemas.js +3 -3
- package/build/schemas/webhook-schemas.js.map +1 -1
- package/build/tools/attachments-tools-setup.js +146 -65
- package/build/tools/attachments-tools-setup.js.map +1 -1
- package/build/tools/chat-tools.js +233 -106
- package/build/tools/chat-tools.js.map +1 -1
- package/build/tools/checklist-tools.js +13 -5
- package/build/tools/checklist-tools.js.map +1 -1
- package/build/tools/comment-tools.js +35 -14
- package/build/tools/comment-tools.js.map +1 -1
- package/build/tools/custom-field-tools.js +192 -67
- package/build/tools/custom-field-tools.js.map +1 -1
- package/build/tools/dependencies-tools-setup.js +133 -58
- package/build/tools/dependencies-tools-setup.js.map +1 -1
- package/build/tools/doc-tools-enhanced.js +153 -45
- package/build/tools/doc-tools-enhanced.js.map +1 -1
- package/build/tools/doc-tools.js +4 -1
- package/build/tools/doc-tools.js.map +1 -1
- package/build/tools/goals-tools.js +113 -41
- package/build/tools/goals-tools.js.map +1 -1
- package/build/tools/helper-tools.js +131 -53
- package/build/tools/helper-tools.js.map +1 -1
- package/build/tools/space-tools.js.map +1 -1
- package/build/tools/task-tools.js +501 -21
- package/build/tools/task-tools.js.map +1 -1
- package/build/tools/test-task-update.d.ts +2 -0
- package/build/tools/test-task-update.js +124 -0
- package/build/tools/test-task-update.js.map +1 -0
- package/build/tools/time-tracking-tools.js +105 -36
- package/build/tools/time-tracking-tools.js.map +1 -1
- package/build/tools/views-tools-setup.js +124 -61
- package/build/tools/views-tools-setup.js.map +1 -1
- package/build/tools/webhook-tools-setup.js +175 -72
- package/build/tools/webhook-tools-setup.js.map +1 -1
- package/build/tools/webhook-tools.js +51 -18
- package/build/tools/webhook-tools.js.map +1 -1
- package/build/utils/clickup-comment-formatter.js +55 -25
- package/build/utils/clickup-comment-formatter.js.map +1 -1
- package/build/utils/context-aware-suggestions.js +42 -22
- package/build/utils/context-aware-suggestions.js.map +1 -1
- package/build/utils/error-handling.js +29 -13
- package/build/utils/error-handling.js.map +1 -1
- package/build/utils/markdown-styling.js.map +1 -1
- package/build/utils/markdown.d.ts +5 -4
- package/build/utils/markdown.js +24 -19
- package/build/utils/markdown.js.map +1 -1
- package/build/utils/security.d.ts +76 -0
- package/build/utils/security.js +280 -25
- package/build/utils/security.js.map +1 -1
- package/build/utils/tool-efficiency.js +21 -12
- package/build/utils/tool-efficiency.js.map +1 -1
- package/package.json +5 -5
- package/LICENSE +0 -21
- package/README.md +0 -510
|
@@ -4,6 +4,7 @@ import { createTasksClient } from '../clickup-client/tasks.js';
|
|
|
4
4
|
import { createListsClient } from '../clickup-client/lists.js';
|
|
5
5
|
import { createFoldersClient } from '../clickup-client/folders.js';
|
|
6
6
|
import { createAuthClient } from '../clickup-client/auth.js';
|
|
7
|
+
import { BulkCreateTasksSchema, BulkUpdateTasksSchema, BulkCreateTaskItemSchema, BulkUpdateTaskItemSchema } from '../schemas/task-schemas.js';
|
|
7
8
|
// Create clients
|
|
8
9
|
const clickUpClient = createClickUpClient();
|
|
9
10
|
const tasksClient = createTasksClient(clickUpClient);
|
|
@@ -67,7 +68,10 @@ export function setupTaskTools(server) {
|
|
|
67
68
|
});
|
|
68
69
|
server.tool('clickup_get_task_details', 'Get detailed information about a specific ClickUp task. Returns comprehensive task data including description, assignees, status, and dates.', {
|
|
69
70
|
task_id: z.string().describe('The ID of the task to get'),
|
|
70
|
-
include_subtasks: z
|
|
71
|
+
include_subtasks: z
|
|
72
|
+
.boolean()
|
|
73
|
+
.optional()
|
|
74
|
+
.describe('Whether to include subtasks in the task details')
|
|
71
75
|
}, async ({ task_id, include_subtasks }) => {
|
|
72
76
|
try {
|
|
73
77
|
const task = await tasksClient.getTask(task_id, { include_subtasks });
|
|
@@ -86,20 +90,38 @@ export function setupTaskTools(server) {
|
|
|
86
90
|
server.tool('clickup_create_task', 'Create a new task in a ClickUp list with specified properties like name, description, assignees, status, and dates. Supports GitHub Flavored Markdown in description field.', {
|
|
87
91
|
list_id: z.string().describe('The ID of the list to create the task in'),
|
|
88
92
|
name: z.string().describe('The name of the task'),
|
|
89
|
-
description: z
|
|
90
|
-
|
|
93
|
+
description: z
|
|
94
|
+
.string()
|
|
95
|
+
.optional()
|
|
96
|
+
.describe('The description of the task (supports GitHub Flavored Markdown including headers, bold, italic, code blocks, links, lists, etc.)'),
|
|
97
|
+
markdown_content: z
|
|
98
|
+
.string()
|
|
99
|
+
.optional()
|
|
100
|
+
.describe('Raw markdown content for the task description (alternative to description field)'),
|
|
101
|
+
assignees: z
|
|
102
|
+
.array(z.number())
|
|
103
|
+
.optional()
|
|
104
|
+
.describe('The IDs of the users to assign to the task'),
|
|
91
105
|
tags: z.array(z.string()).optional().describe('The tags to add to the task'),
|
|
92
106
|
status: z.string().optional().describe('The status of the task'),
|
|
93
107
|
priority: z.number().optional().describe('The priority of the task (1-4)'),
|
|
94
108
|
due_date: z.number().optional().describe('The due date of the task (Unix timestamp)'),
|
|
95
109
|
due_date_time: z.boolean().optional().describe('Whether the due date includes a time'),
|
|
96
|
-
time_estimate: z
|
|
110
|
+
time_estimate: z
|
|
111
|
+
.number()
|
|
112
|
+
.optional()
|
|
113
|
+
.describe('The time estimate for the task (in milliseconds)'),
|
|
97
114
|
start_date: z.number().optional().describe('The start date of the task (Unix timestamp)'),
|
|
98
115
|
start_date_time: z.boolean().optional().describe('Whether the start date includes a time'),
|
|
99
116
|
notify_all: z.boolean().optional().describe('Whether to notify all assignees'),
|
|
100
117
|
parent: z.string().optional().describe('The ID of the parent task')
|
|
101
118
|
}, async ({ list_id, ...taskParams }) => {
|
|
102
119
|
try {
|
|
120
|
+
// If both description and markdown_content are provided, prefer markdown_content
|
|
121
|
+
if (taskParams.markdown_content && taskParams.description) {
|
|
122
|
+
console.warn('Both description and markdown_content provided. Using markdown_content.');
|
|
123
|
+
delete taskParams.description;
|
|
124
|
+
}
|
|
103
125
|
const result = await tasksClient.createTask(list_id, taskParams);
|
|
104
126
|
return {
|
|
105
127
|
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }]
|
|
@@ -113,21 +135,39 @@ export function setupTaskTools(server) {
|
|
|
113
135
|
};
|
|
114
136
|
}
|
|
115
137
|
});
|
|
116
|
-
server.tool('clickup_update_task',
|
|
138
|
+
server.tool('clickup_update_task', "Update an existing ClickUp task's properties including name, description, assignees, status, and dates. Supports GitHub Flavored Markdown in description field.", {
|
|
117
139
|
task_id: z.string().describe('The ID of the task to update'),
|
|
118
140
|
name: z.string().optional().describe('The new name of the task'),
|
|
119
|
-
description: z
|
|
120
|
-
|
|
141
|
+
description: z
|
|
142
|
+
.string()
|
|
143
|
+
.optional()
|
|
144
|
+
.describe('The new description of the task (supports GitHub Flavored Markdown including headers, bold, italic, code blocks, links, lists, etc.)'),
|
|
145
|
+
markdown_content: z
|
|
146
|
+
.string()
|
|
147
|
+
.optional()
|
|
148
|
+
.describe('Raw markdown content for the task description (alternative to description field)'),
|
|
149
|
+
assignees: z
|
|
150
|
+
.array(z.number())
|
|
151
|
+
.optional()
|
|
152
|
+
.describe('The IDs of the users to assign to the task'),
|
|
121
153
|
status: z.string().optional().describe('The new status of the task'),
|
|
122
154
|
priority: z.number().optional().describe('The new priority of the task (1-4)'),
|
|
123
155
|
due_date: z.number().optional().describe('The new due date of the task (Unix timestamp)'),
|
|
124
156
|
due_date_time: z.boolean().optional().describe('Whether the due date includes a time'),
|
|
125
|
-
time_estimate: z
|
|
157
|
+
time_estimate: z
|
|
158
|
+
.number()
|
|
159
|
+
.optional()
|
|
160
|
+
.describe('The new time estimate for the task (in milliseconds)'),
|
|
126
161
|
start_date: z.number().optional().describe('The new start date of the task (Unix timestamp)'),
|
|
127
162
|
start_date_time: z.boolean().optional().describe('Whether the start date includes a time'),
|
|
128
163
|
notify_all: z.boolean().optional().describe('Whether to notify all assignees')
|
|
129
164
|
}, async ({ task_id, ...taskParams }) => {
|
|
130
165
|
try {
|
|
166
|
+
// If both description and markdown_content are provided, prefer markdown_content
|
|
167
|
+
if (taskParams.markdown_content && taskParams.description) {
|
|
168
|
+
console.warn('Both description and markdown_content provided. Using markdown_content.');
|
|
169
|
+
delete taskParams.description;
|
|
170
|
+
}
|
|
131
171
|
const result = await tasksClient.updateTask(task_id, taskParams);
|
|
132
172
|
return {
|
|
133
173
|
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }]
|
|
@@ -143,7 +183,9 @@ export function setupTaskTools(server) {
|
|
|
143
183
|
});
|
|
144
184
|
// List and Folder tools
|
|
145
185
|
server.tool('clickup_get_lists', 'Get lists from a ClickUp folder or space. Returns list details including name and content.', {
|
|
146
|
-
container_type: z
|
|
186
|
+
container_type: z
|
|
187
|
+
.enum(['folder', 'space'])
|
|
188
|
+
.describe('The type of container to get lists from'),
|
|
147
189
|
container_id: z.string().describe('The ID of the container to get lists from')
|
|
148
190
|
}, async ({ container_type, container_id }) => {
|
|
149
191
|
try {
|
|
@@ -187,7 +229,7 @@ export function setupTaskTools(server) {
|
|
|
187
229
|
};
|
|
188
230
|
}
|
|
189
231
|
});
|
|
190
|
-
server.tool('clickup_update_folder',
|
|
232
|
+
server.tool('clickup_update_folder', "Update an existing ClickUp folder's name.", {
|
|
191
233
|
folder_id: z.string().describe('The ID of the folder to update'),
|
|
192
234
|
name: z.string().describe('The new name of the folder')
|
|
193
235
|
}, async ({ folder_id, name }) => {
|
|
@@ -240,7 +282,9 @@ export function setupTaskTools(server) {
|
|
|
240
282
|
}
|
|
241
283
|
});
|
|
242
284
|
server.tool('clickup_create_list', 'Create a new list in a ClickUp folder or space with the specified name.', {
|
|
243
|
-
container_type: z
|
|
285
|
+
container_type: z
|
|
286
|
+
.enum(['folder', 'space'])
|
|
287
|
+
.describe('The type of container to create the list in'),
|
|
244
288
|
container_id: z.string().describe('The ID of the container to create the list in'),
|
|
245
289
|
name: z.string().describe('The name of the list')
|
|
246
290
|
}, async ({ container_type, container_id, name }) => {
|
|
@@ -302,7 +346,7 @@ export function setupTaskTools(server) {
|
|
|
302
346
|
};
|
|
303
347
|
}
|
|
304
348
|
});
|
|
305
|
-
server.tool('clickup_update_list',
|
|
349
|
+
server.tool('clickup_update_list', "Update an existing ClickUp list's name.", {
|
|
306
350
|
list_id: z.string().describe('The ID of the list to update'),
|
|
307
351
|
name: z.string().describe('The new name of the list')
|
|
308
352
|
}, async ({ list_id, name }) => {
|
|
@@ -320,13 +364,35 @@ export function setupTaskTools(server) {
|
|
|
320
364
|
};
|
|
321
365
|
}
|
|
322
366
|
});
|
|
323
|
-
server.tool('clickup_delete_list', 'Delete a list from ClickUp.
|
|
324
|
-
list_id: z.string().describe('The ID of the list to delete')
|
|
325
|
-
|
|
367
|
+
server.tool('clickup_delete_list', '⚠️ DESTRUCTIVE: Delete a list from ClickUp. This action cannot be undone and will permanently remove the list and all its tasks.', {
|
|
368
|
+
list_id: z.string().describe('The ID of the list to delete'),
|
|
369
|
+
confirm_deletion: z
|
|
370
|
+
.boolean()
|
|
371
|
+
.describe('Confirmation that you want to permanently delete this list and all its tasks (must be true)')
|
|
372
|
+
}, async ({ list_id, confirm_deletion }) => {
|
|
326
373
|
try {
|
|
327
|
-
|
|
374
|
+
if (!confirm_deletion) {
|
|
375
|
+
return {
|
|
376
|
+
content: [
|
|
377
|
+
{
|
|
378
|
+
type: 'text',
|
|
379
|
+
text: '❌ List deletion cancelled. You must set confirm_deletion to true to proceed with this destructive operation.'
|
|
380
|
+
}
|
|
381
|
+
],
|
|
382
|
+
isError: true
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
// Get list details first for confirmation message
|
|
386
|
+
const listDetails = await listsClient.getList(list_id);
|
|
387
|
+
await listsClient.deleteList(list_id);
|
|
328
388
|
return {
|
|
329
|
-
content: [
|
|
389
|
+
content: [
|
|
390
|
+
{
|
|
391
|
+
type: 'text',
|
|
392
|
+
text: `✅ List "${listDetails.name}" (ID: ${list_id}) has been permanently deleted.\n\n` +
|
|
393
|
+
'⚠️ This action cannot be undone. The list and all its tasks have been removed from ClickUp.'
|
|
394
|
+
}
|
|
395
|
+
]
|
|
330
396
|
};
|
|
331
397
|
}
|
|
332
398
|
catch (error) {
|
|
@@ -373,13 +439,421 @@ export function setupTaskTools(server) {
|
|
|
373
439
|
};
|
|
374
440
|
}
|
|
375
441
|
});
|
|
442
|
+
server.tool('clickup_bulk_create_tasks', 'Create multiple tasks in a ClickUp list in a single operation. More efficient than creating tasks individually. ' +
|
|
443
|
+
'Supports up to 50 tasks per request.', {
|
|
444
|
+
list_id: z.string().min(1).describe('The ID of the list to create tasks in'),
|
|
445
|
+
tasks: z
|
|
446
|
+
.array(BulkCreateTaskItemSchema)
|
|
447
|
+
.min(1)
|
|
448
|
+
.max(50)
|
|
449
|
+
.describe('Array of tasks to create (maximum 50 tasks per request)'),
|
|
450
|
+
continue_on_error: z
|
|
451
|
+
.boolean()
|
|
452
|
+
.default(false)
|
|
453
|
+
.describe('Whether to continue creating remaining tasks if one fails')
|
|
454
|
+
}, async ({ list_id, tasks, continue_on_error }) => {
|
|
455
|
+
try {
|
|
456
|
+
const validatedData = BulkCreateTasksSchema.parse({ list_id, tasks, continue_on_error });
|
|
457
|
+
// Convert tasks to CreateTaskParams format
|
|
458
|
+
const taskParams = validatedData.tasks.map(task => {
|
|
459
|
+
// Handle markdown content preference
|
|
460
|
+
if (task.markdown_content && task.description) {
|
|
461
|
+
console.warn('Both description and markdown_content provided for a task. Using markdown_content.');
|
|
462
|
+
const { ...rest } = task;
|
|
463
|
+
return rest;
|
|
464
|
+
}
|
|
465
|
+
return task;
|
|
466
|
+
});
|
|
467
|
+
const result = await tasksClient.bulkCreateTasks(validatedData.list_id, taskParams, validatedData.continue_on_error);
|
|
468
|
+
return {
|
|
469
|
+
content: [
|
|
470
|
+
{
|
|
471
|
+
type: 'text',
|
|
472
|
+
text: 'Bulk task creation completed!\n\n' +
|
|
473
|
+
`✅ Successfully created: ${result.success_count} tasks\n` +
|
|
474
|
+
`❌ Failed: ${result.error_count} tasks\n` +
|
|
475
|
+
`📊 Total: ${result.total_count} tasks\n` +
|
|
476
|
+
`⏱️ Execution time: ${result.execution_time_ms}ms\n\n` +
|
|
477
|
+
`Detailed Results:\n${JSON.stringify(result.results, null, 2)}`
|
|
478
|
+
}
|
|
479
|
+
]
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
catch (error) {
|
|
483
|
+
console.error('Error in bulk task creation:', error);
|
|
484
|
+
return {
|
|
485
|
+
content: [
|
|
486
|
+
{
|
|
487
|
+
type: 'text',
|
|
488
|
+
text: `Error in bulk task creation: ${error.message}`
|
|
489
|
+
}
|
|
490
|
+
],
|
|
491
|
+
isError: true
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
server.tool('clickup_bulk_update_tasks', 'Update multiple tasks in ClickUp in a single operation. More efficient than updating tasks individually. ' +
|
|
496
|
+
'Supports up to 50 tasks per request.', {
|
|
497
|
+
tasks: z
|
|
498
|
+
.array(BulkUpdateTaskItemSchema)
|
|
499
|
+
.min(1)
|
|
500
|
+
.max(50)
|
|
501
|
+
.describe('Array of task updates to perform (maximum 50 tasks per request)'),
|
|
502
|
+
continue_on_error: z
|
|
503
|
+
.boolean()
|
|
504
|
+
.default(false)
|
|
505
|
+
.describe('Whether to continue updating remaining tasks if one fails')
|
|
506
|
+
}, async ({ tasks, continue_on_error }) => {
|
|
507
|
+
try {
|
|
508
|
+
const validatedData = BulkUpdateTasksSchema.parse({ tasks, continue_on_error });
|
|
509
|
+
// Convert tasks to the format expected by bulkUpdateTasks
|
|
510
|
+
const taskUpdates = validatedData.tasks.map(task => {
|
|
511
|
+
// Handle markdown content preference
|
|
512
|
+
if (task.markdown_content && task.description) {
|
|
513
|
+
console.warn('Both description and markdown_content provided for a task. Using markdown_content.');
|
|
514
|
+
const { ...rest } = task;
|
|
515
|
+
return rest;
|
|
516
|
+
}
|
|
517
|
+
return task;
|
|
518
|
+
});
|
|
519
|
+
const result = await tasksClient.bulkUpdateTasks(taskUpdates, validatedData.continue_on_error);
|
|
520
|
+
return {
|
|
521
|
+
content: [
|
|
522
|
+
{
|
|
523
|
+
type: 'text',
|
|
524
|
+
text: 'Bulk task update completed!\n\n' +
|
|
525
|
+
`✅ Successfully updated: ${result.success_count} tasks\n` +
|
|
526
|
+
`❌ Failed: ${result.error_count} tasks\n` +
|
|
527
|
+
`📊 Total: ${result.total_count} tasks\n` +
|
|
528
|
+
`⏱️ Execution time: ${result.execution_time_ms}ms\n\n` +
|
|
529
|
+
`Detailed Results:\n${JSON.stringify(result.results, null, 2)}`
|
|
530
|
+
}
|
|
531
|
+
]
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
catch (error) {
|
|
535
|
+
console.error('Error in bulk task update:', error);
|
|
536
|
+
return {
|
|
537
|
+
content: [
|
|
538
|
+
{
|
|
539
|
+
type: 'text',
|
|
540
|
+
text: `Error in bulk task update: ${error.message}`
|
|
541
|
+
}
|
|
542
|
+
],
|
|
543
|
+
isError: true
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
server.tool('clickup_delete_task', '⚠️ DESTRUCTIVE: Delete a task from ClickUp. This action cannot be undone and will permanently remove the task and all its data.', {
|
|
548
|
+
task_id: z.string().min(1).describe('The ID of the task to delete'),
|
|
549
|
+
confirm_deletion: z
|
|
550
|
+
.boolean()
|
|
551
|
+
.describe('Confirmation that you want to permanently delete this task (must be true)')
|
|
552
|
+
}, async ({ task_id, confirm_deletion }) => {
|
|
553
|
+
try {
|
|
554
|
+
if (!confirm_deletion) {
|
|
555
|
+
return {
|
|
556
|
+
content: [
|
|
557
|
+
{
|
|
558
|
+
type: 'text',
|
|
559
|
+
text: '❌ Task deletion cancelled. You must set confirm_deletion to true to proceed with this destructive operation.'
|
|
560
|
+
}
|
|
561
|
+
],
|
|
562
|
+
isError: true
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
// Get task details first for confirmation message
|
|
566
|
+
const taskDetails = await tasksClient.getTask(task_id);
|
|
567
|
+
await tasksClient.deleteTask(task_id);
|
|
568
|
+
return {
|
|
569
|
+
content: [
|
|
570
|
+
{
|
|
571
|
+
type: 'text',
|
|
572
|
+
text: `✅ Task "${taskDetails.name}" (ID: ${task_id}) has been permanently deleted.\n\n` +
|
|
573
|
+
'⚠️ This action cannot be undone. The task and all its data have been removed from ClickUp.'
|
|
574
|
+
}
|
|
575
|
+
]
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
catch (error) {
|
|
579
|
+
console.error('Error deleting task:', error);
|
|
580
|
+
return {
|
|
581
|
+
content: [
|
|
582
|
+
{
|
|
583
|
+
type: 'text',
|
|
584
|
+
text: `Error deleting task: ${error.message}`
|
|
585
|
+
}
|
|
586
|
+
],
|
|
587
|
+
isError: true
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
});
|
|
591
|
+
server.tool('clickup_bulk_delete_tasks', '⚠️ DESTRUCTIVE: Delete multiple tasks from ClickUp in a single operation. This action cannot be undone and will permanently remove all specified tasks.', {
|
|
592
|
+
task_ids: z
|
|
593
|
+
.array(z.string().min(1))
|
|
594
|
+
.min(1)
|
|
595
|
+
.max(50)
|
|
596
|
+
.describe('Array of task IDs to delete (maximum 50 tasks per request)'),
|
|
597
|
+
confirm_deletion: z
|
|
598
|
+
.boolean()
|
|
599
|
+
.describe('Confirmation that you want to permanently delete these tasks (must be true)'),
|
|
600
|
+
continue_on_error: z
|
|
601
|
+
.boolean()
|
|
602
|
+
.default(false)
|
|
603
|
+
.describe('Whether to continue deleting remaining tasks if one fails')
|
|
604
|
+
}, async ({ task_ids, confirm_deletion, continue_on_error }) => {
|
|
605
|
+
try {
|
|
606
|
+
if (!confirm_deletion) {
|
|
607
|
+
return {
|
|
608
|
+
content: [
|
|
609
|
+
{
|
|
610
|
+
type: 'text',
|
|
611
|
+
text: '❌ Bulk task deletion cancelled. You must set confirm_deletion to true to proceed with this destructive operation.'
|
|
612
|
+
}
|
|
613
|
+
],
|
|
614
|
+
isError: true
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
const startTime = Date.now();
|
|
618
|
+
const results = [];
|
|
619
|
+
let successCount = 0;
|
|
620
|
+
let errorCount = 0;
|
|
621
|
+
for (let i = 0; i < task_ids.length; i++) {
|
|
622
|
+
try {
|
|
623
|
+
const taskId = task_ids[i];
|
|
624
|
+
// Get task name for confirmation
|
|
625
|
+
const taskDetails = await tasksClient.getTask(taskId);
|
|
626
|
+
await tasksClient.deleteTask(taskId);
|
|
627
|
+
results.push({
|
|
628
|
+
success: true,
|
|
629
|
+
task_id: taskId,
|
|
630
|
+
task_name: taskDetails.name,
|
|
631
|
+
index: i
|
|
632
|
+
});
|
|
633
|
+
successCount++;
|
|
634
|
+
}
|
|
635
|
+
catch (error) {
|
|
636
|
+
const errorMessage = error.message || 'Unknown error occurred';
|
|
637
|
+
results.push({
|
|
638
|
+
success: false,
|
|
639
|
+
task_id: task_ids[i],
|
|
640
|
+
error: errorMessage,
|
|
641
|
+
index: i
|
|
642
|
+
});
|
|
643
|
+
errorCount++;
|
|
644
|
+
if (!continue_on_error) {
|
|
645
|
+
// Add remaining tasks as failed
|
|
646
|
+
for (let j = i + 1; j < task_ids.length; j++) {
|
|
647
|
+
results.push({
|
|
648
|
+
success: false,
|
|
649
|
+
task_id: task_ids[j],
|
|
650
|
+
error: 'Skipped due to previous error',
|
|
651
|
+
index: j
|
|
652
|
+
});
|
|
653
|
+
errorCount++;
|
|
654
|
+
}
|
|
655
|
+
break;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
const executionTime = Date.now() - startTime;
|
|
660
|
+
return {
|
|
661
|
+
content: [
|
|
662
|
+
{
|
|
663
|
+
type: 'text',
|
|
664
|
+
text: '⚠️ Bulk task deletion completed!\n\n' +
|
|
665
|
+
`✅ Successfully deleted: ${successCount} tasks\n` +
|
|
666
|
+
`❌ Failed: ${errorCount} tasks\n` +
|
|
667
|
+
`📊 Total: ${task_ids.length} tasks\n` +
|
|
668
|
+
`⏱️ Execution time: ${executionTime}ms\n\n` +
|
|
669
|
+
'⚠️ This action cannot be undone. All successfully deleted tasks have been permanently removed.\n\n' +
|
|
670
|
+
`Detailed Results:\n${JSON.stringify(results, null, 2)}`
|
|
671
|
+
}
|
|
672
|
+
]
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
catch (error) {
|
|
676
|
+
console.error('Error in bulk task deletion:', error);
|
|
677
|
+
return {
|
|
678
|
+
content: [
|
|
679
|
+
{
|
|
680
|
+
type: 'text',
|
|
681
|
+
text: `Error in bulk task deletion: ${error.message}`
|
|
682
|
+
}
|
|
683
|
+
],
|
|
684
|
+
isError: true
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
});
|
|
688
|
+
server.tool('clickup_delete_subtask', '⚠️ DESTRUCTIVE: Delete a subtask from ClickUp. This action cannot be undone and will permanently remove the subtask.', {
|
|
689
|
+
task_id: z.string().min(1).describe('The ID of the subtask to delete'),
|
|
690
|
+
confirm_deletion: z
|
|
691
|
+
.boolean()
|
|
692
|
+
.describe('Confirmation that you want to permanently delete this subtask (must be true)')
|
|
693
|
+
}, async ({ task_id, confirm_deletion }) => {
|
|
694
|
+
try {
|
|
695
|
+
if (!confirm_deletion) {
|
|
696
|
+
return {
|
|
697
|
+
content: [
|
|
698
|
+
{
|
|
699
|
+
type: 'text',
|
|
700
|
+
text: '❌ Subtask deletion cancelled. You must set confirm_deletion to true to proceed with this destructive operation.'
|
|
701
|
+
}
|
|
702
|
+
],
|
|
703
|
+
isError: true
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
// Get subtask details first for confirmation message
|
|
707
|
+
const subtaskDetails = await tasksClient.getTask(task_id);
|
|
708
|
+
await tasksClient.deleteTask(task_id);
|
|
709
|
+
return {
|
|
710
|
+
content: [
|
|
711
|
+
{
|
|
712
|
+
type: 'text',
|
|
713
|
+
text: `✅ Subtask "${subtaskDetails.name}" (ID: ${task_id}) has been permanently deleted.\n\n` +
|
|
714
|
+
'⚠️ This action cannot be undone. The subtask and all its data have been removed from ClickUp.'
|
|
715
|
+
}
|
|
716
|
+
]
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
catch (error) {
|
|
720
|
+
console.error('Error deleting subtask:', error);
|
|
721
|
+
return {
|
|
722
|
+
content: [
|
|
723
|
+
{
|
|
724
|
+
type: 'text',
|
|
725
|
+
text: `Error deleting subtask: ${error.message}`
|
|
726
|
+
}
|
|
727
|
+
],
|
|
728
|
+
isError: true
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
});
|
|
732
|
+
server.tool('clickup_merge_tasks', 'Merge multiple tasks into a single task. The primary task will retain all data, and secondary tasks will be deleted after merging their content.', {
|
|
733
|
+
primary_task_id: z
|
|
734
|
+
.string()
|
|
735
|
+
.min(1)
|
|
736
|
+
.describe('The ID of the task that will remain after merging (receives all merged content)'),
|
|
737
|
+
secondary_task_ids: z
|
|
738
|
+
.array(z.string().min(1))
|
|
739
|
+
.min(1)
|
|
740
|
+
.max(10)
|
|
741
|
+
.describe('Array of task IDs to merge into the primary task (maximum 10 tasks, will be deleted after merge)'),
|
|
742
|
+
merge_descriptions: z
|
|
743
|
+
.boolean()
|
|
744
|
+
.default(true)
|
|
745
|
+
.describe('Whether to merge task descriptions into the primary task'),
|
|
746
|
+
merge_comments: z
|
|
747
|
+
.boolean()
|
|
748
|
+
.default(true)
|
|
749
|
+
.describe('Whether to merge comments from secondary tasks'),
|
|
750
|
+
merge_attachments: z
|
|
751
|
+
.boolean()
|
|
752
|
+
.default(true)
|
|
753
|
+
.describe('Whether to merge attachments from secondary tasks'),
|
|
754
|
+
merge_time_tracking: z
|
|
755
|
+
.boolean()
|
|
756
|
+
.default(true)
|
|
757
|
+
.describe('Whether to merge time tracking data'),
|
|
758
|
+
confirm_merge: z
|
|
759
|
+
.boolean()
|
|
760
|
+
.describe('Confirmation that you want to merge these tasks (secondary tasks will be deleted)')
|
|
761
|
+
}, async ({ primary_task_id, secondary_task_ids, merge_descriptions, merge_comments: _merge_comments, merge_attachments: _merge_attachments, merge_time_tracking: _merge_time_tracking, confirm_merge }) => {
|
|
762
|
+
try {
|
|
763
|
+
if (!confirm_merge) {
|
|
764
|
+
return {
|
|
765
|
+
content: [
|
|
766
|
+
{
|
|
767
|
+
type: 'text',
|
|
768
|
+
text: '❌ Task merge cancelled. You must set confirm_merge to true to proceed. Secondary tasks will be deleted after merging.'
|
|
769
|
+
}
|
|
770
|
+
],
|
|
771
|
+
isError: true
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
// Get all task details first
|
|
775
|
+
const primaryTask = await tasksClient.getTask(primary_task_id);
|
|
776
|
+
const secondaryTasks = await Promise.all(secondary_task_ids.map(id => tasksClient.getTask(id)));
|
|
777
|
+
let mergedDescription = primaryTask.description || '';
|
|
778
|
+
const mergeResults = {
|
|
779
|
+
primary_task: primaryTask.name,
|
|
780
|
+
merged_tasks: [],
|
|
781
|
+
merged_content: {
|
|
782
|
+
descriptions: 0,
|
|
783
|
+
comments: 0,
|
|
784
|
+
attachments: 0,
|
|
785
|
+
time_entries: 0
|
|
786
|
+
}
|
|
787
|
+
};
|
|
788
|
+
// Merge descriptions
|
|
789
|
+
if (merge_descriptions) {
|
|
790
|
+
for (const task of secondaryTasks) {
|
|
791
|
+
if (task.description) {
|
|
792
|
+
mergedDescription += `\n\n---\n**Merged from "${task.name}":**\n${task.description}`;
|
|
793
|
+
mergeResults.merged_content.descriptions++;
|
|
794
|
+
}
|
|
795
|
+
mergeResults.merged_tasks.push(task.name);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
// Update primary task with merged description
|
|
799
|
+
if (merge_descriptions && mergedDescription !== primaryTask.description) {
|
|
800
|
+
await tasksClient.updateTask(primary_task_id, {
|
|
801
|
+
description: mergedDescription
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
// TODO: Implement comment, attachment, and time tracking merging
|
|
805
|
+
// This would require additional API calls to get and move these items
|
|
806
|
+
// Delete secondary tasks
|
|
807
|
+
const deletionResults = [];
|
|
808
|
+
for (const taskId of secondary_task_ids) {
|
|
809
|
+
try {
|
|
810
|
+
await tasksClient.deleteTask(taskId);
|
|
811
|
+
deletionResults.push({ task_id: taskId, deleted: true });
|
|
812
|
+
}
|
|
813
|
+
catch (error) {
|
|
814
|
+
deletionResults.push({ task_id: taskId, deleted: false, error: error.message });
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
return {
|
|
818
|
+
content: [
|
|
819
|
+
{
|
|
820
|
+
type: 'text',
|
|
821
|
+
text: '✅ Task merge completed!\n\n' +
|
|
822
|
+
`Primary Task: "${primaryTask.name}" (${primary_task_id})\n` +
|
|
823
|
+
`Merged Tasks: ${mergeResults.merged_tasks.join(', ')}\n\n` +
|
|
824
|
+
'Merged Content:\n' +
|
|
825
|
+
`- Descriptions: ${mergeResults.merged_content.descriptions}\n` +
|
|
826
|
+
`- Comments: ${mergeResults.merged_content.comments} (not yet implemented)\n` +
|
|
827
|
+
`- Attachments: ${mergeResults.merged_content.attachments} (not yet implemented)\n` +
|
|
828
|
+
`- Time Entries: ${mergeResults.merged_content.time_entries} (not yet implemented)\n\n` +
|
|
829
|
+
`Deletion Results:\n${JSON.stringify(deletionResults, null, 2)}\n\n` +
|
|
830
|
+
'⚠️ Secondary tasks have been permanently deleted and cannot be recovered.'
|
|
831
|
+
}
|
|
832
|
+
]
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
catch (error) {
|
|
836
|
+
console.error('Error merging tasks:', error);
|
|
837
|
+
return {
|
|
838
|
+
content: [
|
|
839
|
+
{
|
|
840
|
+
type: 'text',
|
|
841
|
+
text: `Error merging tasks: ${error.message}`
|
|
842
|
+
}
|
|
843
|
+
],
|
|
844
|
+
isError: true
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
});
|
|
376
848
|
server.tool('clickup_create_list_from_template_in_folder', 'Create a new list in a ClickUp folder using an existing template.', {
|
|
377
849
|
folder_id: z.string().describe('The ID of the folder to create the list in'),
|
|
378
850
|
template_id: z.string().describe('The ID of the template to use'),
|
|
379
851
|
name: z.string().describe('The name of the list')
|
|
380
852
|
}, async ({ folder_id, template_id, name }) => {
|
|
381
853
|
try {
|
|
382
|
-
const result = await listsClient.createListFromTemplateInFolder(folder_id, template_id, {
|
|
854
|
+
const result = await listsClient.createListFromTemplateInFolder(folder_id, template_id, {
|
|
855
|
+
name
|
|
856
|
+
});
|
|
383
857
|
return {
|
|
384
858
|
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }]
|
|
385
859
|
};
|
|
@@ -387,7 +861,9 @@ export function setupTaskTools(server) {
|
|
|
387
861
|
catch (error) {
|
|
388
862
|
console.error('Error creating list from template in folder:', error);
|
|
389
863
|
return {
|
|
390
|
-
content: [
|
|
864
|
+
content: [
|
|
865
|
+
{ type: 'text', text: `Error creating list from template in folder: ${error.message}` }
|
|
866
|
+
],
|
|
391
867
|
isError: true
|
|
392
868
|
};
|
|
393
869
|
}
|
|
@@ -398,7 +874,9 @@ export function setupTaskTools(server) {
|
|
|
398
874
|
name: z.string().describe('The name of the list')
|
|
399
875
|
}, async ({ space_id, template_id, name }) => {
|
|
400
876
|
try {
|
|
401
|
-
const result = await listsClient.createListFromTemplateInSpace(space_id, template_id, {
|
|
877
|
+
const result = await listsClient.createListFromTemplateInSpace(space_id, template_id, {
|
|
878
|
+
name
|
|
879
|
+
});
|
|
402
880
|
return {
|
|
403
881
|
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }]
|
|
404
882
|
};
|
|
@@ -406,7 +884,9 @@ export function setupTaskTools(server) {
|
|
|
406
884
|
catch (error) {
|
|
407
885
|
console.error('Error creating list from template in space:', error);
|
|
408
886
|
return {
|
|
409
|
-
content: [
|
|
887
|
+
content: [
|
|
888
|
+
{ type: 'text', text: `Error creating list from template in space: ${error.message}` }
|
|
889
|
+
],
|
|
410
890
|
isError: true
|
|
411
891
|
};
|
|
412
892
|
}
|