@taazkareem/clickup-mcp-server 0.4.58 → 0.4.60

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/README.md CHANGED
@@ -38,6 +38,7 @@ npx -y @taazkareem/clickup-mcp-server \
38
38
  - Full CRUD operations for workspace components
39
39
  - Efficient path-based navigation
40
40
 
41
+
41
42
  - 🔄 **Integration Features**
42
43
  - Name or ID-based item lookup
43
44
  - Case-insensitive name matching
@@ -60,7 +61,7 @@ npx -y @taazkareem/clickup-mcp-server \
60
61
  | [update_task](docs/api-reference.md#task-management) | Modify task | `taskId`/`taskName` |
61
62
  | [get_tasks](docs/api-reference.md#task-retrieval) | Get tasks from list | `listId`/`listName` |
62
63
  | [get_task](docs/api-reference.md#task-retrieval) | Get task details | `taskId`/`taskName` |
63
- | [delete_task](docs/api-reference.md#task-management) | Remove task | `taskId` |
64
+ | [delete_task](docs/api-reference.md#task-management) | Remove task | `taskId`/`taskName` |
64
65
  | [move_task](docs/api-reference.md#task-management) | Move task | `taskId`/`taskName`, `listId`/`listName` |
65
66
  | [duplicate_task](docs/api-reference.md#task-management) | Copy task | `taskId`/`taskName`, `listId`/`listName` |
66
67
  | [create_list](docs/api-reference.md#list-management) | Create list in space | `name`, `spaceId`/`spaceName` |
package/build/index.js CHANGED
@@ -109,11 +109,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
109
109
  description: "Due date of the task (Unix timestamp in milliseconds). Convert dates to this format before submitting."
110
110
  }
111
111
  },
112
- required: ["name"],
113
- oneOf: [
114
- { required: ["listId"] },
115
- { required: ["listName"] }
116
- ]
112
+ required: ["name"]
117
113
  }
118
114
  },
119
115
  {
@@ -168,15 +164,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
168
164
  description: "Array of user IDs to assign to the task"
169
165
  }
170
166
  },
171
- required: ["name"]
167
+ required: []
172
168
  }
173
169
  }
174
170
  },
175
- required: ["tasks"],
176
- oneOf: [
177
- { required: ["listId"] },
178
- { required: ["listName"] }
179
- ]
171
+ required: ["tasks"]
180
172
  }
181
173
  },
182
174
  {
@@ -187,11 +179,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
187
179
  properties: {
188
180
  spaceId: {
189
181
  type: "string",
190
- description: "ID of the space to create the list in (required if not using folderId). If you have this ID from a previous response, use it directly rather than looking up by name."
182
+ description: "ID of the space to create the list in (optional if using spaceName instead). If you have this ID from a previous response, use it directly rather than looking up by name."
191
183
  },
192
- folderId: {
184
+ spaceName: {
193
185
  type: "string",
194
- description: "ID of the folder to create the list in (required if not using spaceId). If you have this ID from a previous response, use it directly rather than looking up by name."
186
+ description: "Name of the space to create the list in - will automatically find the space by name (optional if using spaceId instead). Only use this if you don't already have the space ID from previous responses."
195
187
  },
196
188
  name: {
197
189
  type: "string",
@@ -201,34 +193,24 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
201
193
  type: "string",
202
194
  description: "Description or content of the list"
203
195
  },
204
- assignee: {
205
- type: "number",
206
- description: "User ID to assign the list to"
196
+ dueDate: {
197
+ type: "string",
198
+ description: "Due date for the list (Unix timestamp in milliseconds). Convert dates to this format before submitting."
207
199
  },
208
200
  priority: {
209
201
  type: "number",
210
202
  description: "Priority of the list (1-4), where 1 is urgent/highest priority and 4 is lowest priority. Only set when explicitly requested."
211
203
  },
212
- dueDate: {
213
- type: "string",
214
- description: "Due date for the list (Unix timestamp in milliseconds). Convert dates to this format before submitting."
204
+ assignee: {
205
+ type: "number",
206
+ description: "User ID to assign the list to"
215
207
  },
216
208
  status: {
217
209
  type: "string",
218
210
  description: "Status of the list"
219
211
  }
220
212
  },
221
- allOf: [
222
- {
223
- oneOf: [
224
- { required: ["spaceId"] },
225
- { required: ["folderId"] }
226
- ]
227
- },
228
- {
229
- required: ["name"]
230
- }
231
- ]
213
+ required: ["name"]
232
214
  }
233
215
  },
234
216
  {
@@ -254,11 +236,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
254
236
  description: "Whether to override space statuses with folder-specific statuses"
255
237
  }
256
238
  },
257
- required: ["name"],
258
- oneOf: [
259
- { required: ["spaceId"] },
260
- { required: ["spaceName"] }
261
- ]
239
+ required: ["name"]
262
240
  }
