@taazkareem/clickup-mcp-server 0.4.56 → 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 +0 -1
- package/build/index.js +192 -49
- package/build/services/clickup.js +51 -23
- package/package.json +2 -4
package/README.md
CHANGED
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: ["name"]
|
|
112
|
+
required: ["name"],
|
|
113
|
+
oneOf: [
|
|
114
|
+
{ required: ["listId"] },
|
|
115
|
+
{ required: ["listName"] }
|
|
116
|
+
]
|
|
113
117
|
}
|
|
114
118
|
},
|
|
115
119
|
{
|
|
@@ -168,7 +172,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
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 (
|
|
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
|
-
|
|
192
|
+
folderId: {
|
|
185
193
|
type: "string",
|
|
186
|
-
description: "
|
|
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
|
-
|
|
197
|
-
type: "
|
|
198
|
-
description: "
|
|
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
|
-
|
|
205
|
-
type: "
|
|
206
|
-
description: "
|
|
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
|
-
|
|
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: ["name"]
|
|
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: ["name"]
|
|
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
|
-
|
|
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
|
-
|
|
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
|
{
|
|
@@ -363,20 +416,25 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
363
416
|
type: "string",
|
|
364
417
|
description: "New plain text description for the task"
|
|
365
418
|
},
|
|
419
|
+
markdown_description: {
|
|
420
|
+
type: "string",
|
|
421
|
+
description: "New markdown formatted description for the task. If provided, this takes precedence over description"
|
|
422
|
+
},
|
|
366
423
|
status: {
|
|
367
424
|
type: "string",
|
|
368
425
|
description: "New status for the task (must be a valid status in the task's list)"
|
|
369
426
|
},
|
|
370
427
|
priority: {
|
|
371
|
-
type: "number",
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
type: "string",
|
|
376
|
-
description: "New due date for the task (Unix timestamp in milliseconds). Convert dates to this format before submitting."
|
|
428
|
+
type: ["number", "null"],
|
|
429
|
+
enum: [1, 2, 3, 4, null],
|
|
430
|
+
description: "New priority for the task (1-4 or null), where 1 is urgent/highest priority and 4 is lowest priority. Set to null to clear priority.",
|
|
431
|
+
optional: true
|
|
377
432
|
}
|
|
378
433
|
},
|
|
379
|
-
|
|
434
|
+
oneOf: [
|
|
435
|
+
{ required: ["taskId"] },
|
|
436
|
+
{ required: ["taskName"] }
|
|
437
|
+
]
|
|
380
438
|
}
|
|
381
439
|
},
|
|
382
440
|
{
|
|
@@ -456,7 +514,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
456
514
|
description: "Object with custom field IDs as keys and desired values for filtering"
|
|
457
515
|
}
|
|
458
516
|
},
|
|
459
|
-
|
|
517
|
+
oneOf: [
|
|
518
|
+
{ required: ["listId"] },
|
|
519
|
+
{ required: ["listName"] }
|
|
520
|
+
]
|
|
460
521
|
}
|
|
461
522
|
},
|
|
462
523
|
{
|
|
@@ -478,7 +539,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
478
539
|
description: "Optional: Name of the list to narrow down task search when multiple tasks have the same name"
|
|
479
540
|
}
|
|
480
541
|
},
|
|
481
|
-
|
|
542
|
+
oneOf: [
|
|
543
|
+
{ required: ["taskId"] },
|
|
544
|
+
{ required: ["taskName"] }
|
|
545
|
+
]
|
|
482
546
|
}
|
|
483
547
|
},
|
|
484
548
|
{
|
|
@@ -526,7 +590,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
526
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."
|
|
527
591
|
}
|
|
528
592
|
},
|
|
529
|
-
|
|
593
|
+
oneOf: [
|
|
594
|
+
{ required: ["folderId"] },
|
|
595
|
+
{ required: ["folderName", "spaceId"] },
|
|
596
|
+
{ required: ["folderName", "spaceName"] }
|
|
597
|
+
]
|
|
530
598
|
}
|
|
531
599
|
},
|
|
532
600
|
{
|
|
@@ -560,7 +628,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
560
628
|
description: "Whether to override space statuses with folder-specific statuses"
|
|
561
629
|
}
|
|
562
630
|
},
|
|
563
|
-
|
|
631
|
+
oneOf: [
|
|
632
|
+
{ required: ["folderId"] },
|
|
633
|
+
{ required: ["folderName", "spaceId"] },
|
|
634
|
+
{ required: ["folderName", "spaceName"] }
|
|
635
|
+
]
|
|
564
636
|
}
|
|
565
637
|
},
|
|
566
638
|
{
|
|
@@ -586,7 +658,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
586
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."
|
|
587
659
|
}
|
|
588
660
|
},
|
|
589
|
-
|
|
661
|
+
oneOf: [
|
|
662
|
+
{ required: ["folderId"] },
|
|
663
|
+
{ required: ["folderName", "spaceId"] },
|
|
664
|
+
{ required: ["folderName", "spaceName"] }
|
|
665
|
+
]
|
|
590
666
|
}
|
|
591
667
|
},
|
|
592
668
|
{
|
|
@@ -604,7 +680,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
604
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."
|
|
605
681
|
}
|
|
606
682
|
},
|
|
607
|
-
|
|
683
|
+
oneOf: [
|
|
684
|
+
{ required: ["listId"] },
|
|
685
|
+
{ required: ["listName"] }
|
|
686
|
+
]
|
|
608
687
|
}
|
|
609
688
|
},
|
|
610
689
|
{
|
|
@@ -634,7 +713,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
634
713
|
description: "New status for the list"
|
|
635
714
|
}
|
|
636
715
|
},
|
|
637
|
-
|
|
716
|
+
oneOf: [
|
|
717
|
+
{ required: ["listId"] },
|
|
718
|
+
{ required: ["listName"] }
|
|
719
|
+
]
|
|
638
720
|
}
|
|
639
721
|
},
|
|
640
722
|
{
|
|
@@ -652,7 +734,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
652
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."
|
|
653
735
|
}
|
|
654
736
|
},
|
|
655
|
-
|
|
737
|
+
oneOf: [
|
|
738
|
+
{ required: ["listId"] },
|
|
739
|
+
{ required: ["listName"] }
|
|
740
|
+
]
|
|
656
741
|
}
|
|
657
742
|
}
|
|
658
743
|
]
|
|
@@ -730,12 +815,17 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
730
815
|
}
|
|
731
816
|
case "create_bulk_tasks": {
|
|
732
817
|
const args = request.params.arguments;
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
}
|
|
736
|
-
if (!args.tasks || args.tasks.length === 0) {
|
|
818
|
+
// First validate tasks array
|
|
819
|
+
if (!args.tasks || !Array.isArray(args.tasks) || args.tasks.length === 0) {
|
|
737
820
|
throw new Error("tasks array is required and must not be empty");
|
|
738
821
|
}
|
|
822
|
+
// Validate each task has required fields
|
|
823
|
+
args.tasks.forEach((task, index) => {
|
|
824
|
+
if (!task.name) {
|
|
825
|
+
throw new Error(`Task at index ${index} is missing required field 'name'`);
|
|
826
|
+
}
|
|
827
|
+
});
|
|
828
|
+
// Get listId from name if needed
|
|
739
829
|
let listId = args.listId;
|
|
740
830
|
if (!listId && args.listName) {
|
|
741
831
|
const result = await clickup.findListIDByName(args.listName);
|
|
@@ -744,33 +834,75 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
744
834
|
}
|
|
745
835
|
listId = result.id;
|
|
746
836
|
}
|
|
837
|
+
// Now validate we have a listId
|
|
838
|
+
if (!listId) {
|
|
839
|
+
throw new Error("Either listId or listName must be provided");
|
|
840
|
+
}
|
|
747
841
|
const { listId: _, listName: __, tasks } = args;
|
|
748
842
|
const createdTasks = await clickup.createBulkTasks(listId, { tasks });
|
|
749
843
|
return {
|
|
750
844
|
content: [{
|
|
751
845
|
type: "text",
|
|
752
|
-
text:
|
|
846
|
+
text: JSON.stringify({
|
|
847
|
+
message: `Created ${createdTasks.length} tasks`,
|
|
848
|
+
tasks: createdTasks.map(task => ({
|
|
849
|
+
id: task.id,
|
|
850
|
+
name: task.name,
|
|
851
|
+
url: task.url
|
|
852
|
+
}))
|
|
853
|
+
}, null, 2)
|
|
753
854
|
}]
|
|
754
855
|
};
|
|
755
856
|
}
|
|
756
857
|
case "create_list": {
|
|
757
|
-
const args = request.params.arguments;
|
|
858
|
+
const args = request.params.arguments ? request.params.arguments : { name: '' };
|
|
758
859
|
if (!args.name) {
|
|
759
|
-
throw new Error("name is required");
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
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;
|
|
766
891
|
}
|
|
767
|
-
|
|
892
|
+
list = await clickup.createList(spaceId, listData);
|
|
768
893
|
}
|
|
769
|
-
|
|
770
|
-
|
|
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);
|
|
771
905
|
}
|
|
772
|
-
const { spaceId: _, spaceName: __, ...listData } = args;
|
|
773
|
-
const list = await clickup.createList(spaceId, listData);
|
|
774
906
|
return {
|
|
775
907
|
content: [{
|
|
776
908
|
type: "text",
|
|
@@ -902,9 +1034,11 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
902
1034
|
}
|
|
903
1035
|
case "update_task": {
|
|
904
1036
|
const args = request.params.arguments;
|
|
1037
|
+
// Require either taskId or taskName
|
|
905
1038
|
if (!args.taskId && !args.taskName) {
|
|
906
1039
|
throw new Error("Either taskId or taskName is required");
|
|
907
1040
|
}
|
|
1041
|
+
// Get taskId from taskName if needed
|
|
908
1042
|
let taskId = args.taskId;
|
|
909
1043
|
if (!taskId && args.taskName) {
|
|
910
1044
|
const result = await clickup.findTaskByName(args.taskName, undefined, args.listName);
|
|
@@ -913,7 +1047,16 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
913
1047
|
}
|
|
914
1048
|
taskId = result.id;
|
|
915
1049
|
}
|
|
1050
|
+
// Remove helper fields before updating
|
|
916
1051
|
const { taskId: _, taskName: __, listName: ___, ...updateData } = args;
|
|
1052
|
+
// Ensure priority is properly handled
|
|
1053
|
+
if (updateData.priority !== undefined && updateData.priority !== null) {
|
|
1054
|
+
const priority = Number(updateData.priority);
|
|
1055
|
+
if (isNaN(priority) || ![1, 2, 3, 4].includes(priority)) {
|
|
1056
|
+
throw new Error("Priority must be a number between 1 and 4, or null to clear priority");
|
|
1057
|
+
}
|
|
1058
|
+
updateData.priority = priority;
|
|
1059
|
+
}
|
|
917
1060
|
const task = await clickup.updateTask(taskId, updateData);
|
|
918
1061
|
return {
|
|
919
1062
|
content: [{
|
|
@@ -59,16 +59,7 @@ export class ClickUpService {
|
|
|
59
59
|
*/
|
|
60
60
|
async makeRequest(requestFn) {
|
|
61
61
|
await this.checkRateLimit();
|
|
62
|
-
|
|
63
|
-
return await requestFn();
|
|
64
|
-
}
|
|
65
|
-
catch (error) {
|
|
66
|
-
if (error.response?.status === 429) {
|
|
67
|
-
// Let the interceptor handle it
|
|
68
|
-
throw error;
|
|
69
|
-
}
|
|
70
|
-
throw error;
|
|
71
|
-
}
|
|
62
|
+
return await requestFn();
|
|
72
63
|
}
|
|
73
64
|
/**
|
|
74
65
|
* Initializes the ClickUpService singleton instance.
|
|
@@ -94,6 +85,13 @@ export class ClickUpService {
|
|
|
94
85
|
}
|
|
95
86
|
return ClickUpService.instance;
|
|
96
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
|
+
}
|
|
97
95
|
// Tasks
|
|
98
96
|
/**
|
|
99
97
|
* Retrieves tasks from a specific list with optional filtering.
|
|
@@ -183,10 +181,15 @@ export class ClickUpService {
|
|
|
183
181
|
async createTask(listId, data) {
|
|
184
182
|
return this.makeRequest(async () => {
|
|
185
183
|
const taskData = { ...data };
|
|
186
|
-
|
|
187
|
-
|
|
184
|
+
// If markdown_description is provided, it takes precedence
|
|
185
|
+
if (taskData.markdown_description) {
|
|
186
|
+
// Ensure we don't send both to avoid confusion
|
|
188
187
|
delete taskData.description;
|
|
189
188
|
}
|
|
189
|
+
else if (taskData.description) {
|
|
190
|
+
// Only use description as-is, don't auto-convert to markdown
|
|
191
|
+
taskData.description = taskData.description.trim();
|
|
192
|
+
}
|
|
190
193
|
const response = await this.client.post(`/list/${listId}/task`, taskData);
|
|
191
194
|
return response.data;
|
|
192
195
|
});
|
|
@@ -200,10 +203,15 @@ export class ClickUpService {
|
|
|
200
203
|
for (const taskData of data.tasks) {
|
|
201
204
|
await this.makeRequest(async () => {
|
|
202
205
|
const processedTask = { ...taskData };
|
|
203
|
-
|
|
204
|
-
|
|
206
|
+
// If markdown_description is provided, it takes precedence
|
|
207
|
+
if (processedTask.markdown_description) {
|
|
208
|
+
// Ensure we don't send both to avoid confusion
|
|
205
209
|
delete processedTask.description;
|
|
206
210
|
}
|
|
211
|
+
else if (processedTask.description) {
|
|
212
|
+
// Only use description as-is, don't auto-convert to markdown
|
|
213
|
+
processedTask.description = processedTask.description.trim();
|
|
214
|
+
}
|
|
207
215
|
const response = await this.client.post(`/list/${listId}/task`, processedTask);
|
|
208
216
|
createdTasks.push(response.data);
|
|
209
217
|
});
|
|
@@ -216,7 +224,21 @@ export class ClickUpService {
|
|
|
216
224
|
*/
|
|
217
225
|
async updateTask(taskId, data) {
|
|
218
226
|
return this.makeRequest(async () => {
|
|
219
|
-
const
|
|
227
|
+
const updateData = { ...data };
|
|
228
|
+
// If markdown_description is provided, it takes precedence
|
|
229
|
+
if (updateData.markdown_description) {
|
|
230
|
+
// Ensure we don't send both to avoid confusion
|
|
231
|
+
delete updateData.description;
|
|
232
|
+
}
|
|
233
|
+
else if (updateData.description) {
|
|
234
|
+
// Only use description as-is, don't auto-convert to markdown
|
|
235
|
+
updateData.description = updateData.description.trim();
|
|
236
|
+
}
|
|
237
|
+
// Handle null priority explicitly
|
|
238
|
+
if (updateData.priority === null) {
|
|
239
|
+
updateData.priority = null;
|
|
240
|
+
}
|
|
241
|
+
const response = await this.client.put(`/task/${taskId}`, updateData);
|
|
220
242
|
return response.data;
|
|
221
243
|
});
|
|
222
244
|
}
|
|
@@ -285,6 +307,9 @@ export class ClickUpService {
|
|
|
285
307
|
}
|
|
286
308
|
/**
|
|
287
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
|
|
288
313
|
* @param spaceId - ID of the space to create the list in
|
|
289
314
|
* @param data - List creation data (name, content, due date, etc.)
|
|
290
315
|
* @returns Promise resolving to the created ClickUpList
|
|
@@ -292,7 +317,17 @@ export class ClickUpService {
|
|
|
292
317
|
*/
|
|
293
318
|
async createList(spaceId, data) {
|
|
294
319
|
return this.makeRequest(async () => {
|
|
295
|
-
|
|
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);
|
|
296
331
|
return response.data;
|
|
297
332
|
});
|
|
298
333
|
}
|
|
@@ -730,11 +765,4 @@ export class ClickUpService {
|
|
|
730
765
|
: `${task.space.name} > ${task.list.name} > ${task.name}`;
|
|
731
766
|
return { id: task.id, path };
|
|
732
767
|
}
|
|
733
|
-
async getTaskStatuses(listId) {
|
|
734
|
-
const response = await this.getTasks(listId);
|
|
735
|
-
const statuses = [...new Set(response.tasks
|
|
736
|
-
.filter((task) => task.status !== undefined)
|
|
737
|
-
.map((task) => task.status.status))];
|
|
738
|
-
return statuses;
|
|
739
|
-
}
|
|
740
768
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taazkareem/clickup-mcp-server",
|
|
3
|
-
"version": "0.4.
|
|
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",
|
|
@@ -44,10 +44,8 @@
|
|
|
44
44
|
"homepage": "https://github.com/taazkareem/clickup-mcp-server#readme",
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@modelcontextprotocol/sdk": "0.6.0",
|
|
47
|
-
"@types/express": "^5.0.0",
|
|
48
47
|
"axios": "^1.6.7",
|
|
49
|
-
"dotenv": "^16.4.1"
|
|
50
|
-
"express": "^4.21.2"
|
|
48
|
+
"dotenv": "^16.4.1"
|
|
51
49
|
},
|
|
52
50
|
"devDependencies": {
|
|
53
51
|
"@types/node": "^20.11.16",
|