@taazkareem/clickup-mcp-server 0.3.0 → 0.4.1
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 +24 -9
- package/build/config.js +8 -1
- package/build/handlers/prompts.js +25 -0
- package/build/handlers/tools.js +38 -0
- package/build/index.js +203 -236
- package/build/services/clickup.js +37 -4
- package/build/utils/resolvers.js +48 -0
- package/package.json +2 -2
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
|
|
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
|
|
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. **
|
|
85
|
-
- Lists
|
|
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
|
-
|
|
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
|
-
|
|
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/config.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import dotenv from 'dotenv';
|
|
2
2
|
// Load environment variables from .env file
|
|
3
3
|
dotenv.config();
|
|
4
|
+
console.log('Environment variables received:', {
|
|
5
|
+
CLICKUP_API_KEY: process.env.CLICKUP_API_KEY,
|
|
6
|
+
TEAM_ID: process.env.TEAM_ID
|
|
7
|
+
});
|
|
4
8
|
// Parse command line arguments for --env flags
|
|
5
9
|
const args = process.argv.slice(2);
|
|
10
|
+
console.log('Command line arguments:', args);
|
|
6
11
|
const envArgs = {};
|
|
7
12
|
for (let i = 0; i < args.length; i++) {
|
|
8
13
|
if (args[i] === '--env' && i + 1 < args.length) {
|
|
@@ -14,10 +19,12 @@ for (let i = 0; i < args.length; i++) {
|
|
|
14
19
|
i++; // Skip the next argument since we used it
|
|
15
20
|
}
|
|
16
21
|
}
|
|
22
|
+
console.log('Parsed environment arguments:', envArgs);
|
|
17
23
|
const configuration = {
|
|
18
24
|
clickupApiKey: envArgs.clickupApiKey || process.env.CLICKUP_API_KEY || '',
|
|
19
|
-
teamId: envArgs.teamId || process.env.TEAM_ID || ''
|
|
25
|
+
teamId: envArgs.teamId || process.env.TEAM_ID || ''
|
|
20
26
|
};
|
|
27
|
+
console.log('Final configuration:', configuration);
|
|
21
28
|
// Check for missing environment variables
|
|
22
29
|
const missingEnvVars = Object.entries(configuration)
|
|
23
30
|
.filter(([_, value]) => !value)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { getAllTasks } from '../utils/resolvers.js';
|
|
2
|
+
export async function handleSummarizeTasks(clickup, teamId) {
|
|
3
|
+
const { tasks } = await getAllTasks(clickup, teamId);
|
|
4
|
+
let output = "Summarized Tasks:\n\n";
|
|
5
|
+
for (const task of tasks) {
|
|
6
|
+
output += `- ${task.name}: ${task.description}\n`;
|
|
7
|
+
}
|
|
8
|
+
return output;
|
|
9
|
+
}
|
|
10
|
+
export async function handleAnalyzeTaskPriorities(clickup, teamId) {
|
|
11
|
+
const { tasks } = await getAllTasks(clickup, teamId);
|
|
12
|
+
const priorities = tasks.map(task => task.priority?.priority);
|
|
13
|
+
const uniquePriorities = [...new Set(priorities.filter(p => p !== undefined))];
|
|
14
|
+
const priorityCounts = uniquePriorities.map(priority => ({
|
|
15
|
+
priority,
|
|
16
|
+
count: priorities.filter(p => p === priority).length
|
|
17
|
+
}));
|
|
18
|
+
let output = "Task Priorities Analysis:\n\n";
|
|
19
|
+
output += "Available Priorities: " + uniquePriorities.join(', ') + "\n\n";
|
|
20
|
+
output += "Priority Counts:\n";
|
|
21
|
+
for (const priority of priorityCounts) {
|
|
22
|
+
output += `- Priority ${priority.priority}: ${priority.count}\n`;
|
|
23
|
+
}
|
|
24
|
+
return output;
|
|
25
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { resolveListId } from '../utils/resolvers.js';
|
|
2
|
+
export async function handleWorkspaceHierarchy(clickup, teamId) {
|
|
3
|
+
const spaces = await clickup.getSpaces(teamId);
|
|
4
|
+
const allLists = await clickup.getAllLists(teamId);
|
|
5
|
+
let output = "ClickUp Workspace Hierarchy:\n\n";
|
|
6
|
+
for (const space of spaces) {
|
|
7
|
+
output += `Space: ${space.name} (ID: ${space.id})\n`;
|
|
8
|
+
const folders = await clickup.getFolders(space.id);
|
|
9
|
+
for (const folder of folders) {
|
|
10
|
+
output += ` ├─ Folder: ${folder.name} (ID: ${folder.id})\n`;
|
|
11
|
+
const folderLists = folder.lists || [];
|
|
12
|
+
for (const list of folderLists) {
|
|
13
|
+
const { statuses } = await clickup.getTasks(list.id);
|
|
14
|
+
output += ` │ └─ List: ${list.name} (ID: ${list.id})\n`;
|
|
15
|
+
output += ` │ Available Statuses: ${statuses.join(', ')}\n`;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const spaceLists = allLists.filter(list => list.space &&
|
|
19
|
+
list.space.id === space.id &&
|
|
20
|
+
!folders.some(folder => folder.lists?.some(fl => fl.id === list.id)));
|
|
21
|
+
if (spaceLists.length > 0) {
|
|
22
|
+
output += " ├─ Lists (not in folders):\n";
|
|
23
|
+
for (const list of spaceLists) {
|
|
24
|
+
const { statuses } = await clickup.getTasks(list.id);
|
|
25
|
+
output += ` │ └─ List: ${list.name} (ID: ${list.id})\n`;
|
|
26
|
+
output += ` │ Available Statuses: ${statuses.join(', ')}\n`;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
output += "\n";
|
|
30
|
+
}
|
|
31
|
+
return output;
|
|
32
|
+
}
|
|
33
|
+
export async function handleCreateTask(clickup, teamId, args) {
|
|
34
|
+
const listId = await resolveListId(clickup, teamId, args.listId, args.listName);
|
|
35
|
+
const { listId: _, listName: __, ...taskData } = args;
|
|
36
|
+
return await clickup.createTask(listId, taskData);
|
|
37
|
+
}
|
|
38
|
+
// Add other handler functions for each tool...
|
package/build/index.js
CHANGED
|
@@ -1,36 +1,31 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* This is a template MCP server that implements a simple ClickUp task management system.
|
|
4
|
-
* It demonstrates core MCP concepts like resources, tools, and prompts by allowing:
|
|
5
|
-
* - Listing ClickUp tasks as resources
|
|
6
|
-
* - Reading individual ClickUp tasks
|
|
7
|
-
* - Creating new ClickUp tasks via a tool
|
|
8
|
-
* - Updating existing ClickUp tasks via a tool
|
|
9
|
-
* - Summarizing all ClickUp tasks via a prompt
|
|
10
|
-
* - Analyzing task priorities via a prompt
|
|
11
|
-
* - Generating detailed descriptions for tasks via a prompt
|
|
12
|
-
*/
|
|
13
2
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
14
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
15
4
|
import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
16
5
|
import { ClickUpService } from "./services/clickup.js";
|
|
17
6
|
import config from "./config.js";
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
};
|
|
7
|
+
import { handleWorkspaceHierarchy, handleCreateTask } from "./handlers/tools.js";
|
|
8
|
+
import { handleSummarizeTasks, handleAnalyzeTaskPriorities } from "./handlers/prompts.js";
|
|
9
|
+
import { getAllTasks } from "./utils/resolvers.js";
|
|
10
|
+
console.log('Server starting up...');
|
|
11
|
+
console.log('Config loaded:', {
|
|
12
|
+
clickupApiKey: config.clickupApiKey ? '***' : 'missing',
|
|
13
|
+
teamId: config.teamId || 'missing'
|
|
14
|
+
});
|
|
26
15
|
// Initialize ClickUp service
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
16
|
+
let clickup;
|
|
17
|
+
try {
|
|
18
|
+
console.log('Initializing ClickUp service...');
|
|
19
|
+
clickup = ClickUpService.initialize(config.clickupApiKey);
|
|
20
|
+
console.log('ClickUp service initialized successfully');
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
console.error("Failed to initialize ClickUp service:", error);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
console.log('Creating MCP server...');
|
|
32
27
|
const server = new Server({
|
|
33
|
-
name: "clickup
|
|
28
|
+
name: "clickup",
|
|
34
29
|
version: "0.1.0",
|
|
35
30
|
}, {
|
|
36
31
|
capabilities: {
|
|
@@ -39,40 +34,31 @@ const server = new Server({
|
|
|
39
34
|
prompts: {},
|
|
40
35
|
},
|
|
41
36
|
});
|
|
37
|
+
console.log('MCP server created');
|
|
42
38
|
/**
|
|
43
39
|
* Handler for listing available ClickUp tasks as resources.
|
|
44
|
-
* Each task is exposed as a resource with:
|
|
45
|
-
* - A clickup:// URI scheme
|
|
46
|
-
* - JSON MIME type
|
|
47
|
-
* - Human readable name and description (including the task name and description)
|
|
48
40
|
*/
|
|
49
41
|
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
42
|
+
console.log('Handling ListResources request');
|
|
50
43
|
try {
|
|
51
|
-
const spaces = await clickup
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
description: task.description || `Task in ${list.name} (${space.name})`,
|
|
62
|
-
tags: []
|
|
63
|
-
})));
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return { resources };
|
|
44
|
+
const { tasks, spaces } = await getAllTasks(clickup, config.teamId);
|
|
45
|
+
return {
|
|
46
|
+
resources: tasks.map(task => ({
|
|
47
|
+
uri: `clickup://task/${task.id}`,
|
|
48
|
+
mimeType: "application/json",
|
|
49
|
+
name: task.name,
|
|
50
|
+
description: task.description || `Task in ${task.list.name} (${task.space.name})`,
|
|
51
|
+
tags: []
|
|
52
|
+
}))
|
|
53
|
+
};
|
|
67
54
|
}
|
|
68
55
|
catch (error) {
|
|
69
|
-
console.error('Error
|
|
56
|
+
console.error('Error in ListResources:', error);
|
|
70
57
|
throw error;
|
|
71
58
|
}
|
|
72
59
|
});
|
|
73
60
|
/**
|
|
74
61
|
* Handler for reading the contents of a specific ClickUp task.
|
|
75
|
-
* Takes a clickup:// URI and returns the task content as JSON.
|
|
76
62
|
*/
|
|
77
63
|
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
78
64
|
try {
|
|
@@ -94,15 +80,15 @@ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
|
94
80
|
}
|
|
95
81
|
});
|
|
96
82
|
/**
|
|
97
|
-
* Handler
|
|
98
|
-
* Exposes tools for listing spaces, creating tasks, and updating tasks.
|
|
83
|
+
* Handler for listing available tools.
|
|
99
84
|
*/
|
|
100
85
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
86
|
+
console.log('Handling ListTools request');
|
|
101
87
|
return {
|
|
102
88
|
tools: [
|
|
103
89
|
{
|
|
104
|
-
name: "
|
|
105
|
-
description: "List
|
|
90
|
+
name: "workspace_hierarchy",
|
|
91
|
+
description: "List complete hierarchy of the ClickUp workspace",
|
|
106
92
|
inputSchema: {
|
|
107
93
|
type: "object",
|
|
108
94
|
properties: {},
|
|
@@ -117,7 +103,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
117
103
|
properties: {
|
|
118
104
|
listId: {
|
|
119
105
|
type: "string",
|
|
120
|
-
description: "ID of the list to create the task in"
|
|
106
|
+
description: "ID of the list to create the task in (optional if listName is provided)"
|
|
107
|
+
},
|
|
108
|
+
listName: {
|
|
109
|
+
type: "string",
|
|
110
|
+
description: "Name of the list to create the task in (optional if listId is provided)"
|
|
121
111
|
},
|
|
122
112
|
name: {
|
|
123
113
|
type: "string",
|
|
@@ -140,7 +130,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
140
130
|
description: "Due date of the task (ISO string)"
|
|
141
131
|
}
|
|
142
132
|
},
|
|
143
|
-
required: ["
|
|
133
|
+
required: ["name"]
|
|
144
134
|
}
|
|
145
135
|
},
|
|
146
136
|
{
|
|
@@ -151,7 +141,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
151
141
|
properties: {
|
|
152
142
|
listId: {
|
|
153
143
|
type: "string",
|
|
154
|
-
description: "ID of the list to create the tasks in"
|
|
144
|
+
description: "ID of the list to create the tasks in (optional if listName is provided)"
|
|
145
|
+
},
|
|
146
|
+
listName: {
|
|
147
|
+
type: "string",
|
|
148
|
+
description: "Name of the list to create the tasks in (optional if listId is provided)"
|
|
155
149
|
},
|
|
156
150
|
tasks: {
|
|
157
151
|
type: "array",
|
|
@@ -177,7 +171,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
177
171
|
},
|
|
178
172
|
dueDate: {
|
|
179
173
|
type: "string",
|
|
180
|
-
description: "Due date
|
|
174
|
+
description: "Due date (ISO string)"
|
|
181
175
|
},
|
|
182
176
|
assignees: {
|
|
183
177
|
type: "array",
|
|
@@ -191,7 +185,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
191
185
|
}
|
|
192
186
|
}
|
|
193
187
|
},
|
|
194
|
-
required: ["
|
|
188
|
+
required: ["tasks"]
|
|
195
189
|
}
|
|
196
190
|
},
|
|
197
191
|
{
|
|
@@ -312,10 +306,14 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
312
306
|
},
|
|
313
307
|
listId: {
|
|
314
308
|
type: "string",
|
|
315
|
-
description: "ID of the destination list"
|
|
309
|
+
description: "ID of the destination list (optional if listName is provided)"
|
|
310
|
+
},
|
|
311
|
+
listName: {
|
|
312
|
+
type: "string",
|
|
313
|
+
description: "Name of the destination list (optional if listId is provided)"
|
|
316
314
|
}
|
|
317
315
|
},
|
|
318
|
-
required: ["taskId"
|
|
316
|
+
required: ["taskId"]
|
|
319
317
|
}
|
|
320
318
|
},
|
|
321
319
|
{
|
|
@@ -330,10 +328,14 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
330
328
|
},
|
|
331
329
|
listId: {
|
|
332
330
|
type: "string",
|
|
333
|
-
description: "ID of the list
|
|
331
|
+
description: "ID of the destination list (optional if listName is provided)"
|
|
332
|
+
},
|
|
333
|
+
listName: {
|
|
334
|
+
type: "string",
|
|
335
|
+
description: "Name of the destination list (optional if listId is provided)"
|
|
334
336
|
}
|
|
335
337
|
},
|
|
336
|
-
required: ["taskId"
|
|
338
|
+
required: ["taskId"]
|
|
337
339
|
}
|
|
338
340
|
},
|
|
339
341
|
{
|
|
@@ -374,36 +376,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
374
376
|
};
|
|
375
377
|
});
|
|
376
378
|
/**
|
|
377
|
-
* Handler for
|
|
378
|
-
* Handles the execution of tools like listing spaces, creating tasks, and updating tasks.
|
|
379
|
+
* Handler for executing tools.
|
|
379
380
|
*/
|
|
380
381
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
381
382
|
try {
|
|
382
383
|
switch (request.params.name) {
|
|
383
|
-
case "
|
|
384
|
-
const
|
|
385
|
-
const allLists = await clickup.getAllLists(config.teamId);
|
|
386
|
-
let output = "Available Spaces and Lists:\n\n";
|
|
387
|
-
for (const space of spaces) {
|
|
388
|
-
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`;
|
|
394
|
-
}
|
|
395
|
-
output += "\n";
|
|
396
|
-
}
|
|
397
|
-
// Add lists without spaces at the end
|
|
398
|
-
const listsWithoutSpace = allLists.filter(list => !list.space);
|
|
399
|
-
if (listsWithoutSpace.length > 0) {
|
|
400
|
-
output += "Lists without assigned spaces:\n";
|
|
401
|
-
for (const list of listsWithoutSpace) {
|
|
402
|
-
const { statuses } = await clickup.getTasks(list.id);
|
|
403
|
-
output += ` └─ List: ${list.name} (ID: ${list.id})\n`;
|
|
404
|
-
output += ` Available Statuses: ${statuses.join(', ')}\n`;
|
|
405
|
-
}
|
|
406
|
-
}
|
|
384
|
+
case "workspace_hierarchy": {
|
|
385
|
+
const output = await handleWorkspaceHierarchy(clickup, config.teamId);
|
|
407
386
|
return {
|
|
408
387
|
content: [{
|
|
409
388
|
type: "text",
|
|
@@ -413,11 +392,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
413
392
|
}
|
|
414
393
|
case "create_task": {
|
|
415
394
|
const args = request.params.arguments;
|
|
416
|
-
|
|
417
|
-
throw new Error("listId and name are required");
|
|
418
|
-
}
|
|
419
|
-
const { listId, ...taskData } = args;
|
|
420
|
-
const task = await clickup.createTask(listId, taskData);
|
|
395
|
+
const task = await handleCreateTask(clickup, config.teamId, args);
|
|
421
396
|
return {
|
|
422
397
|
content: [{
|
|
423
398
|
type: "text",
|
|
@@ -427,10 +402,21 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
427
402
|
}
|
|
428
403
|
case "create_bulk_tasks": {
|
|
429
404
|
const args = request.params.arguments;
|
|
430
|
-
|
|
431
|
-
|
|
405
|
+
let listId = args.listId;
|
|
406
|
+
if (!listId && args.listName) {
|
|
407
|
+
const result = await clickup.findListByNameGlobally(config.teamId, args.listName);
|
|
408
|
+
if (!result) {
|
|
409
|
+
throw new Error(`List with name "${args.listName}" not found`);
|
|
410
|
+
}
|
|
411
|
+
listId = result.list.id;
|
|
432
412
|
}
|
|
433
|
-
|
|
413
|
+
if (!listId) {
|
|
414
|
+
throw new Error("Either listId or listName is required");
|
|
415
|
+
}
|
|
416
|
+
if (!args.tasks || !args.tasks.length) {
|
|
417
|
+
throw new Error("At least one task is required");
|
|
418
|
+
}
|
|
419
|
+
const { listId: _, listName: __, tasks } = args;
|
|
434
420
|
const createdTasks = await clickup.createBulkTasks(listId, { tasks });
|
|
435
421
|
return {
|
|
436
422
|
content: [{
|
|
@@ -444,6 +430,29 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
444
430
|
if (!args.name) {
|
|
445
431
|
throw new Error("name is required");
|
|
446
432
|
}
|
|
433
|
+
// If folder is specified, create list in folder
|
|
434
|
+
if (args.folderName || args.folderId) {
|
|
435
|
+
let folderId = args.folderId;
|
|
436
|
+
if (!folderId && args.folderName) {
|
|
437
|
+
const result = await clickup.findFolderByNameGlobally(config.teamId, args.folderName);
|
|
438
|
+
if (!result) {
|
|
439
|
+
throw new Error(`Folder with name "${args.folderName}" not found`);
|
|
440
|
+
}
|
|
441
|
+
folderId = result.folder.id;
|
|
442
|
+
}
|
|
443
|
+
if (!folderId) {
|
|
444
|
+
throw new Error("Either folderId or folderName must be provided");
|
|
445
|
+
}
|
|
446
|
+
const { spaceId: _, spaceName: __, folderName: ___, folderId: ____, ...listData } = args;
|
|
447
|
+
const list = await clickup.createListInFolder(folderId, listData);
|
|
448
|
+
return {
|
|
449
|
+
content: [{
|
|
450
|
+
type: "text",
|
|
451
|
+
text: `Created list ${list.id}: ${list.name} in folder`
|
|
452
|
+
}]
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
// Otherwise, create list in space
|
|
447
456
|
let spaceId = args.spaceId;
|
|
448
457
|
if (!spaceId && args.spaceName) {
|
|
449
458
|
const space = await clickup.findSpaceByName(config.teamId, args.spaceName);
|
|
@@ -455,7 +464,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
455
464
|
if (!spaceId) {
|
|
456
465
|
throw new Error("Either spaceId or spaceName must be provided");
|
|
457
466
|
}
|
|
458
|
-
const { spaceId: _, spaceName: __, ...listData } = args;
|
|
467
|
+
const { spaceId: _, spaceName: __, folderName: ___, folderId: ____, ...listData } = args;
|
|
459
468
|
const list = await clickup.createList(spaceId, listData);
|
|
460
469
|
return {
|
|
461
470
|
content: [{
|
|
@@ -496,58 +505,78 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
496
505
|
}
|
|
497
506
|
let folderId = args.folderId;
|
|
498
507
|
if (!folderId && args.folderName) {
|
|
499
|
-
|
|
500
|
-
if (!
|
|
501
|
-
const space = await clickup.findSpaceByName(config.teamId, args.spaceName);
|
|
502
|
-
if (!space) {
|
|
503
|
-
throw new Error(`Space with name "${args.spaceName}" not found`);
|
|
504
|
-
}
|
|
505
|
-
spaceId = space.id;
|
|
506
|
-
}
|
|
507
|
-
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) {
|
|
508
|
+
const result = await clickup.findFolderByNameGlobally(config.teamId, args.folderName);
|
|
509
|
+
if (!result) {
|
|
512
510
|
throw new Error(`Folder with name "${args.folderName}" not found`);
|
|
513
511
|
}
|
|
514
|
-
folderId = folder.id;
|
|
512
|
+
folderId = result.folder.id;
|
|
515
513
|
}
|
|
516
514
|
if (!folderId) {
|
|
517
|
-
throw new Error("Either folderId or folderName
|
|
515
|
+
throw new Error("Either folderId or folderName is required");
|
|
518
516
|
}
|
|
519
|
-
const
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
type: "text",
|
|
524
|
-
text: `Created list ${list.id}: ${list.name} in folder`
|
|
525
|
-
}]
|
|
517
|
+
const listData = {
|
|
518
|
+
name: args.name,
|
|
519
|
+
content: args.content,
|
|
520
|
+
status: args.status
|
|
526
521
|
};
|
|
522
|
+
try {
|
|
523
|
+
const list = await clickup.createListInFolder(folderId, listData);
|
|
524
|
+
return {
|
|
525
|
+
content: [{
|
|
526
|
+
type: "text",
|
|
527
|
+
text: `Created list ${list.id}: ${list.name} in folder`
|
|
528
|
+
}]
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
catch (error) {
|
|
532
|
+
throw new Error(`Failed to create list: ${error.message}`);
|
|
533
|
+
}
|
|
527
534
|
}
|
|
528
535
|
case "move_task": {
|
|
529
536
|
const args = request.params.arguments;
|
|
530
|
-
if (!args.taskId
|
|
531
|
-
throw new Error("taskId
|
|
537
|
+
if (!args.taskId) {
|
|
538
|
+
throw new Error("taskId is required");
|
|
539
|
+
}
|
|
540
|
+
let listId = args.listId;
|
|
541
|
+
if (!listId && args.listName) {
|
|
542
|
+
const result = await clickup.findListByNameGlobally(config.teamId, args.listName);
|
|
543
|
+
if (!result) {
|
|
544
|
+
throw new Error(`List with name "${args.listName}" not found`);
|
|
545
|
+
}
|
|
546
|
+
listId = result.list.id;
|
|
547
|
+
}
|
|
548
|
+
if (!listId) {
|
|
549
|
+
throw new Error("Either listId or listName is required");
|
|
532
550
|
}
|
|
533
|
-
const task = await clickup.moveTask(args.taskId,
|
|
551
|
+
const task = await clickup.moveTask(args.taskId, listId);
|
|
534
552
|
return {
|
|
535
553
|
content: [{
|
|
536
554
|
type: "text",
|
|
537
|
-
text: `Moved task ${task.id} to list ${
|
|
555
|
+
text: `Moved task ${task.id} to list ${listId}`
|
|
538
556
|
}]
|
|
539
557
|
};
|
|
540
558
|
}
|
|
541
559
|
case "duplicate_task": {
|
|
542
560
|
const args = request.params.arguments;
|
|
543
|
-
if (!args.taskId
|
|
544
|
-
throw new Error("taskId
|
|
561
|
+
if (!args.taskId) {
|
|
562
|
+
throw new Error("taskId is required");
|
|
545
563
|
}
|
|
546
|
-
|
|
564
|
+
let listId = args.listId;
|
|
565
|
+
if (!listId && args.listName) {
|
|
566
|
+
const result = await clickup.findListByNameGlobally(config.teamId, args.listName);
|
|
567
|
+
if (!result) {
|
|
568
|
+
throw new Error(`List with name "${args.listName}" not found`);
|
|
569
|
+
}
|
|
570
|
+
listId = result.list.id;
|
|
571
|
+
}
|
|
572
|
+
if (!listId) {
|
|
573
|
+
throw new Error("Either listId or listName is required");
|
|
574
|
+
}
|
|
575
|
+
const task = await clickup.duplicateTask(args.taskId, listId);
|
|
547
576
|
return {
|
|
548
577
|
content: [{
|
|
549
578
|
type: "text",
|
|
550
|
-
text: `Duplicated task ${args.taskId} to new task ${task.id} in list ${
|
|
579
|
+
text: `Duplicated task ${args.taskId} to new task ${task.id} in list ${listId}`
|
|
551
580
|
}]
|
|
552
581
|
};
|
|
553
582
|
}
|
|
@@ -556,8 +585,14 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
556
585
|
if (!args.taskId) {
|
|
557
586
|
throw new Error("taskId is required");
|
|
558
587
|
}
|
|
559
|
-
const
|
|
560
|
-
const task = await clickup.updateTask(taskId,
|
|
588
|
+
const dueDate = args.due_date ? new Date(args.due_date).getTime() : undefined;
|
|
589
|
+
const task = await clickup.updateTask(args.taskId, {
|
|
590
|
+
name: args.name,
|
|
591
|
+
description: args.description,
|
|
592
|
+
status: args.status,
|
|
593
|
+
priority: args.priority,
|
|
594
|
+
due_date: dueDate
|
|
595
|
+
});
|
|
561
596
|
return {
|
|
562
597
|
content: [{
|
|
563
598
|
type: "text",
|
|
@@ -570,147 +605,79 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
570
605
|
}
|
|
571
606
|
}
|
|
572
607
|
catch (error) {
|
|
573
|
-
console.error('Error
|
|
608
|
+
console.error('Error executing tool:', error);
|
|
574
609
|
throw error;
|
|
575
610
|
}
|
|
576
611
|
});
|
|
577
612
|
/**
|
|
578
|
-
*
|
|
579
|
-
* Prompts include summarizing tasks, analyzing priorities, and generating task descriptions.
|
|
613
|
+
* Handler for listing available prompts.
|
|
580
614
|
*/
|
|
581
615
|
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
582
616
|
return {
|
|
583
617
|
prompts: [
|
|
584
618
|
{
|
|
585
619
|
name: "summarize_tasks",
|
|
586
|
-
description: "Summarize all tasks
|
|
587
|
-
},
|
|
588
|
-
{
|
|
589
|
-
name: "analyze_priorities",
|
|
590
|
-
description: "Analyze task priorities and suggest optimizations",
|
|
620
|
+
description: "Summarize all ClickUp tasks"
|
|
591
621
|
},
|
|
592
622
|
{
|
|
593
|
-
name: "
|
|
594
|
-
description: "
|
|
623
|
+
name: "analyze_task_priorities",
|
|
624
|
+
description: "Analyze task priorities"
|
|
595
625
|
}
|
|
596
626
|
]
|
|
597
627
|
};
|
|
598
628
|
});
|
|
629
|
+
/**
|
|
630
|
+
* Handler for getting a specific prompt.
|
|
631
|
+
*/
|
|
599
632
|
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
600
633
|
try {
|
|
601
634
|
switch (request.params.name) {
|
|
602
635
|
case "summarize_tasks": {
|
|
603
|
-
const
|
|
604
|
-
const tasks = [];
|
|
605
|
-
// Gather all tasks
|
|
606
|
-
for (const space of spaces) {
|
|
607
|
-
const lists = await clickup.getLists(space.id);
|
|
608
|
-
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
|
-
})));
|
|
618
|
-
}
|
|
619
|
-
}
|
|
636
|
+
const output = await handleSummarizeTasks(clickup, config.teamId);
|
|
620
637
|
return {
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
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
|
-
]
|
|
641
|
-
};
|
|
642
|
-
}
|
|
643
|
-
case "analyze_priorities": {
|
|
644
|
-
const spaces = await clickup.getSpaces(config.teamId);
|
|
645
|
-
const tasks = [];
|
|
646
|
-
for (const space of spaces) {
|
|
647
|
-
const lists = await clickup.getLists(space.id);
|
|
648
|
-
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
|
-
})));
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
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
|
-
]
|
|
638
|
+
content: [{
|
|
639
|
+
type: "text",
|
|
640
|
+
text: output
|
|
641
|
+
}]
|
|
681
642
|
};
|
|
682
643
|
}
|
|
683
|
-
case "
|
|
644
|
+
case "analyze_task_priorities": {
|
|
645
|
+
const output = await handleAnalyzeTaskPriorities(clickup, config.teamId);
|
|
684
646
|
return {
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
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
|
-
}
|
|
692
|
-
}
|
|
693
|
-
]
|
|
647
|
+
content: [{
|
|
648
|
+
type: "text",
|
|
649
|
+
text: output
|
|
650
|
+
}]
|
|
694
651
|
};
|
|
695
652
|
}
|
|
696
653
|
default:
|
|
697
|
-
throw new Error("
|
|
654
|
+
throw new Error("Prompt not found");
|
|
698
655
|
}
|
|
699
656
|
}
|
|
700
657
|
catch (error) {
|
|
701
|
-
console.error('Error
|
|
658
|
+
console.error('Error getting prompt:', error);
|
|
702
659
|
throw error;
|
|
703
660
|
}
|
|
704
661
|
});
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
}
|
|
713
|
-
main().catch((error) => {
|
|
714
|
-
console.error("Server error:", error);
|
|
662
|
+
// Start the server
|
|
663
|
+
console.log('Setting up transport...');
|
|
664
|
+
const transport = new StdioServerTransport();
|
|
665
|
+
// Connect the server to the transport
|
|
666
|
+
console.log('Connecting server to transport...');
|
|
667
|
+
server.connect(transport).catch(error => {
|
|
668
|
+
console.error('Error connecting server to transport:', error);
|
|
715
669
|
process.exit(1);
|
|
716
670
|
});
|
|
671
|
+
// Handle process signals
|
|
672
|
+
process.on('SIGINT', () => {
|
|
673
|
+
console.log('Received SIGINT. Shutting down...');
|
|
674
|
+
transport.close();
|
|
675
|
+
});
|
|
676
|
+
process.on('SIGTERM', () => {
|
|
677
|
+
console.log('Received SIGTERM. Shutting down...');
|
|
678
|
+
transport.close();
|
|
679
|
+
});
|
|
680
|
+
// Prevent unhandled promise rejections from crashing the server
|
|
681
|
+
process.on('unhandledRejection', (error) => {
|
|
682
|
+
console.error('Unhandled promise rejection:', error);
|
|
683
|
+
});
|
|
@@ -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
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export async function resolveListId(clickup, teamId, listId, listName) {
|
|
2
|
+
if (listId)
|
|
3
|
+
return listId;
|
|
4
|
+
if (!listName) {
|
|
5
|
+
throw new Error("Either listId or listName is required");
|
|
6
|
+
}
|
|
7
|
+
const result = await clickup.findListByNameGlobally(teamId, listName);
|
|
8
|
+
if (!result) {
|
|
9
|
+
throw new Error(`List with name "${listName}" not found`);
|
|
10
|
+
}
|
|
11
|
+
return result.list.id;
|
|
12
|
+
}
|
|
13
|
+
export async function resolveSpaceId(clickup, teamId, spaceId, spaceName) {
|
|
14
|
+
if (spaceId)
|
|
15
|
+
return spaceId;
|
|
16
|
+
if (!spaceName) {
|
|
17
|
+
throw new Error("Either spaceId or spaceName is required");
|
|
18
|
+
}
|
|
19
|
+
const space = await clickup.findSpaceByName(teamId, spaceName);
|
|
20
|
+
if (!space) {
|
|
21
|
+
throw new Error(`Space with name "${spaceName}" not found`);
|
|
22
|
+
}
|
|
23
|
+
return space.id;
|
|
24
|
+
}
|
|
25
|
+
export async function resolveFolderId(clickup, teamId, folderId, folderName) {
|
|
26
|
+
if (folderId)
|
|
27
|
+
return folderId;
|
|
28
|
+
if (!folderName) {
|
|
29
|
+
throw new Error("Either folderId or folderName is required");
|
|
30
|
+
}
|
|
31
|
+
const result = await clickup.findFolderByNameGlobally(teamId, folderName);
|
|
32
|
+
if (!result) {
|
|
33
|
+
throw new Error(`Folder with name "${folderName}" not found`);
|
|
34
|
+
}
|
|
35
|
+
return result.folder.id;
|
|
36
|
+
}
|
|
37
|
+
export async function getAllTasks(clickup, teamId) {
|
|
38
|
+
const spaces = await clickup.getSpaces(teamId);
|
|
39
|
+
const spacePromises = spaces.map(async (space) => {
|
|
40
|
+
const lists = await clickup.getLists(space.id);
|
|
41
|
+
const listPromises = lists.map(list => clickup.getTasks(list.id));
|
|
42
|
+
const listResults = await Promise.all(listPromises);
|
|
43
|
+
return listResults.flatMap(result => result.tasks);
|
|
44
|
+
});
|
|
45
|
+
const tasksPerSpace = await Promise.all(spacePromises);
|
|
46
|
+
const allTasks = tasksPerSpace.flat();
|
|
47
|
+
return { tasks: allTasks, spaces };
|
|
48
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taazkareem/clickup-mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
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": "
|
|
44
|
+
"@modelcontextprotocol/sdk": "^1.4.1",
|
|
45
45
|
"axios": "^1.6.7",
|
|
46
46
|
"dotenv": "^16.4.1"
|
|
47
47
|
},
|