263
241
  },
264
242
  {
@@ -267,6 +245,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
267
245
  inputSchema: {
268
246
  type: "object",
269
247
  properties: {
248
+ name: {
249
+ type: "string",
250
+ description: "Name of the list"
251
+ },
270
252
  folderId: {
271
253
  type: "string",
272
254
  description: "ID of the folder to create the list in (optional if using folderName instead). If you have this ID from a previous response, use it directly rather than looking up by name."
@@ -283,10 +265,6 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
283
265
  type: "string",
284
266
  description: "Name of the space containing the folder - will automatically find the space by name (optional if using spaceId instead). Only use this if you don't already have the space ID from previous responses."
285
267
  },
286
- name: {
287
- type: "string",
288
- description: "Name of the list"
289
- },
290
268
  content: {
291
269
  type: "string",
292
270
  description: "Description or content of the list"
@@ -296,12 +274,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
296
274
  description: "Status of the list (uses folder default if not specified)"
297
275
  }
298
276
  },
299
- required: ["name"],
300
- oneOf: [
301
- { required: ["folderId"] },
302
- { required: ["folderName", "spaceId"] },
303
- { required: ["folderName", "spaceName"] }
304
- ]
277
+ required: ["name"]
305
278
  }
306
279
  },
307
280
  {
@@ -331,20 +304,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
331
304
  description: "Name of the destination list - will automatically find the list by name (optional if using listId instead). Only use this if you don't already have the list ID from previous responses."
332
305
  }
333
306
  },
334
- allOf: [
335
- {
336
- oneOf: [
337
- { required: ["taskId"] },
338
- { required: ["taskName"] }
339
- ]
340
- },
341
- {
342
- oneOf: [
343
- { required: ["listId"] },
344
- { required: ["listName"] }
345
- ]
346
- }
347
- ]
307
+ required: []
348
308
  }
349
309
  },
350
310
  {
@@ -374,20 +334,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
374
334
  description: "Name of the list to create the duplicate in - will automatically find the list by name (optional if using listId instead). Only use this if you don't already have the list ID from previous responses."
375
335
  }
376
336
  },
377
- allOf: [
378
- {
379
- oneOf: [
380
- { required: ["taskId"] },
381
- { required: ["taskName"] }
382
- ]
383
- },
384
- {
385
- oneOf: [
386
- { required: ["listId"] },
387
- { required: ["listName"] }
388
- ]
389
- }
390
- ]
337
+ required: []
391
338
  }
392
339
  },
393
340
  {
@@ -431,10 +378,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
431
378
  optional: true
432
379
  }
433
380
  },
434
- oneOf: [
435
- { required: ["taskId"] },
436
- { required: ["taskName"] }
437
- ]
381
+ required: []
438
382
  }
439
383
  },
440
384
  {
@@ -514,10 +458,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
514
458
  description: "Object with custom field IDs as keys and desired values for filtering"
515
459
  }
516
460
  },
517
- oneOf: [
518
- { required: ["listId"] },
519
- { required: ["listName"] }
520
- ]
461
+ required: []
521
462
  }
522
463
  },
523
464
  {
@@ -539,10 +480,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
539
480
  description: "Optional: Name of the list to narrow down task search when multiple tasks have the same name"
540
481
  }
541
482
  },
542
- oneOf: [
543
- { required: ["taskId"] },
544
- { required: ["taskName"] }
545
- ]
483
+ required: []
546
484
  }
547
485
  },
548
486
  {
@@ -564,7 +502,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
564
502
  description: "Optional: Name of the list to narrow down task search when multiple tasks have the same name"
565
503
  }
566
504
  },
567
- required: ["taskId"]
505
+ required: []
568
506
  }
569
507
  },
570
508
  {
@@ -590,11 +528,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
590
528
  description: "Name of the space containing the folder (optional if using spaceId instead, and only needed when using folderName). Only use this if you don't already have the space ID from previous responses."
591
529
  }
592
530
  },
593
- oneOf: [
594
- { required: ["folderId"] },
595
- { required: ["folderName", "spaceId"] },
596
- { required: ["folderName", "spaceName"] }
597
- ]
531
+ required: []
598
532
  }
599
533
  },
600
534
  {
@@ -628,11 +562,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
628
562
  description: "Whether to override space statuses with folder-specific statuses"
629
563
  }
630
564
  },
