@taazkareem/clickup-mcp-server 0.3.0 → 0.4.0

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
@@ -16,18 +16,24 @@ A Model Context Protocol (MCP) server for integrating ClickUp tasks with AI appl
16
16
  - Flexible identification using IDs or names
17
17
 
18
18
  - ✨ **Task Operations**
19
- - Create and update tasks
19
+ - Create single or bulk tasks
20
20
  - Move tasks between lists
21
21
  - Duplicate tasks
22
22
  - Set priorities and due dates
23
23
  - Assign team members
24
24
 
25
25
  - 📊 **Information Retrieval**
26
- - Get spaces and lists with their IDs
26
+ - Get complete hierarchy of spaces, folders, and lists with IDs
27
27
  - List available statuses
28
28
  - Find items by name (case-insensitive)
29
29
  - View task relationships
30
30
 
31
+ - 🔍 **Smart Name Resolution**
32
+ - Use names instead of IDs for lists and folders
33
+ - Global search across all spaces
34
+ - Case-insensitive matching
35
+ - Automatic location of items
36
+
31
37
  - 📝 **AI Integration**
32
38
  - Generate task descriptions with AI
33
39
  - Summarize tasks and analyze priorities
@@ -81,17 +87,20 @@ You can get these values from:
81
87
 
82
88
  ### Available Tools
83
89
 
84
- 1. **list_spaces**
85
- - Lists all spaces and their lists with IDs
90
+ 1. **workspace_hierarchy**
91
+ - Lists complete hierarchy of the ClickUp workspace
92
+ - Shows spaces, folders, and lists with their IDs
86
93
  - Shows available statuses for each list
94
+ - Provides a tree view of your workspace organization
87
95
  - No parameters required
88
96
 
89
97
  2. **create_task**
90
98
  - Creates a new task in ClickUp
91
99
  - Required parameters:
92
- - `listId`: ID of the list to create the task in
93
100
  - `name`: Name of the task
94
101
  - Optional parameters:
102
+ - `listId`: ID of the list (optional if listName provided)
103
+ - `listName`: Name of the list (optional if listId provided)
95
104
  - `description`: Task description
96
105
  - `status`: Task status
97
106
  - `priority`: Priority level (1-4)
@@ -101,7 +110,6 @@ You can get these values from:
101
110
  3. **create_bulk_tasks**
102
111
  - Creates multiple tasks simultaneously in a list
103
112
  - Required parameters:
104
- - `listId`: ID of the list to create the tasks in
105
113
  - `tasks`: Array of task objects, each containing:
106
114
  - `name`: Name of the task (required)
107
115
  - `description`: Task description (optional)
@@ -109,6 +117,9 @@ You can get these values from:
109
117
  - `priority`: Priority level 1-4 (optional)
110
118
  - `dueDate`: Due date ISO string (optional)
111
119
  - `assignees`: Array of user IDs (optional)
120
+ - Optional parameters:
121
+ - `listId`: ID of the list (optional if listName provided)
122
+ - `listName`: Name of the list (optional if listId provided)
112
123
 
113
124
  4. **create_list**
114
125
  - Creates a new list in a space
@@ -147,13 +158,17 @@ You can get these values from:
147
158
  - Moves a task to a different list
148
159
  - Required parameters:
149
160
  - `taskId`: ID of the task to move
150
- - `listId`: ID of the destination list
161
+ - Optional parameters:
162
+ - `listId`: ID of destination list (optional if listName provided)
163
+ - `listName`: Name of destination list (optional if listId provided)
151
164
 
152
165
  8. **duplicate_task**
153
166
  - Creates a copy of a task in a specified list
154
167
  - Required parameters:
155
168
  - `taskId`: ID of the task to duplicate
156
- - `listId`: ID of the destination list
169
+ - Optional parameters:
170
+ - `listId`: ID of destination list (optional if listName provided)
171
+ - `listName`: Name of destination list (optional if listId provided)
157
172
 
158
173
  9. **update_task**
