@taazkareem/clickup-mcp-server 0.4.30 → 0.4.40
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 -2
- package/build/config.js +4 -14
- package/build/handlers/prompts.js +0 -53
- package/build/handlers/tools.js +30 -303
- package/build/index.js +646 -175
- package/build/services/clickup.js +5 -171
- package/build/types/clickup.js +0 -7
- package/build/utils/logger.js +39 -45
- package/build/utils/resolvers.js +0 -50
- package/package.json +5 -7
- package/LICENSE +0 -21
package/README.md
CHANGED
|
@@ -88,8 +88,6 @@ To add this server to Roo Code:
|
|
|
88
88
|
**Note:** Do not use the example settings and credentials provided here; use your own.
|
|
89
89
|
5. Save the `cline_mcp_settings.json` file.
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
|
|
93
91
|
> **Security Note**: Your API key will be stored securely and will not be exposed to AI models.
|
|
94
92
|
|
|
95
93
|
### Available Tools
|
package/build/config.js
CHANGED
|
@@ -1,23 +1,13 @@
|
|
|
1
1
|
import dotenv from 'dotenv';
|
|
2
|
-
// Function to format messages as JSON-RPC 2.0
|
|
3
|
-
function logMessage(method, params) {
|
|
4
|
-
const jsonRpcMessage = {
|
|
5
|
-
jsonrpc: "2.0",
|
|
6
|
-
method,
|
|
7
|
-
params,
|
|
8
|
-
id: Date.now()
|
|
9
|
-
};
|
|
10
|
-
console.log(JSON.stringify(jsonRpcMessage));
|
|
11
|
-
}
|
|
12
2
|
// Load environment variables from .env file
|
|
13
3
|
dotenv.config();
|
|
14
|
-
|
|
4
|
+
console.log('Environment variables received:', {
|
|
15
5
|
CLICKUP_API_KEY: process.env.CLICKUP_API_KEY,
|
|
16
6
|
TEAM_ID: process.env.TEAM_ID
|
|
17
7
|
});
|
|
18
8
|
// Parse command line arguments for --env flags
|
|
19
9
|
const args = process.argv.slice(2);
|
|
20
|
-
|
|
10
|
+
console.log('Command line arguments:', args);
|
|
21
11
|
const envArgs = {};
|
|
22
12
|
for (let i = 0; i < args.length; i++) {
|
|
23
13
|
if (args[i] === '--env' && i + 1 < args.length) {
|
|
@@ -29,12 +19,12 @@ for (let i = 0; i < args.length; i++) {
|
|
|
29
19
|
i++; // Skip the next argument since we used it
|
|
30
20
|
}
|
|
31
21
|
}
|
|
32
|
-
|
|
22
|
+
console.log('Parsed environment arguments:', envArgs);
|
|
33
23
|
const configuration = {
|
|
34
24
|
clickupApiKey: envArgs.clickupApiKey || process.env.CLICKUP_API_KEY || '',
|
|
35
25
|
teamId: envArgs.teamId || process.env.TEAM_ID || ''
|
|
36
26
|
};
|
|
37
|
-
|
|
27
|
+
console.log('Final configuration:', configuration);
|
|
38
28
|
// Check for missing environment variables
|
|
39
29
|
const missingEnvVars = Object.entries(configuration)
|
|
40
30
|
.filter(([_, value]) => !value)
|
|
@@ -1,28 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Prompt handlers for ClickUp MCP server.
|
|
3
|
-
* Implements handlers for AI-powered analysis and summarization of ClickUp data.
|
|
4
|
-
* Each handler processes ClickUp data and returns formatted text output.
|
|
5
|
-
* @module handlers/prompts
|
|
6
|
-
*/
|
|
7
1
|
import { getAllTasks } from '../utils/resolvers.js';
|
|
8
|
-
/**
|
|
9
|
-
* Generates a summary of all tasks in the workspace
|
|
10
|
-
* Lists each task with its name and description, providing a quick overview
|
|
11
|
-
* of all work items across spaces and lists.
|
|
12
|
-
*
|
|
13
|
-
* @param clickup - ClickUp service instance for API operations
|
|
14
|
-
* @param teamId - Team ID to fetch tasks for
|
|
15
|
-
* @returns Promise resolving to formatted text summary of all tasks
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* Output format:
|
|
19
|
-
* ```
|
|
20
|
-
* Summarized Tasks:
|
|
21
|
-
*
|
|
22
|
-
* - Task Name 1: Description of first task
|
|
23
|
-
* - Task Name 2: Description of second task
|
|
24
|
-
* ```
|
|
25
|
-
*/
|
|
26
2
|
export async function handleSummarizeTasks(clickup, teamId) {
|
|
27
3
|
const { tasks } = await getAllTasks(clickup, teamId);
|
|
28
4
|
let output = "Summarized Tasks:\n\n";
|
|
@@ -31,35 +7,6 @@ export async function handleSummarizeTasks(clickup, teamId) {
|
|
|
31
7
|
}
|
|
32
8
|
return output;
|
|
33
9
|
}
|
|
34
|
-
/**
|
|
35
|
-
* Analyzes task priorities across the workspace
|
|
36
|
-
* Provides a statistical breakdown of task priorities, showing the distribution
|
|
37
|
-
* of priority levels and identifying potential workload patterns.
|
|
38
|
-
*
|
|
39
|
-
* @param clickup - ClickUp service instance for API operations
|
|
40
|
-
* @param teamId - Team ID to analyze tasks for
|
|
41
|
-
* @returns Promise resolving to formatted text analysis of task priorities
|
|
42
|
-
*
|
|
43
|
-
* @example
|
|
44
|
-
* Output format:
|
|
45
|
-
* ```
|
|
46
|
-
* Task Priorities Analysis:
|
|
47
|
-
*
|
|
48
|
-
* Available Priorities: 1, 2, 3, 4
|
|
49
|
-
*
|
|
50
|
-
* Priority Counts:
|
|
51
|
-
* - Priority 1: 5
|
|
52
|
-
* - Priority 2: 3
|
|
53
|
-
* - Priority 3: 8
|
|
54
|
-
* - Priority 4: 2
|
|
55
|
-
* ```
|
|
56
|
-
*
|
|
57
|
-
* Priority levels:
|
|
58
|
-
* 1 - Urgent
|
|
59
|
-
* 2 - High
|
|
60
|
-
* 3 - Normal
|
|
61
|
-
* 4 - Low
|
|
62
|
-
*/
|
|
63
10
|
export async function handleAnalyzeTaskPriorities(clickup, teamId) {
|
|
64
11
|
const { tasks } = await getAllTasks(clickup, teamId);
|
|
65
12
|
const priorities = tasks.map(task => task.priority?.priority);
|
package/build/handlers/tools.js
CHANGED
|
@@ -1,311 +1,38 @@
|
|
|
1
|
-
|
|
2
|
-
* Tool handlers for ClickUp MCP server.
|
|
3
|
-
* Implements the business logic for each tool operation.
|
|
4
|
-
* @module handlers/tools
|
|
5
|
-
*/
|
|
6
|
-
import { resolveListId, resolveSpaceId, resolveFolderId } from '../utils/resolvers.js';
|
|
7
|
-
import { logError } from '../utils/logger.js';
|
|
8
|
-
/**
|
|
9
|
-
* Handles the workspace_hierarchy tool request
|
|
10
|
-
* Returns a formatted tree view of the ClickUp workspace structure
|
|
11
|
-
* @param clickup - ClickUp service instance
|
|
12
|
-
* @param teamId - Team ID to fetch hierarchy for
|
|
13
|
-
* @returns Promise resolving to MCP-formatted response
|
|
14
|
-
*/
|
|
1
|
+
import { resolveListId } from '../utils/resolvers.js';
|
|
15
2
|
export async function handleWorkspaceHierarchy(clickup, teamId) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
output += ` │ Available Statuses: ${statuses.join(', ')}\n`;
|
|
30
|
-
}
|
|
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`;
|
|
31
16
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
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`;
|
|
42
27
|
}
|
|
43
|
-
output += "\n";
|
|
44
28
|
}
|
|
45
|
-
|
|
46
|
-
content: [{
|
|
47
|
-
type: 'text',
|
|
48
|
-
text: output
|
|
49
|
-
}]
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
catch (error) {
|
|
53
|
-
logError('tool.workspace_hierarchy', error);
|
|
54
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
55
|
-
return {
|
|
56
|
-
content: [{
|
|
57
|
-
type: 'error',
|
|
58
|
-
text: `Failed to fetch workspace hierarchy: ${errorMessage}`
|
|
59
|
-
}]
|
|
60
|
-
};
|
|
29
|
+
output += "\n";
|
|
61
30
|
}
|
|
31
|
+
return output;
|
|
62
32
|
}
|
|
63
|
-
/**
|
|
64
|
-
* Handles the create_task tool request
|
|
65
|
-
* Creates a new task in the specified list
|
|
66
|
-
* @param clickup - ClickUp service instance
|
|
67
|
-
* @param teamId - Team ID to create task in
|
|
68
|
-
* @param args - Task creation arguments
|
|
69
|
-
* @returns Promise resolving to MCP-formatted response
|
|
70
|
-
*/
|
|
71
33
|
export async function handleCreateTask(clickup, teamId, args) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const task = await clickup.createTask(listId, taskData);
|
|
76
|
-
return {
|
|
77
|
-
content: [{
|
|
78
|
-
type: 'text',
|
|
79
|
-
text: `Successfully created task "${task.name}" (ID: ${task.id})`
|
|
80
|
-
}]
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
catch (error) {
|
|
84
|
-
logError('tool.create_task', error);
|
|
85
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
86
|
-
return {
|
|
87
|
-
content: [{
|
|
88
|
-
type: 'error',
|
|
89
|
-
text: `Failed to create task: ${errorMessage}`
|
|
90
|
-
}]
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Handles the create_bulk_tasks tool request
|
|
96
|
-
* Creates multiple tasks in the specified list
|
|
97
|
-
* @param clickup - ClickUp service instance
|
|
98
|
-
* @param teamId - Team ID to create tasks in
|
|
99
|
-
* @param args - Bulk task creation arguments
|
|
100
|
-
* @returns Promise resolving to MCP-formatted response
|
|
101
|
-
*/
|
|
102
|
-
export async function handleCreateBulkTasks(clickup, teamId, args) {
|
|
103
|
-
try {
|
|
104
|
-
const listId = await resolveListId(clickup, teamId, args.listId, args.listName);
|
|
105
|
-
const { listId: _, listName: __, tasks } = args;
|
|
106
|
-
const createdTasks = await Promise.all(tasks.map(taskData => clickup.createTask(listId, taskData)));
|
|
107
|
-
return {
|
|
108
|
-
content: [{
|
|
109
|
-
type: 'text',
|
|
110
|
-
text: `Successfully created ${createdTasks.length} tasks in list ${listId}`
|
|
111
|
-
}]
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
catch (error) {
|
|
115
|
-
logError('tool.create_bulk_tasks', error);
|
|
116
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
117
|
-
return {
|
|
118
|
-
content: [{
|
|
119
|
-
type: 'error',
|
|
120
|
-
text: `Failed to create bulk tasks: ${errorMessage}`
|
|
121
|
-
}]
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Handles the create_list tool request
|
|
127
|
-
* Creates a new list in the specified space
|
|
128
|
-
* @param clickup - ClickUp service instance
|
|
129
|
-
* @param teamId - Team ID to create list in
|
|
130
|
-
* @param args - List creation arguments
|
|
131
|
-
* @returns Promise resolving to MCP-formatted response
|
|
132
|
-
*/
|
|
133
|
-
export async function handleCreateList(clickup, teamId, args) {
|
|
134
|
-
try {
|
|
135
|
-
const spaceId = await resolveSpaceId(clickup, teamId, args.spaceId, args.spaceName);
|
|
136
|
-
const { spaceId: _, spaceName: __, ...listData } = args;
|
|
137
|
-
const list = await clickup.createList(spaceId, listData);
|
|
138
|
-
return {
|
|
139
|
-
content: [{
|
|
140
|
-
type: 'text',
|
|
141
|
-
text: `Successfully created list "${list.name}" (ID: ${list.id})`
|
|
142
|
-
}]
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
catch (error) {
|
|
146
|
-
logError('tool.create_list', error);
|
|
147
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
148
|
-
return {
|
|
149
|
-
content: [{
|
|
150
|
-
type: 'error',
|
|
151
|
-
text: `Failed to create list: ${errorMessage}`
|
|
152
|
-
}]
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* Handles the create_folder tool request
|
|
158
|
-
* Creates a new folder in the specified space
|
|
159
|
-
* @param clickup - ClickUp service instance
|
|
160
|
-
* @param teamId - Team ID to create folder in
|
|
161
|
-
* @param args - Folder creation arguments
|
|
162
|
-
* @returns Promise resolving to MCP-formatted response
|
|
163
|
-
*/
|
|
164
|
-
export async function handleCreateFolder(clickup, teamId, args) {
|
|
165
|
-
try {
|
|
166
|
-
const spaceId = await resolveSpaceId(clickup, teamId, args.spaceId, args.spaceName);
|
|
167
|
-
const { spaceId: _, spaceName: __, ...folderData } = args;
|
|
168
|
-
const folder = await clickup.createFolder(spaceId, folderData);
|
|
169
|
-
return {
|
|
170
|
-
content: [{
|
|
171
|
-
type: 'text',
|
|
172
|
-
text: `Successfully created folder "${folder.name}" (ID: ${folder.id})`
|
|
173
|
-
}]
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
catch (error) {
|
|
177
|
-
logError('tool.create_folder', error);
|
|
178
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
179
|
-
return {
|
|
180
|
-
content: [{
|
|
181
|
-
type: 'error',
|
|
182
|
-
text: `Failed to create folder: ${errorMessage}`
|
|
183
|
-
}]
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
/**
|
|
188
|
-
* Handles the create_list_in_folder tool request
|
|
189
|
-
* Creates a new list within a specified folder
|
|
190
|
-
* @param clickup - ClickUp service instance
|
|
191
|
-
* @param teamId - Team ID to create list in
|
|
192
|
-
* @param args - List creation arguments
|
|
193
|
-
* @returns Promise resolving to MCP-formatted response
|
|
194
|
-
*/
|
|
195
|
-
export async function handleCreateListInFolder(clickup, teamId, args) {
|
|
196
|
-
try {
|
|
197
|
-
let folderId = args.folderId;
|
|
198
|
-
if (!folderId) {
|
|
199
|
-
const spaceId = await resolveSpaceId(clickup, teamId, args.spaceId, args.spaceName);
|
|
200
|
-
folderId = await resolveFolderId(clickup, teamId, undefined, args.folderName);
|
|
201
|
-
}
|
|
202
|
-
const { folderId: _, folderName: __, spaceId: ___, spaceName: ____, ...listData } = args;
|
|
203
|
-
const list = await clickup.createListInFolder(folderId, listData);
|
|
204
|
-
return {
|
|
205
|
-
content: [{
|
|
206
|
-
type: 'text',
|
|
207
|
-
text: `Successfully created list "${list.name}" (ID: ${list.id}) in folder`
|
|
208
|
-
}]
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
catch (error) {
|
|
212
|
-
logError('tool.create_list_in_folder', error);
|
|
213
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
214
|
-
return {
|
|
215
|
-
content: [{
|
|
216
|
-
type: 'error',
|
|
217
|
-
text: `Failed to create list in folder: ${errorMessage}`
|
|
218
|
-
}]
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
/**
|
|
223
|
-
* Handles the move_task tool request
|
|
224
|
-
* Moves a task to a different list
|
|
225
|
-
* @param clickup - ClickUp service instance
|
|
226
|
-
* @param teamId - Team ID
|
|
227
|
-
* @param args - Task move arguments
|
|
228
|
-
* @returns Promise resolving to MCP-formatted response
|
|
229
|
-
*/
|
|
230
|
-
export async function handleMoveTask(clickup, teamId, args) {
|
|
231
|
-
try {
|
|
232
|
-
const listId = await resolveListId(clickup, teamId, args.listId, args.listName);
|
|
233
|
-
await clickup.moveTask(args.taskId, listId);
|
|
234
|
-
return {
|
|
235
|
-
content: [{
|
|
236
|
-
type: 'text',
|
|
237
|
-
text: `Successfully moved task ${args.taskId} to list ${listId}`
|
|
238
|
-
}]
|
|
239
|
-
};
|
|
240
|
-
}
|
|
241
|
-
catch (error) {
|
|
242
|
-
logError('tool.move_task', error);
|
|
243
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
244
|
-
return {
|
|
245
|
-
content: [{
|
|
246
|
-
type: 'error',
|
|
247
|
-
text: `Failed to move task: ${errorMessage}`
|
|
248
|
-
}]
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
/**
|
|
253
|
-
* Handles the duplicate_task tool request
|
|
254
|
-
* Creates a copy of a task in a specified list
|
|
255
|
-
* @param clickup - ClickUp service instance
|
|
256
|
-
* @param teamId - Team ID
|
|
257
|
-
* @param args - Task duplication arguments
|
|
258
|
-
* @returns Promise resolving to MCP-formatted response
|
|
259
|
-
*/
|
|
260
|
-
export async function handleDuplicateTask(clickup, teamId, args) {
|
|
261
|
-
try {
|
|
262
|
-
const listId = await resolveListId(clickup, teamId, args.listId, args.listName);
|
|
263
|
-
const task = await clickup.duplicateTask(args.taskId, listId);
|
|
264
|
-
return {
|
|
265
|
-
content: [{
|
|
266
|
-
type: 'text',
|
|
267
|
-
text: `Successfully duplicated task "${task.name}" (ID: ${task.id})`
|
|
268
|
-
}]
|
|
269
|
-
};
|
|
270
|
-
}
|
|
271
|
-
catch (error) {
|
|
272
|
-
logError('tool.duplicate_task', error);
|
|
273
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
274
|
-
return {
|
|
275
|
-
content: [{
|
|
276
|
-
type: 'error',
|
|
277
|
-
text: `Failed to duplicate task: ${errorMessage}`
|
|
278
|
-
}]
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
/**
|
|
283
|
-
* Handles the update_task tool request
|
|
284
|
-
* Updates an existing task with new data
|
|
285
|
-
* @param clickup - ClickUp service instance
|
|
286
|
-
* @param teamId - Team ID
|
|
287
|
-
* @param args - Task update arguments
|
|
288
|
-
* @returns Promise resolving to MCP-formatted response
|
|
289
|
-
*/
|
|
290
|
-
export async function handleUpdateTask(clickup, teamId, args) {
|
|
291
|
-
try {
|
|
292
|
-
const { taskId, ...updateData } = args;
|
|
293
|
-
const task = await clickup.updateTask(taskId, updateData);
|
|
294
|
-
return {
|
|
295
|
-
content: [{
|
|
296
|
-
type: 'text',
|
|
297
|
-
text: `Successfully updated task "${task.name}" (ID: ${task.id})`
|
|
298
|
-
}]
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
catch (error) {
|
|
302
|
-
logError('tool.update_task', error);
|
|
303
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
304
|
-
return {
|
|
305
|
-
content: [{
|
|
306
|
-
type: 'error',
|
|
307
|
-
text: `Failed to update task: ${errorMessage}`
|
|
308
|
-
}]
|
|
309
|
-
};
|
|
310
|
-
}
|
|
34
|
+
const listId = await resolveListId(clickup, teamId, args.listId, args.listName);
|
|
35
|
+
const { listId: _, listName: __, ...taskData } = args;
|
|
36
|
+
return await clickup.createTask(listId, taskData);
|
|
311
37
|
}
|
|
38
|
+
// Add other handler functions for each tool...
|