631
- oneOf: [
632
- { required: ["folderId"] },
633
- { required: ["folderName", "spaceId"] },
634
- { required: ["folderName", "spaceName"] }
635
- ]
565
+ required: []
636
566
  }
637
567
  },
638
568
  {
@@ -658,11 +588,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
658
588
  description: "Name of the space containing the folder (optional if using spaceId instead, and only needed when using folderName). Only use this if you don't already have the space ID from previous responses."
659
589
  }
660
590
  },
661
- oneOf: [
662
- { required: ["folderId"] },
663
- { required: ["folderName", "spaceId"] },
664
- { required: ["folderName", "spaceName"] }
665
- ]
591
+ required: []
666
592
  }
667
593
  },
668
594
  {
@@ -680,10 +606,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
680
606
  description: "Name of the list to retrieve - will automatically find the list by name (optional if using listId instead). Only use this if you don't already have the list ID from previous responses."
681
607
  }
682
608
  },
683
- oneOf: [
684
- { required: ["listId"] },
685
- { required: ["listName"] }
686
- ]
609
+ required: []
687
610
  }
688
611
  },
689
612
  {
@@ -713,10 +636,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
713
636
  description: "New status for the list"
714
637
  }
715
638
  },
716
- oneOf: [
717
- { required: ["listId"] },
718
- { required: ["listName"] }
719
- ]
639
+ required: []
720
640
  }
721
641
  },
722
642
  {
@@ -734,10 +654,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
734
654
  description: "Name of the list to delete - will automatically find the list by name (optional if using listId instead). Only use this if you don't already have the list ID from previous responses."
735
655
  }
736
656
  },
737
- oneOf: [
738
- { required: ["listId"] },
739
- { required: ["listName"] }
740
- ]
657
+ required: []
741
658
  }
742
659
  }
743
660
  ]
@@ -855,54 +772,23 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
855
772
  };
856
773
  }
