@taazkareem/clickup-mcp-server 0.4.57 → 0.4.58

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,7 +38,6 @@ npx -y @taazkareem/clickup-mcp-server \
38
38
  - Full CRUD operations for workspace components
39
39
  - Efficient path-based navigation
40
40
 
41
-
42
41
  - 🔄 **Integration Features**
43
42
  - Name or ID-based item lookup
44
43
  - Case-insensitive name matching
package/build/index.js CHANGED
@@ -109,7 +109,11 @@ 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: []
112
+ required: ["name"],
113
+ oneOf: [
114
+ { required: ["listId"] },
115
+ { required: ["listName"] }
116
+ ]
113
117
  }
114
118
  },
115
119
  {
@@ -164,11 +168,15 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
164
168
  description: "Array of user IDs to assign to the task"
165
169
  }
166
170
  },
167
- required: []
171
+ required: ["name"]
168
172
  }
169
173
  }
170
174
  },
171
- required: []
175
+ required: ["tasks"],
176
+ oneOf: [
177
+ { required: ["listId"] },
178
+ { required: ["listName"] }
179
+ ]
172
180
  }
173
181
  },
174
182
  {
@@ -179,11 +187,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
179
187
  properties: {
180
188
  spaceId: {
181
189
  type: "string",
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."
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."
183
191
  },
184
- spaceName: {
192
+ folderId: {
185
193
  type: "string",
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."
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."
187
195
  },
188
196
  name: {
189
197
  type: "string",
@@ -193,24 +201,34 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
193
201
  type: "string",
194
202
  description: "Description or content of the list"
195
203
  },
196
- dueDate: {
197
- type: "string",
198
- 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"
199
207
  },
200
208
  priority: {
201
209
  type: "number",
202
210
  description: "Priority of the list (1-4), where 1 is urgent/highest priority and 4 is lowest priority. Only set when explicitly requested."
203
211
  },
204
- assignee: {
205
- type: "number",
206
- description: "User ID to assign the list to"
212
+ dueDate: {
213
+ type: "string",
214
+ description: "Due date for the list (Unix timestamp in milliseconds). Convert dates to this format before submitting."
207
215
  },
208
216
  status: {
209
217
  type: "string",
210
218
  description: "Status of the list"
211
219
  }
212
220
  },
213
- required: []
221
+ allOf: [
222
+ {
223
+ oneOf: [
224
+ { required: ["spaceId"] },
225
+ { required: ["folderId"] }
226
+ ]
227
+ },
228
+ {
229
+ required: ["name"]
230
+ }
231
+ ]
214
232
  }
215
233
  },
216
234
  {
@@ -236,7 +254,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
236
254
  description: "Whether to override space statuses with folder-specific statuses"
237
255
  }
238
256
  },
239
- required: []
257
+ required: ["name"],
258
+ oneOf: [
259
+ { required: ["spaceId"] },
260
+ { required: ["spaceName"] }
261
+ ]
240
262
  }
241
263
  },
242
264
  {
@@ -274,7 +296,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
274
296
  description: "Status of the list (uses folder default if not specified)"
275
297
  }
276
298
  },
277
- required: []
299
+ required: ["name"],
300
+ oneOf: [
301
+ { required: ["folderId"] },
302
+ { required: ["folderName", "spaceId"] },
303
+ { required: ["folderName", "spaceName"] }
304
+ ]
278
305
  }
279
306
  },
280
307
  {
@@ -304,7 +331,20 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
304
331
  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."
305
332
  }
306
333
  },
307
- required: []
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
+ ]
308
348
  }
309
349
  },
310
350
  {
@@ -334,7 +374,20 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
334
374
  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."
335
375
  }
336
376
  },
337
- required: []
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
+ ]
338
391
  }
339
392
  },
340
393
  {
@@ -378,7 +431,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
378
431
  optional: true
379
432
  }
380
433
  },
381
- required: []
434
+ oneOf: [
435
+ { required: ["taskId"] },
436
+ { required: ["taskName"] }
437
+ ]
382
438
  }
383
439
  },
384
440
  {
@@ -458,7 +514,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
458
514
  description: "Object with custom field IDs as keys and desired values for filtering"
459
515
  }
460
516
  },
461
- required: []
517
+ oneOf: [
518
+ { required: ["listId"] },
519
+ { required: ["listName"] }
520
+ ]
462
521
  }
463
522
  },