159
174
  - Updates an existing task
@@ -231,4 +246,4 @@ Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md)
231
246
 
232
247
  ## License
233
248
 
234
- This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
249
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
package/build/index.js CHANGED
@@ -101,8 +101,8 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
101
101
  return {
102
102
  tools: [
103
103
  {
104
- name: "list_spaces",
105
- description: "List all spaces and their lists with IDs",
104
+ name: "workspace_hierarchy",
105
+ description: "List complete hierarchy of the ClickUp workspace, including spaces, folders, lists, and their IDs and available statuses",
106
106
  inputSchema: {
107
107
  type: "object",
108
108
  properties: {},
@@ -117,7 +117,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
117
117
  properties: {
118
118
  listId: {
119
119
  type: "string",
120
- description: "ID of the list to create the task in"
120
+ description: "ID of the list to create the task in (optional if listName is provided)"
121
+ },
122
+ listName: {
123
+ type: "string",
124
+ description: "Name of the list to create the task in (optional if listId is provided)"
121
125
  },
122
126
  name: {
123
127
  type: "string",
@@ -140,7 +144,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
140
144
  description: "Due date of the task (ISO string)"
141
145
  }
142
146
  },
143
- required: ["listId", "name"]
147
+ required: ["name"]
144
148
  }
145
149
  },
146
150
  {
@@ -151,7 +155,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
151
155
  properties: {
152
156
  listId: {
153
157
  type: "string",
154
- description: "ID of the list to create the tasks in"
158
+ description: "ID of the list to create the tasks in (optional if listName is provided)"
159
+ },
160
+ listName: {
161
+ type: "string",
162
+ description: "Name of the list to create the tasks in (optional if listId is provided)"
155
163
  },
156
164
  tasks: {
157
165
  type: "array",
@@ -177,7 +185,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
177
185
  },
178
186
  dueDate: {
179
187
  type: "string",
180
- description: "Due date of the task (ISO string)"
188
+ description: "Due date (ISO string)"
181
189
  },
182
190
  assignees: {
183
191
  type: "array",
@@ -191,7 +199,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
191
199
  }
192
200
  }
193
201
  },
194
- required: ["listId", "tasks"]
202
+ required: ["tasks"]
195
203
  }
196
204
  },
197
205
  {
@@ -312,10 +320,14 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
312
320
  },
313
321
  listId: {
314
322
  type: "string",
315
- description: "ID of the destination list"
323
+ description: "ID of the destination list (optional if listName is provided)"
324
+ },
325
+ listName: {
326
+ type: "string",
327
+ description: "Name of the destination list (optional if listId is provided)"
316
328
  }
317
329
  },
318
- required: ["taskId", "listId"]
330
+ required: ["taskId"]
319
331
  }
320
332
  },
321
333
  {
@@ -330,10 +342,14 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
330
342
  },
331
343
  listId: {
332
344
  type: "string",
333
- description: "ID of the list to create the duplicate in"
345
+ description: "ID of the destination list (optional if listName is provided)"
346
+ },
347
+ listName: {
348
+ type: "string",
349
+ description: "Name of the destination list (optional if listId is provided)"
334
350
  }
335
351
  },
336
- required: ["taskId", "listId"]
352
+ required: ["taskId"]
337
353
  }
338
354
  },