857
774
  case "create_list": {
858
- const args = request.params.arguments ? request.params.arguments : { name: '' };
775
+ const args = request.params.arguments;
859
776
  if (!args.name) {
860
- throw new Error("List name is required");
861
- }
862
- // Validate that we have either spaceId/spaceName OR folderId/folderName, but not both
863
- const hasSpace = !!(args.spaceId || args.spaceName);
864
- const hasFolder = !!(args.folderId || args.folderName);
865
- if (!hasSpace && !hasFolder) {
866
- throw new Error("Either spaceId/spaceName or folderId/folderName must be provided");
867
- }
868
- if (hasSpace && hasFolder) {
869
- throw new Error("Cannot provide both space and folder identifiers. Use either spaceId/spaceName OR folderId/folderName");
870
- }
871
- // Prepare the list data
872
- const listData = {
873
- name: args.name,
874
- content: args.content,
875
- due_date: args.dueDate,
876
- priority: args.priority,
877
- assignee: args.assignee,
878
- status: args.status
879
- };
880
- let list;
881
- if (hasSpace) {
882
- // Handle space-based creation
883
- let spaceId = args.spaceId;
884
- if (!spaceId && args.spaceName) {
885
- const teamId = await clickup.getTeamId();
886
- const space = await clickup.findSpaceByName(args.spaceName, teamId);
887
- if (!space) {
888
- throw new Error(`Space with name "${args.spaceName}" not found`);
889
- }
890
- spaceId = space.id;
891
- }
892
- list = await clickup.createList(spaceId, listData);
777
+ throw new Error("name is required");
893
778
  }
894
- else {
895
- // Handle folder-based creation
896
- let folderId = args.folderId;
897
- if (!folderId && args.folderName) {
898
- const result = await clickup.findFolderIDByName(args.folderName);
899
- if (!result) {
900
- throw new Error(`Folder with name "${args.folderName}" not found`);
901
- }
902
- folderId = result.id;
779
+ let spaceId = args.spaceId;
780
+ if (!spaceId && args.spaceName) {
781
+ const foundId = await clickup.findSpaceIDByName(args.spaceName);
782
+ if (!foundId) {
783
+ throw new Error(`Space with name "${args.spaceName}" not found`);
903
784
  }
904
- list = await clickup.createListInFolder(folderId, listData);
785
+ spaceId = foundId;
786
+ }
787
+ if (!spaceId) {
788
+ throw new Error("Either spaceId or spaceName must be provided");
905
789
  }
790
+ const { spaceId: _, spaceName: __, ...listData } = args;
791
+ const list = await clickup.createList(spaceId, listData);
906
792
  return {
907
793
  content: [{
908
794
  type: "text",
@@ -1113,26 +999,14 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1113
999
  }
1114
1000
  case "delete_task": {
1115
1001
  const args = request.params.arguments;
1116
- // Validate the required taskId parameter
1117
- if (!args.taskId) {
1118
- throw new Error("taskId is required for deletion operations");
1119
- }
1120
- // Store the task name before deletion for the response message
1121
- let taskName = args.taskName;
1122
- if (!taskName) {
1123
- try {
1124
- const task = await clickup.getTask(args.taskId);
1125
- taskName = task.name;
1126
- }
1127
- catch (error) {
1128
- // If we can't get the task details, just use the ID in the response
1129
- }
1002
+ if (!args.taskId && !args.taskName) {
1003
+ throw new Error("Either taskId or taskName is required");
1130
1004
  }
1131
- await clickup.deleteTask(args.taskId);
1005
+ await clickup.deleteTask(args.taskId, args.taskName, args.listName);
1132
1006
  return {
1133
1007
  content: [{
1134
1008
  type: "text",
1135
- text: `Successfully deleted task ${taskName || args.taskId}`
1009
+ text: `Successfully deleted task${args.taskName ? ` "${args.taskName}"` : ` with ID ${args.taskId}`}`
1136
1010
  }]
1137
1011
  };
1138
1012
  }
@@ -85,13 +85,6 @@ export class ClickUpService {
85
85
  }
86
86
  return ClickUpService.instance;
87
87
  }
88
- /**
89
- * Gets the team/workspace ID that was set during initialization.
90
- * @returns The team/workspace ID
91
- */
92
- getTeamId() {
93
- return this.clickupTeamId;
94
- }
95
88
  // Tasks
96
89
  /**
97
90
  * Retrieves tasks from a specific list with optional filtering.
@@ -244,11 +237,28 @@ export class ClickUpService {
244
237
  }
245
238
  /**
246
239
  * Deletes a task from the workspace.
240
+ * Can delete by taskId directly or find by taskName first.
247
241
  * Handles rate limiting automatically.
242
+ * @param taskId - ID of the task to delete (optional if taskName provided)
243
+ * @param taskName - Name of the task to delete (optional if taskId provided)
244
+ * @param listName - Optional list name to narrow down task search
245
+ * @throws Error if neither taskId nor taskName is provided, or if task not found
248
246
  */
249
- async deleteTask(taskId) {
247
+ async deleteTask(taskId, taskName, listName) {
250
248
  return this.makeRequest(async () => {
251
- await this.client.delete(`/task/${taskId}`);
249
+ let finalTaskId = taskId;
250
+ // If no taskId but taskName provided, find the task first
251
+ if (!taskId && taskName) {
252
+ const taskInfo = await this.findTaskByName(taskName, undefined, listName);
253
+ if (!taskInfo) {
254
+ throw new Error(`Task "${taskName}" not found${listName ? ` in list "${listName}"` : ''}`);
255
+ }
256
+ finalTaskId = taskInfo.id;
257
+ }
258
+ if (!finalTaskId) {
259
+ throw new Error('Either taskId or taskName must be provided');
260
+ }
261
+ await this.client.delete(`/task/${finalTaskId}`);
252
262
  });
253
263
  }
254
264
  // Lists
@@ -307,9 +317,6 @@ export class ClickUpService {
307
317
  }
308
318
  /**
309
319
  * Creates a new list in a space.
310
- * Note: ClickUp API requires lists to be in folders, so this will:
311
- * 1. Create a default folder if none specified
312
- * 2. Create the list within that folder
313
320
  * @param spaceId - ID of the space to create the list in
314
321
  * @param data - List creation data (name, content, due date, etc.)
315
322
  * @returns Promise resolving to the created ClickUpList
@@ -317,17 +324,7 @@ export class ClickUpService {
317
324
  */
318
325
  async createList(spaceId, data) {
319
326
  return this.makeRequest(async () => {
320
- // First, get or create a default folder
321
- const folders = await this.getFolders(spaceId);
322
- let defaultFolder = folders.find(f => f.name === 'Default Lists');
323
- if (!defaultFolder) {
324
- // Create a default folder if none exists
325
- defaultFolder = await this.createFolder(spaceId, {
326
- name: 'Default Lists'
327
- });
328
- }
329
- // Create the list within the default folder
330
- const response = await this.client.post(`/folder/${defaultFolder.id}/list`, data);
327
+ const response = await this.client.post(`/space/${spaceId}/list`, data);
331
328
  return response.data;
332
329
  });
333
330
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taazkareem/clickup-mcp-server",
3
- "version": "0.4.58",
3
+ "version": "0.4.60",
4
4
  "description": "ClickUp MCP Server - Integrate ClickUp tasks with AI through Model Context Protocol",
5
5
  "type": "module",
6
6
  "main": "build/index.js",