464
523
  {
@@ -480,7 +539,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
480
539
  description: "Optional: Name of the list to narrow down task search when multiple tasks have the same name"
481
540
  }
482
541
  },
483
- required: []
542
+ oneOf: [
543
+ { required: ["taskId"] },
544
+ { required: ["taskName"] }
545
+ ]
484
546
  }
485
547
  },
486
548
  {
@@ -502,7 +564,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
502
564
  description: "Optional: Name of the list to narrow down task search when multiple tasks have the same name"
503
565
  }
504
566
  },
505
- required: []
567
+ required: ["taskId"]
506
568
  }
507
569
  },
508
570
  {
@@ -528,7 +590,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
528
590
  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."
529
591
  }
530
592
  },
531
- required: []
593
+ oneOf: [
594
+ { required: ["folderId"] },
595
+ { required: ["folderName", "spaceId"] },
596
+ { required: ["folderName", "spaceName"] }
597
+ ]
532
598
  }
533
599
  },
534
600
  {
@@ -562,7 +628,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
562
628
  description: "Whether to override space statuses with folder-specific statuses"
563
629
  }
564
630
  },
565
- required: []
631
+ oneOf: [
632
+ { required: ["folderId"] },
633
+ { required: ["folderName", "spaceId"] },
634
+ { required: ["folderName", "spaceName"] }
635
+ ]
566
636
  }
567
637
  },
568
638
  {
@@ -588,7 +658,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
588
658
  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."
589
659
  }
590
660
  },
591
- required: []
661
+ oneOf: [
662
+ { required: ["folderId"] },
663
+ { required: ["folderName", "spaceId"] },
664
+ { required: ["folderName", "spaceName"] }
665
+ ]
592
666
  }
593
667
  },
594
668
  {
@@ -606,7 +680,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
606
680
  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."
607
681
  }
608
682
  },
609
- required: []
683
+ oneOf: [
684
+ { required: ["listId"] },
685
+ { required: ["listName"] }
686
+ ]
610
687
  }
611
688
  },
612
689
  {
@@ -636,7 +713,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
636
713
  description: "New status for the list"
637
714
  }
638
715
  },
639
- required: []
716
+ oneOf: [
717
+ { required: ["listId"] },
718
+ { required: ["listName"] }
719
+ ]
640
720
  }
641
721
  },
642
722
  {
@@ -654,7 +734,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
654
734
  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."
655
735
  }
656
736
  },
657
- required: []
737
+ oneOf: [
738
+ { required: ["listId"] },
739
+ { required: ["listName"] }
740
+ ]
658
741
  }
659
742
  }
660
743
  ]
@@ -772,23 +855,54 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
772
855
  };
773
856
  }
774
857
  case "create_list": {
775
- const args = request.params.arguments;
858
+ const args = request.params.arguments ? request.params.arguments : { name: '' };
776
859
  if (!args.name) {
777
- throw new Error("name is required");
778
- }
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`);
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;
784
891
  }
785
- spaceId = foundId;
892
+ list = await clickup.createList(spaceId, listData);
786
893
  }
787
- if (!spaceId) {
788
- throw new Error("Either spaceId or spaceName must be provided");
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;
903
+ }
904
+ list = await clickup.createListInFolder(folderId, listData);
789
905
  }
790
- const { spaceId: _, spaceName: __, ...listData } = args;
791
- const list = await clickup.createList(spaceId, listData);
792
906
  return {
793
907
  content: [{
794
908
  type: "text",
@@ -85,6 +85,13 @@ 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
+ }
88
95
  // Tasks
89
96
  /**
90
97
  * Retrieves tasks from a specific list with optional filtering.
@@ -300,6 +307,9 @@ export class ClickUpService {
300
307
  }
301
308
  /**
302
309
  * 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
303
313
  * @param spaceId - ID of the space to create the list in
304
314
  * @param data - List creation data (name, content, due date, etc.)
305
315
  * @returns Promise resolving to the created ClickUpList
@@ -307,7 +317,17 @@ export class ClickUpService {
307
317
  */
308
318
  async createList(spaceId, data) {
309
319
  return this.makeRequest(async () => {
310
- const response = await this.client.post(`/space/${spaceId}/list`, data);
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);
311
331
  return response.data;
312
332
  });
313
333
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taazkareem/clickup-mcp-server",
3
- "version": "0.4.57",
3
+ "version": "0.4.58",
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",