339
355
  {
@@ -380,17 +396,35 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
380
396
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
381
397
  try {
382
398
  switch (request.params.name) {
383
- case "list_spaces": {
399
+ case "workspace_hierarchy": {
384
400
  const spaces = await clickup.getSpaces(config.teamId);
385
401
  const allLists = await clickup.getAllLists(config.teamId);
386
- let output = "Available Spaces and Lists:\n\n";
402
+ let output = "ClickUp Workspace Hierarchy:\n\n";
387
403
  for (const space of spaces) {
388
404
  output += `Space: ${space.name} (ID: ${space.id})\n`;
389
- const spaceLists = allLists.filter(list => list.space.id === space.id);
390
- for (const list of spaceLists) {
391
- const { statuses } = await clickup.getTasks(list.id);
392
- output += ` └─ List: ${list.name} (ID: ${list.id})\n`;
393
- output += ` Available Statuses: ${statuses.join(', ')}\n`;
405
+ // Get folders in this space
406
+ const folders = await clickup.getFolders(space.id);
407
+ for (const folder of folders) {
408
+ output += ` ├─ Folder: ${folder.name} (ID: ${folder.id})\n`;
409
+ // Get lists in this folder
410
+ const folderLists = folder.lists || [];
411
+ for (const list of folderLists) {
412
+ const { statuses } = await clickup.getTasks(list.id);
413
+ output += ` │ └─ List: ${list.name} (ID: ${list.id})\n`;
414
+ output += ` │ Available Statuses: ${statuses.join(', ')}\n`;
415
+ }
416
+ }
417
+ // Get lists directly in space (not in folders)
418
+ const spaceLists = allLists.filter(list => list.space &&
419
+ list.space.id === space.id &&
420
+ !folders.some(folder => folder.lists?.some(fl => fl.id === list.id)));
421
+ if (spaceLists.length > 0) {
422
+ output += " ├─ Lists (not in folders):\n";
423
+ for (const list of spaceLists) {
424
+ const { statuses } = await clickup.getTasks(list.id);
425
+ output += ` │ └─ List: ${list.name} (ID: ${list.id})\n`;
426
+ output += ` │ Available Statuses: ${statuses.join(', ')}\n`;
427
+ }
394
428
  }
395
429
  output += "\n";
396
430
  }
@@ -413,10 +447,18 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
413
447
  }
414
448
  case "create_task": {
415
449
  const args = request.params.arguments;
416
- if (!args.listId || !args.name) {
417
- throw new Error("listId and name are required");
450
+ let listId = args.listId;
451
+ if (!listId && args.listName) {
452
+ const result = await clickup.findListByNameGlobally(config.teamId, args.listName);
453
+ if (!result) {
454
+ throw new Error(`List with name "${args.listName}" not found`);
455
+ }
456
+ listId = result.list.id;
457
+ }
458
+ if (!listId) {
459
+ throw new Error("Either listId or listName is required");
418
460
  }
419
- const { listId, ...taskData } = args;
461
+ const { listId: _, listName: __, ...taskData } = args;
420
462
  const task = await clickup.createTask(listId, taskData);
421
463
  return {
422
464
  content: [{
@@ -427,10 +469,21 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
427
469
  }
428
470
  case "create_bulk_tasks": {
429
471
  const args = request.params.arguments;
430
- if (!args.listId || !args.tasks || !args.tasks.length) {
431
- throw new Error("listId and at least one task are required");
472
+ let listId = args.listId;
473
+ if (!listId && args.listName) {
474
+ const result = await clickup.findListByNameGlobally(config.teamId, args.listName);
475
+ if (!result) {
476
+ throw new Error(`List with name "${args.listName}" not found`);
477
+ }
478
+ listId = result.list.id;
479
+ }
480
+ if (!listId) {
481
+ throw new Error("Either listId or listName is required");
482
+ }
483
+ if (!args.tasks || !args.tasks.length) {
484
+ throw new Error("At least one task is required");
432
485
  }
433
- const { listId, tasks } = args;
486
+ const { listId: _, listName: __, tasks } = args;
434
487
  const createdTasks = await clickup.createBulkTasks(listId, { tasks });
435
488
  return {
436
489
  content: [{
@@ -444,6 +497,29 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
444
497
  if (!args.name) {
445
498
  throw new Error("name is required");
446
499
  }
500
+ // If folder is specified, create list in folder
501
+ if (args.folderName || args.folderId) {
502
+ let folderId = args.folderId;
503
+ if (!folderId && args.folderName) {
504
+ const result = await clickup.findFolderByNameGlobally(config.teamId, args.folderName);
505
+ if (!result) {
506
+ throw new Error(`Folder with name "${args.folderName}" not found`);
507
+ }
508
+ folderId = result.folder.id;
509
+ }
510
+ if (!folderId) {
511
+ throw new Error("Either folderId or folderName must be provided");
512
+ }
513
+ const { spaceId: _, spaceName: __, folderName: ___, folderId: ____, ...listData } = args;
514
+ const list = await clickup.createListInFolder(folderId, listData);
515
+ return {
516
+ content: [{
517
+ type: "text",
518
+ text: `Created list ${list.id}: ${list.name} in folder`
519
+ }]
520
+ };
521
+ }
522
+ // Otherwise, create list in space
447
523
  let spaceId = args.spaceId;
448
524
  if (!spaceId && args.spaceName) {
449
525
  const space = await clickup.findSpaceByName(config.teamId, args.spaceName);
@@ -455,7 +531,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
455
531
  if (!spaceId) {
456
532
  throw new Error("Either spaceId or spaceName must be provided");
457
533
  }
458
- const { spaceId: _, spaceName: __, ...listData } = args;
534
+ const { spaceId: _, spaceName: __, folderName: ___, folderId: ____, ...listData } = args;
459
535
  const list = await clickup.createList(spaceId, listData);
460
536
  return {
461
537
  content: [{
@@ -505,18 +581,21 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
505
581
  spaceId = space.id;
506
582
  }
507
583
  if (!spaceId) {
508
- throw new Error("Either spaceId or spaceName must be provided when using folderName");
509
- }
510
- const folder = await clickup.findFolderByName(spaceId, args.folderName);
511
- if (!folder) {
512
- throw new Error(`Folder with name "${args.folderName}" not found`);
584
+ throw new Error("Either spaceId or spaceName must be provided");
513
585
  }
514
- folderId = folder.id;
586
+ const { spaceId: _, spaceName: ___, ...listData } = args;
587
+ const list = await clickup.createListInFolder(spaceId, listData);
588
+ return {
589
+ content: [{
590
+ type: "text",
591
+ text: `Created list ${list.id}: ${list.name} in folder`
592
+ }]
593
+ };
515
594
  }
516
595
  if (!folderId) {
517
- throw new Error("Either folderId or folderName (with space information) must be provided");
596
+ throw new Error("Either folderId or folderName must be provided");
518
597
  }
519
- const { folderId: _, folderName: __, spaceId: ___, spaceName: ____, ...listData } = args;
598
+ const { spaceId: _, spaceName: ___, ...listData } = args;
520
599
  const list = await clickup.createListInFolder(folderId, listData);
521
600
  return {
522
601
  content: [{
@@ -527,37 +606,64 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
527
606
  }
528
607
  case "move_task": {
529
608
  const args = request.params.arguments;
530
- if (!args.taskId || !args.listId) {
531
- throw new Error("taskId and listId are required");
609
+ if (!args.taskId) {
610
+ throw new Error("taskId is required");
611
+ }
612
+ let listId = args.listId;
613
+ if (!listId && args.listName) {
614
+ const result = await clickup.findListByNameGlobally(config.teamId, args.listName);
615
+ if (!result) {
616
+ throw new Error(`List with name "${args.listName}" not found`);
617
+ }
618
+ listId = result.list.id;
532
619
  }
533
- const task = await clickup.moveTask(args.taskId, args.listId);
620
+ if (!listId) {
621
+ throw new Error("Either listId or listName is required");
622
+ }
623
+ const task = await clickup.moveTask(args.taskId, listId);
534
624
  return {
535
625
  content: [{
536
626
  type: "text",
537
- text: `Moved task ${task.id} to list ${args.listId}`
627
+ text: `Moved task ${task.id} to list ${listId}`
538
628
  }]
539
629
  };
540
630
  }
541
631
  case "duplicate_task": {
542
632
  const args = request.params.arguments;
543
- if (!args.taskId || !args.listId) {
544
- throw new Error("taskId and listId are required");
633
+ if (!args.taskId) {
634
+ throw new Error("taskId is required");
635
+ }
636
+ let listId = args.listId;
637
+ if (!listId && args.listName) {
638
+ const result = await clickup.findListByNameGlobally(config.teamId, args.listName);
639
+ if (!result) {
640
+ throw new Error(`List with name "${args.listName}" not found`);
641
+ }
642
+ listId = result.list.id;
545
643
  }
546
- const task = await clickup.duplicateTask(args.taskId, args.listId);
644
+ if (!listId) {
645
+ throw new Error("Either listId or listName is required");
646
+ }
647
+ const task = await clickup.duplicateTask(args.taskId, listId);
547
648
  return {
548
649
  content: [{
549
650
  type: "text",
550
- text: `Duplicated task ${args.taskId} to new task ${task.id} in list ${args.listId}`
651
+ text: `Duplicated task ${args.taskId} to new task ${task.id} in list ${listId}`
551
652
  }]
552
653
  };
553
654
  }
554
655
  case "update_task": {
555
656
  const args = request.params.arguments;
556
- if (!args.taskId) {
557
- throw new Error("taskId is required");
657
+ if (!args.taskId || !args.name || !args.description || !args.status || !args.priority || !args.due_date) {
658
+ throw new Error("All arguments are required");
558
659
  }
559
- const { taskId, ...updateData } = args;
560
- const task = await clickup.updateTask(taskId, updateData);
660
+ const task = await clickup.updateTask(args.taskId, {
661
+ name: args.name,
662
+ description: args.description,
663
+ status: args.status,
664
+ priority: args.priority,
665
+ due_date: args.due_date ? new Date(args.due_date).getTime() : undefined
666
+ });
561
667
  return {
562
668
  content: [{
563
669
  type: "text",
@@ -565,152 +671,119 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
565
671
  }]
566
672
  };
567
673
  }
568
- default:
569
- throw new Error("Unknown tool");
570
674
  }
675
+ throw new Error("Unknown tool");
571
676
  }
572
677
  catch (error) {
573
- console.error('Error handling tool call:', error);
678
+ console.error('Error executing tool:', error);
574
679
  throw error;
575
680
  }
576
681
  });
577
682
  /**
578
- * Add handlers for listing and getting prompts.
579
- * Prompts include summarizing tasks, analyzing priorities, and generating task descriptions.
683
+ * Handler for listing available prompts.
684
+ * Exposes prompts for summarizing/analyzing ClickUp tasks.
580
685
  */
581
686
  server.setRequestHandler(ListPromptsRequestSchema, async () => {
582
687
  return {
583
688
  prompts: [
584
689
  {
585
690
  name: "summarize_tasks",
586
- description: "Summarize all tasks in a list",
691
+ description: "Summarize all ClickUp tasks"
587
692
  },
588
693
  {
589
- name: "analyze_priorities",
590
- description: "Analyze task priorities and suggest optimizations",
694
+ name: "analyze_task_priorities",
695
+ description: "Analyze task priorities"
591
696
  },
592
697
  {
593
- name: "generate_description",
594
- description: "Generate a detailed description for a task",
698
+ name: "generate_task_descriptions",
699
+ description: "Generate detailed descriptions for tasks"
595
700
  }
596
701
  ]
597
702
  };
598
703
  });
704
+ /**
705
+ * Handler for getting a specific prompt.
706
+ * Takes a prompt name and returns the prompt content.
707
+ */
599
708
  server.setRequestHandler(GetPromptRequestSchema, async (request) => {
600
709
  try {
601
710
  switch (request.params.name) {
602
711
  case "summarize_tasks": {
603
712
  const spaces = await clickup.getSpaces(config.teamId);
604
- const tasks = [];
605
- // Gather all tasks
713
+ let output = "Summarized Tasks:\n\n";
606
714
  for (const space of spaces) {
607
715
  const lists = await clickup.getLists(space.id);
608
716
  for (const list of lists) {
609
- const { tasks: listTasks } = await clickup.getTasks(list.id);
610
- tasks.push(...listTasks.map((task) => ({
611
- type: "resource",
612
- resource: {
613
- uri: `clickup://task/${task.id}`,
614
- mimeType: "application/json",
615
- text: JSON.stringify(task, null, 2)
616
- }
617
- })));
717
+ const { tasks } = await clickup.getTasks(list.id);
718
+ for (const task of tasks) {
719
+ output += `- ${task.name}: ${task.description}\n`;
720
+ }
618
721
  }
619
722
  }
620
723
  return {
621
- messages: [
622
- {
623
- role: "user",
624
- content: {
625
- type: "text",
626
- text: "Please provide a summary of the following ClickUp tasks:"
627
- }
628
- },
629
- ...tasks.map(task => ({
630
- role: "user",
631
- content: task
632
- })),
633
- {
634
- role: "user",
635
- content: {
636
- type: "text",
637
- text: "Please provide:\n1. A high-level overview of all tasks\n2. Group them by status\n3. Highlight any urgent or high-priority items\n4. Suggest any task dependencies or relationships"
638
- }
639
- }
640
- ]
724
+ content: [{
725
+ type: "text",
726
+ text: output
727
+ }]
641
728
  };
642
729
  }
643
- case "analyze_priorities": {
730
+ case "analyze_task_priorities": {
644
731
  const spaces = await clickup.getSpaces(config.teamId);
645
- const tasks = [];
732
+ const allTasks = [];
646
733
  for (const space of spaces) {
647
734
  const lists = await clickup.getLists(space.id);
648
735
  for (const list of lists) {
649
- const { tasks: listTasks } = await clickup.getTasks(list.id);
650
- tasks.push(...listTasks.map((task) => ({
651
- type: "resource",
652
- resource: {
653
- uri: `clickup://task/${task.id}`,
654
- mimeType: "application/json",
655
- text: JSON.stringify(task, null, 2)
656
- }
657
- })));
736
+ const { tasks } = await clickup.getTasks(list.id);
737
+ allTasks.push(...tasks);
658
738
  }
659
739
  }
740
+ const priorities = allTasks.map((task) => task.priority?.priority);
741
+ const uniquePriorities = [...new Set(priorities.filter(p => p !== undefined))];
742
+ const priorityCounts = uniquePriorities.map(priority => ({
743
+ priority: priority,
744
+ count: priorities.filter((p) => p === priority).length
745
+ }));
746
+ let output = "Task Priorities Analysis:\n\n";
747
+ output += "Available Priorities: " + uniquePriorities.join(', ') + "\n\n";
748
+ output += "Priority Counts:\n";
749
+ for (const priority of priorityCounts) {
750
+ output += `- Priority ${priority.priority}: ${priority.count}\n`;
751
+ }
660
752
  return {
661
- messages: [
662
- {
663
- role: "user",
664
- content: {
665
- type: "text",
666
- text: "Please analyze the priorities of the following ClickUp tasks:"
667
- }
668
- },
669
- ...tasks.map(task => ({
670
- role: "user",
671
- content: task
672
- })),
673
- {
674
- role: "user",
675
- content: {
676
- type: "text",
677
- text: "Please provide:\n1. Analysis of current priority distribution\n2. Identify any misaligned priorities\n3. Suggest priority adjustments\n4. Recommend task sequencing based on priorities"
678
- }
679
- }
680
- ]
753
+ content: [{
754
+ type: "text",
755
+ text: output
756
+ }]
681
757
  };
682
758
  }
683
- case "generate_description": {
684
- return {
685
- messages: [
686
- {
687
- role: "user",
688
- content: {
689
- type: "text",
690
- text: "Please help me generate a detailed description for a ClickUp task. The description should include:\n1. Clear objective\n2. Success criteria\n3. Required resources\n4. Dependencies\n5. Potential risks\n\nPlease ask me about the task details."
691
- }
759
+ case "generate_task_descriptions": {
760
+ const spaces = await clickup.getSpaces(config.teamId);
761
+ let output = "Generated Task Descriptions:\n\n";
762
+ for (const space of spaces) {
763
+ const lists = await clickup.getLists(space.id);
764
+ for (const list of lists) {
765
+ const { tasks } = await clickup.getTasks(list.id);
766
+ for (const task of tasks) {
767
+ output += `- ${task.name}: ${task.description}\n`;
692
768
  }
693
- ]
769
+ }
770
+ }
771
+ return {
772
+ content: [{
773
+ type: "text",
774
+ text: output
775
+ }]
694
776
  };
695
777
  }
696
778
  default:
697
- throw new Error("Unknown prompt");
779
+ throw new Error("Prompt not found");
698
780
  }
699
781
  }
700
782
  catch (error) {
701
- console.error('Error handling prompt:', error);
783
+ console.error('Error getting prompt:', error);
702
784
  throw error;
703
785
  }
704
786
  });
705
- /**
706
- * Start the server using stdio transport.
707
- * This allows the server to communicate via standard input/output streams.
708
- */
709
- async function main() {
710
- const transport = new StdioServerTransport();
711
- await server.connect(transport);
712
- }
713
- main().catch((error) => {
714
- console.error("Server error:", error);
715
- process.exit(1);
716
- });
787
+ // Start the server
788
+ const transport = new StdioServerTransport();
789
+ transport.start();
@@ -110,6 +110,43 @@ export class ClickUpService {
110
110
  });
111
111
  return response.data;
112
112
  }
113
+ async findListByNameGlobally(teamId, listName) {
114
+ const spaces = await this.getSpaces(teamId);
115
+ for (const space of spaces) {
116
+ // Check lists in folders
117
+ const folders = await this.getFolders(space.id);
118
+ for (const folder of folders) {
119
+ const folderList = folder.lists?.find(list => list.name.toLowerCase() === listName.toLowerCase());
120
+ if (folderList) {
121
+ return { list: folderList, space, folder };
122
+ }
123
+ }
124
+ // Check lists directly in space
125
+ const spaceLists = await this.getLists(space.id);
126
+ const spaceList = spaceLists.find(list => list.name.toLowerCase() === listName.toLowerCase());
127
+ if (spaceList) {
128
+ return { list: spaceList, space };
129
+ }
130
+ }
131
+ // Check lists without spaces
132
+ const allLists = await this.getAllLists(teamId);
133
+ const list = allLists.find(list => list.name.toLowerCase() === listName.toLowerCase());
134
+ if (list) {
135
+ return { list };
136
+ }
137
+ return null;
138
+ }
139
+ async findFolderByNameGlobally(teamId, folderName) {
140
+ const spaces = await this.getSpaces(teamId);
141
+ for (const space of spaces) {
142
+ const folders = await this.getFolders(space.id);
143
+ const folder = folders.find(folder => folder.name.toLowerCase() === folderName.toLowerCase());
144
+ if (folder) {
145
+ return { folder, space };
146
+ }
147
+ }
148
+ return null;
149
+ }
113
150
  async duplicateTask(taskId, listId) {
114
151
  const response = await this.client.post(`/task/${taskId}/duplicate`, {
115
152
  list: listId
@@ -123,8 +160,4 @@ export class ClickUpService {
123
160
  const response = await this.client.put(`/list/${listId}`, data);
124
161
  return response.data;
125
162
  }
126
- async findListByName(spaceId, listName) {
127
- const lists = await this.getLists(spaceId);
128
- return lists.find(list => list.name.toLowerCase() === listName.toLowerCase()) || null;
129
- }
130
163
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taazkareem/clickup-mcp-server",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
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",
@@ -41,7 +41,7 @@
41
41
  },
42
42
  "homepage": "https://github.com/taazkareem/clickup-mcp-server#readme",
43
43
  "dependencies": {
44
- "@modelcontextprotocol/sdk": "0.6.0",
44
+ "@modelcontextprotocol/sdk": "^1.4.1",
45
45
  "axios": "^1.6.7",
46
46
  "dotenv": "^16.4.1"
47
47
  },