@taazkareem/clickup-mcp-server 0.4.41 → 0.4.42
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 +26 -45
- package/build/config.js +4 -14
- package/build/handlers/prompts.js +0 -53
- package/build/handlers/tools.js +30 -303
- package/build/index.js +978 -77
- package/build/services/clickup.js +5 -171
- package/build/types/clickup.js +0 -7
- package/build/utils/resolvers.js +0 -50
- package/package.json +4 -3
- package/build/utils/logger.js +0 -47
package/build/index.js
CHANGED
|
@@ -1,92 +1,993 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* Provides tools and resources for AI agents to interact with ClickUp tasks,
|
|
6
|
-
* spaces, lists, and folders through a standardized protocol.
|
|
7
|
-
*
|
|
8
|
-
* @module clickup-mcp-server
|
|
9
|
-
*/
|
|
10
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
11
|
-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
12
|
-
import { z } from 'zod';
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
13
5
|
import { ClickUpService } from "./services/clickup.js";
|
|
14
6
|
import config from "./config.js";
|
|
15
7
|
import { handleWorkspaceHierarchy, handleCreateTask } from "./handlers/tools.js";
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
+
});
|
|
15
|
+
// Initialize ClickUp service
|
|
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...');
|
|
27
|
+
const server = new Server({
|
|
28
|
+
name: "clickup",
|
|
29
|
+
version: "0.1.0",
|
|
30
|
+
}, {
|
|
31
|
+
capabilities: {
|
|
32
|
+
resources: {
|
|
33
|
+
list: true,
|
|
34
|
+
read: true,
|
|
35
|
+
},
|
|
36
|
+
tools: {
|
|
37
|
+
workspace_hierarchy: {
|
|
38
|
+
description: "List complete hierarchy of the ClickUp workspace",
|
|
39
|
+
inputSchema: {
|
|
40
|
+
type: "object",
|
|
41
|
+
properties: {},
|
|
42
|
+
required: []
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
create_task: {
|
|
46
|
+
description: "Create a new task in ClickUp",
|
|
47
|
+
inputSchema: {
|
|
48
|
+
type: "object",
|
|
49
|
+
properties: {
|
|
50
|
+
listId: {
|
|
51
|
+
type: "string",
|
|
52
|
+
description: "ID of the list to create the task in (optional if listName is provided)"
|
|
53
|
+
},
|
|
54
|
+
listName: {
|
|
55
|
+
type: "string",
|
|
56
|
+
description: "Name of the list to create the task in (optional if listId is provided)"
|
|
57
|
+
},
|
|
58
|
+
name: {
|
|
59
|
+
type: "string",
|
|
60
|
+
description: "Name of the task"
|
|
61
|
+
},
|
|
62
|
+
description: {
|
|
63
|
+
type: "string",
|
|
64
|
+
description: "Description of the task"
|
|
65
|
+
},
|
|
66
|
+
status: {
|
|
67
|
+
type: "string",
|
|
68
|
+
description: "Status of the task"
|
|
69
|
+
},
|
|
70
|
+
priority: {
|
|
71
|
+
type: "number",
|
|
72
|
+
description: "Priority of the task (1-4)"
|
|
73
|
+
},
|
|
74
|
+
dueDate: {
|
|
75
|
+
type: "string",
|
|
76
|
+
description: "Due date of the task (ISO string)"
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
required: ["name"]
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
create_bulk_tasks: {
|
|
83
|
+
description: "Create multiple tasks in a ClickUp list",
|
|
84
|
+
inputSchema: {
|
|
85
|
+
type: "object",
|
|
86
|
+
properties: {
|
|
87
|
+
listId: {
|
|
88
|
+
type: "string",
|
|
89
|
+
description: "ID of the list to create the tasks in (optional if listName is provided)"
|
|
90
|
+
},
|
|
91
|
+
listName: {
|
|
92
|
+
type: "string",
|
|
93
|
+
description: "Name of the list to create the tasks in (optional if listId is provided)"
|
|
94
|
+
},
|
|
95
|
+
tasks: {
|
|
96
|
+
type: "array",
|
|
97
|
+
description: "Array of tasks to create",
|
|
98
|
+
items: {
|
|
99
|
+
type: "object",
|
|
100
|
+
properties: {
|
|
101
|
+
name: {
|
|
102
|
+
type: "string",
|
|
103
|
+
description: "Name of the task"
|
|
104
|
+
},
|
|
105
|
+
description: {
|
|
106
|
+
type: "string",
|
|
107
|
+
description: "Description of the task"
|
|
108
|
+
},
|
|
109
|
+
status: {
|
|
110
|
+
type: "string",
|
|
111
|
+
description: "Status of the task"
|
|
112
|
+
},
|
|
113
|
+
priority: {
|
|
114
|
+
type: "number",
|
|
115
|
+
description: "Priority level (1-4)"
|
|
116
|
+
},
|
|
117
|
+
dueDate: {
|
|
118
|
+
type: "string",
|
|
119
|
+
description: "Due date (ISO string)"
|
|
120
|
+
},
|
|
121
|
+
assignees: {
|
|
122
|
+
type: "array",
|
|
123
|
+
items: {
|
|
124
|
+
type: "number"
|
|
125
|
+
},
|
|
126
|
+
description: "Array of user IDs to assign to the task"
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
required: ["name"]
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
required: ["tasks"]
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
create_list: {
|
|
137
|
+
description: "Create a new list in a ClickUp space",
|
|
138
|
+
inputSchema: {
|
|
139
|
+
type: "object",
|
|
140
|
+
properties: {
|
|
141
|
+
spaceId: {
|
|
142
|
+
type: "string",
|
|
143
|
+
description: "ID of the space to create the list in (optional if spaceName is provided)"
|
|
144
|
+
},
|
|
145
|
+
spaceName: {
|
|
146
|
+
type: "string",
|
|
147
|
+
description: "Name of the space to create the list in (optional if spaceId is provided)"
|
|
148
|
+
},
|
|
149
|
+
name: {
|
|
150
|
+
type: "string",
|
|
151
|
+
description: "Name of the list"
|
|
152
|
+
},
|
|
153
|
+
content: {
|
|
154
|
+
type: "string",
|
|
155
|
+
description: "Description or content of the list"
|
|
156
|
+
},
|
|
157
|
+
dueDate: {
|
|
158
|
+
type: "string",
|
|
159
|
+
description: "Due date for the list (ISO string)"
|
|
160
|
+
},
|
|
161
|
+
priority: {
|
|
162
|
+
type: "number",
|
|
163
|
+
description: "Priority of the list (1-4)"
|
|
164
|
+
},
|
|
165
|
+
assignee: {
|
|
166
|
+
type: "number",
|
|
167
|
+
description: "User ID to assign the list to"
|
|
168
|
+
},
|
|
169
|
+
status: {
|
|
170
|
+
type: "string",
|
|
171
|
+
description: "Status of the list"
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
required: ["name"]
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
create_folder: {
|
|
178
|
+
description: "Create a new folder in a ClickUp space",
|
|
179
|
+
inputSchema: {
|
|
180
|
+
type: "object",
|
|
181
|
+
properties: {
|
|
182
|
+
spaceId: {
|
|
183
|
+
type: "string",
|
|
184
|
+
description: "ID of the space to create the folder in (optional if spaceName is provided)"
|
|
185
|
+
},
|
|
186
|
+
spaceName: {
|
|
187
|
+
type: "string",
|
|
188
|
+
description: "Name of the space to create the folder in (optional if spaceId is provided)"
|
|
189
|
+
},
|
|
190
|
+
name: {
|
|
191
|
+
type: "string",
|
|
192
|
+
description: "Name of the folder"
|
|
193
|
+
},
|
|
194
|
+
override_statuses: {
|
|
195
|
+
type: "boolean",
|
|
196
|
+
description: "Whether to override space statuses"
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
required: ["name"]
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
create_list_in_folder: {
|
|
203
|
+
description: "Create a new list in a ClickUp folder",
|
|
204
|
+
inputSchema: {
|
|
205
|
+
type: "object",
|
|
206
|
+
properties: {
|
|
207
|
+
folderId: {
|
|
208
|
+
type: "string",
|
|
209
|
+
description: "ID of the folder to create the list in (optional if folderName and spaceId/spaceName are provided)"
|
|
210
|
+
},
|
|
211
|
+
folderName: {
|
|
212
|
+
type: "string",
|
|
213
|
+
description: "Name of the folder to create the list in"
|
|
214
|
+
},
|
|
215
|
+
spaceId: {
|
|
216
|
+
type: "string",
|
|
217
|
+
description: "ID of the space containing the folder (required if using folderName)"
|
|
218
|
+
},
|
|
219
|
+
spaceName: {
|
|
220
|
+
type: "string",
|
|
221
|
+
description: "Name of the space containing the folder (alternative to spaceId)"
|
|
222
|
+
},
|
|
223
|
+
name: {
|
|
224
|
+
type: "string",
|
|
225
|
+
description: "Name of the list"
|
|
226
|
+
},
|
|
227
|
+
content: {
|
|
228
|
+
type: "string",
|
|
229
|
+
description: "Description or content of the list"
|
|
230
|
+
},
|
|
231
|
+
status: {
|
|
232
|
+
type: "string",
|
|
233
|
+
description: "Status of the list"
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
required: ["name"]
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
move_task: {
|
|
240
|
+
description: "Move a task to a different list",
|
|
241
|
+
inputSchema: {
|
|
242
|
+
type: "object",
|
|
243
|
+
properties: {
|
|
244
|
+
taskId: {
|
|
245
|
+
type: "string",
|
|
246
|
+
description: "ID of the task to move"
|
|
247
|
+
},
|
|
248
|
+
listId: {
|
|
249
|
+
type: "string",
|
|
250
|
+
description: "ID of the destination list (optional if listName is provided)"
|
|
251
|
+
},
|
|
252
|
+
listName: {
|
|
253
|
+
type: "string",
|
|
254
|
+
description: "Name of the destination list (optional if listId is provided)"
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
required: ["taskId"]
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
duplicate_task: {
|
|
261
|
+
description: "Duplicate a task to a list",
|
|
262
|
+
inputSchema: {
|
|
263
|
+
type: "object",
|
|
264
|
+
properties: {
|
|
265
|
+
taskId: {
|
|
266
|
+
type: "string",
|
|
267
|
+
description: "ID of the task to duplicate"
|
|
268
|
+
},
|
|
269
|
+
listId: {
|
|
270
|
+
type: "string",
|
|
271
|
+
description: "ID of the destination list (optional if listName is provided)"
|
|
272
|
+
},
|
|
273
|
+
listName: {
|
|
274
|
+
type: "string",
|
|
275
|
+
description: "Name of the destination list (optional if listId is provided)"
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
required: ["taskId"]
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
update_task: {
|
|
282
|
+
description: "Update an existing task in ClickUp",
|
|
283
|
+
inputSchema: {
|
|
284
|
+
type: "object",
|
|
285
|
+
properties: {
|
|
286
|
+
taskId: {
|
|
287
|
+
type: "string",
|
|
288
|
+
description: "ID of the task to update"
|
|
289
|
+
},
|
|
290
|
+
name: {
|
|
291
|
+
type: "string",
|
|
292
|
+
description: "New name of the task"
|
|
293
|
+
},
|
|
294
|
+
description: {
|
|
295
|
+
type: "string",
|
|
296
|
+
description: "New description of the task"
|
|
297
|
+
},
|
|
298
|
+
status: {
|
|
299
|
+
type: "string",
|
|
300
|
+
description: "New status of the task"
|
|
301
|
+
},
|
|
302
|
+
priority: {
|
|
303
|
+
type: "number",
|
|
304
|
+
description: "New priority of the task (1-4)"
|
|
305
|
+
},
|
|
306
|
+
dueDate: {
|
|
307
|
+
type: "string",
|
|
308
|
+
description: "New due date of the task (ISO string)"
|
|
309
|
+
}
|
|
310
|
+
},
|
|
311
|
+
required: ["taskId"]
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
},
|
|
315
|
+
prompts: {
|
|
316
|
+
summarize_tasks: {
|
|
317
|
+
description: "Summarize tasks in the workspace",
|
|
318
|
+
inputSchema: {
|
|
319
|
+
type: "object",
|
|
320
|
+
properties: {},
|
|
321
|
+
required: []
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
analyze_priorities: {
|
|
325
|
+
description: "Analyze task priorities",
|
|
326
|
+
inputSchema: {
|
|
327
|
+
type: "object",
|
|
328
|
+
properties: {},
|
|
329
|
+
required: []
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
});
|
|
335
|
+
console.log('MCP server created');
|
|
336
|
+
/**
|
|
337
|
+
* Handler for listing available ClickUp tasks as resources.
|
|
338
|
+
*/
|
|
339
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
340
|
+
console.log('Handling ListResources request');
|
|
341
|
+
try {
|
|
342
|
+
const { tasks, spaces } = await getAllTasks(clickup, config.teamId);
|
|
42
343
|
return {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
344
|
+
resources: tasks.map(task => ({
|
|
345
|
+
uri: `clickup://task/${task.id}`,
|
|
346
|
+
mimeType: "application/json",
|
|
347
|
+
name: task.name,
|
|
348
|
+
description: task.description || `Task in ${task.list.name} (${task.space.name})`,
|
|
349
|
+
tags: []
|
|
350
|
+
}))
|
|
47
351
|
};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
status: args.status,
|
|
63
|
-
priority: args.priority,
|
|
64
|
-
due_date: args.dueDate,
|
|
65
|
-
listId: args.listId,
|
|
66
|
-
listName: args.listName
|
|
67
|
-
};
|
|
68
|
-
const result = await handleCreateTask(clickup, config.teamId, taskData);
|
|
352
|
+
}
|
|
353
|
+
catch (error) {
|
|
354
|
+
console.error('Error in ListResources:', error);
|
|
355
|
+
throw error;
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
/**
|
|
359
|
+
* Handler for reading the contents of a specific ClickUp task.
|
|
360
|
+
*/
|
|
361
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
362
|
+
try {
|
|
363
|
+
const url = new URL(request.params.uri);
|
|
364
|
+
const taskId = url.pathname.replace(/^\/task\//, '');
|
|
365
|
+
const task = await clickup.getTask(taskId);
|
|
69
366
|
return {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
367
|
+
contents: [{
|
|
368
|
+
uri: request.params.uri,
|
|
369
|
+
mimeType: "application/json",
|
|
370
|
+
text: JSON.stringify(task, null, 2),
|
|
371
|
+
tags: []
|
|
73
372
|
}]
|
|
74
373
|
};
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
374
|
+
}
|
|
375
|
+
catch (error) {
|
|
376
|
+
console.error('Error reading resource:', error);
|
|
377
|
+
throw error;
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
/**
|
|
381
|
+
* Handler for listing available tools.
|
|
382
|
+
*/
|
|
383
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
384
|
+
console.log('Handling ListTools request');
|
|
385
|
+
return {
|
|
386
|
+
tools: [
|
|
387
|
+
{
|
|
388
|
+
name: "workspace_hierarchy",
|
|
389
|
+
description: "List complete hierarchy of the ClickUp workspace",
|
|
390
|
+
inputSchema: {
|
|
391
|
+
type: "object",
|
|
392
|
+
properties: {},
|
|
393
|
+
required: []
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
name: "create_task",
|
|
398
|
+
description: "Create a new task in ClickUp",
|
|
399
|
+
inputSchema: {
|
|
400
|
+
type: "object",
|
|
401
|
+
properties: {
|
|
402
|
+
listId: {
|
|
403
|
+
type: "string",
|
|
404
|
+
description: "ID of the list to create the task in (optional if listName is provided)"
|
|
405
|
+
},
|
|
406
|
+
listName: {
|
|
407
|
+
type: "string",
|
|
408
|
+
description: "Name of the list to create the task in (optional if listId is provided)"
|
|
409
|
+
},
|
|
410
|
+
name: {
|
|
411
|
+
type: "string",
|
|
412
|
+
description: "Name of the task"
|
|
413
|
+
},
|
|
414
|
+
description: {
|
|
415
|
+
type: "string",
|
|
416
|
+
description: "Description of the task"
|
|
417
|
+
},
|
|
418
|
+
status: {
|
|
419
|
+
type: "string",
|
|
420
|
+
description: "Status of the task"
|
|
421
|
+
},
|
|
422
|
+
priority: {
|
|
423
|
+
type: "number",
|
|
424
|
+
description: "Priority of the task (1-4)"
|
|
425
|
+
},
|
|
426
|
+
dueDate: {
|
|
427
|
+
type: "string",
|
|
428
|
+
description: "Due date of the task (ISO string)"
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
required: ["name"]
|
|
432
|
+
}
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
name: "create_bulk_tasks",
|
|
436
|
+
description: "Create multiple tasks in a ClickUp list",
|
|
437
|
+
inputSchema: {
|
|
438
|
+
type: "object",
|
|
439
|
+
properties: {
|
|
440
|
+
listId: {
|
|
441
|
+
type: "string",
|
|
442
|
+
description: "ID of the list to create the tasks in (optional if listName is provided)"
|
|
443
|
+
},
|
|
444
|
+
listName: {
|
|
445
|
+
type: "string",
|
|
446
|
+
description: "Name of the list to create the tasks in (optional if listId is provided)"
|
|
447
|
+
},
|
|
448
|
+
tasks: {
|
|
449
|
+
type: "array",
|
|
450
|
+
description: "Array of tasks to create",
|
|
451
|
+
items: {
|
|
452
|
+
type: "object",
|
|
453
|
+
properties: {
|
|
454
|
+
name: {
|
|
455
|
+
type: "string",
|
|
456
|
+
description: "Name of the task"
|
|
457
|
+
},
|
|
458
|
+
description: {
|
|
459
|
+
type: "string",
|
|
460
|
+
description: "Description of the task"
|
|
461
|
+
},
|
|
462
|
+
status: {
|
|
463
|
+
type: "string",
|
|
464
|
+
description: "Status of the task"
|
|
465
|
+
},
|
|
466
|
+
priority: {
|
|
467
|
+
type: "number",
|
|
468
|
+
description: "Priority level (1-4)"
|
|
469
|
+
},
|
|
470
|
+
dueDate: {
|
|
471
|
+
type: "string",
|
|
472
|
+
description: "Due date (ISO string)"
|
|
473
|
+
},
|
|
474
|
+
assignees: {
|
|
475
|
+
type: "array",
|
|
476
|
+
items: {
|
|
477
|
+
type: "number"
|
|
478
|
+
},
|
|
479
|
+
description: "Array of user IDs to assign to the task"
|
|
480
|
+
}
|
|
481
|
+
},
|
|
482
|
+
required: ["name"]
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
},
|
|
486
|
+
required: ["tasks"]
|
|
487
|
+
}
|
|
488
|
+
},
|
|
489
|
+
{
|
|
490
|
+
name: "create_list",
|
|
491
|
+
description: "Create a new list in a ClickUp space",
|
|
492
|
+
inputSchema: {
|
|
493
|
+
type: "object",
|
|
494
|
+
properties: {
|
|
495
|
+
spaceId: {
|
|
496
|
+
type: "string",
|
|
497
|
+
description: "ID of the space to create the list in (optional if spaceName is provided)"
|
|
498
|
+
},
|
|
499
|
+
spaceName: {
|
|
500
|
+
type: "string",
|
|
501
|
+
description: "Name of the space to create the list in (optional if spaceId is provided)"
|
|
502
|
+
},
|
|
503
|
+
name: {
|
|
504
|
+
type: "string",
|
|
505
|
+
description: "Name of the list"
|
|
506
|
+
},
|
|
507
|
+
content: {
|
|
508
|
+
type: "string",
|
|
509
|
+
description: "Description or content of the list"
|
|
510
|
+
},
|
|
511
|
+
dueDate: {
|
|
512
|
+
type: "string",
|
|
513
|
+
description: "Due date for the list (ISO string)"
|
|
514
|
+
},
|
|
515
|
+
priority: {
|
|
516
|
+
type: "number",
|
|
517
|
+
description: "Priority of the list (1-4)"
|
|
518
|
+
},
|
|
519
|
+
assignee: {
|
|
520
|
+
type: "number",
|
|
521
|
+
description: "User ID to assign the list to"
|
|
522
|
+
},
|
|
523
|
+
status: {
|
|
524
|
+
type: "string",
|
|
525
|
+
description: "Status of the list"
|
|
526
|
+
}
|
|
527
|
+
},
|
|
528
|
+
required: ["name"]
|
|
529
|
+
}
|
|
530
|
+
},
|
|
531
|
+
{
|
|
532
|
+
name: "create_folder",
|
|
533
|
+
description: "Create a new folder in a ClickUp space",
|
|
534
|
+
inputSchema: {
|
|
535
|
+
type: "object",
|
|
536
|
+
properties: {
|
|
537
|
+
spaceId: {
|
|
538
|
+
type: "string",
|
|
539
|
+
description: "ID of the space to create the folder in (optional if spaceName is provided)"
|
|
540
|
+
},
|
|
541
|
+
spaceName: {
|
|
542
|
+
type: "string",
|
|
543
|
+
description: "Name of the space to create the folder in (optional if spaceId is provided)"
|
|
544
|
+
},
|
|
545
|
+
name: {
|
|
546
|
+
type: "string",
|
|
547
|
+
description: "Name of the folder"
|
|
548
|
+
},
|
|
549
|
+
override_statuses: {
|
|
550
|
+
type: "boolean",
|
|
551
|
+
description: "Whether to override space statuses"
|
|
552
|
+
}
|
|
553
|
+
},
|
|
554
|
+
required: ["name"]
|
|
555
|
+
}
|
|
556
|
+
},
|
|
557
|
+
{
|
|
558
|
+
name: "create_list_in_folder",
|
|
559
|
+
description: "Create a new list in a ClickUp folder",
|
|
560
|
+
inputSchema: {
|
|
561
|
+
type: "object",
|
|
562
|
+
properties: {
|
|
563
|
+
folderId: {
|
|
564
|
+
type: "string",
|
|
565
|
+
description: "ID of the folder to create the list in (optional if folderName and spaceId/spaceName are provided)"
|
|
566
|
+
},
|
|
567
|
+
folderName: {
|
|
568
|
+
type: "string",
|
|
569
|
+
description: "Name of the folder to create the list in"
|
|
570
|
+
},
|
|
571
|
+
spaceId: {
|
|
572
|
+
type: "string",
|
|
573
|
+
description: "ID of the space containing the folder (required if using folderName)"
|
|
574
|
+
},
|
|
575
|
+
spaceName: {
|
|
576
|
+
type: "string",
|
|
577
|
+
description: "Name of the space containing the folder (alternative to spaceId)"
|
|
578
|
+
},
|
|
579
|
+
name: {
|
|
580
|
+
type: "string",
|
|
581
|
+
description: "Name of the list"
|
|
582
|
+
},
|
|
583
|
+
content: {
|
|
584
|
+
type: "string",
|
|
585
|
+
description: "Description or content of the list"
|
|
586
|
+
},
|
|
587
|
+
status: {
|
|
588
|
+
type: "string",
|
|
589
|
+
description: "Status of the list"
|
|
590
|
+
}
|
|
591
|
+
},
|
|
592
|
+
required: ["name"]
|
|
593
|
+
}
|
|
594
|
+
},
|
|
595
|
+
{
|
|
596
|
+
name: "move_task",
|
|
597
|
+
description: "Move a task to a different list",
|
|
598
|
+
inputSchema: {
|
|
599
|
+
type: "object",
|
|
600
|
+
properties: {
|
|
601
|
+
taskId: {
|
|
602
|
+
type: "string",
|
|
603
|
+
description: "ID of the task to move"
|
|
604
|
+
},
|
|
605
|
+
listId: {
|
|
606
|
+
type: "string",
|
|
607
|
+
description: "ID of the destination list (optional if listName is provided)"
|
|
608
|
+
},
|
|
609
|
+
listName: {
|
|
610
|
+
type: "string",
|
|
611
|
+
description: "Name of the destination list (optional if listId is provided)"
|
|
612
|
+
}
|
|
613
|
+
},
|
|
614
|
+
required: ["taskId"]
|
|
615
|
+
}
|
|
616
|
+
},
|
|
617
|
+
{
|
|
618
|
+
name: "duplicate_task",
|
|
619
|
+
description: "Duplicate a task to a list",
|
|
620
|
+
inputSchema: {
|
|
621
|
+
type: "object",
|
|
622
|
+
properties: {
|
|
623
|
+
taskId: {
|
|
624
|
+
type: "string",
|
|
625
|
+
description: "ID of the task to duplicate"
|
|
626
|
+
},
|
|
627
|
+
listId: {
|
|
628
|
+
type: "string",
|
|
629
|
+
description: "ID of the destination list (optional if listName is provided)"
|
|
630
|
+
},
|
|
631
|
+
listName: {
|
|
632
|
+
type: "string",
|
|
633
|
+
description: "Name of the destination list (optional if listId is provided)"
|
|
634
|
+
}
|
|
635
|
+
},
|
|
636
|
+
required: ["taskId"]
|
|
637
|
+
}
|
|
638
|
+
},
|
|
639
|
+
{
|
|
640
|
+
name: "update_task",
|
|
641
|
+
description: "Update an existing task in ClickUp",
|
|
642
|
+
inputSchema: {
|
|
643
|
+
type: "object",
|
|
644
|
+
properties: {
|
|
645
|
+
taskId: {
|
|
646
|
+
type: "string",
|
|
647
|
+
description: "ID of the task to update"
|
|
648
|
+
},
|
|
649
|
+
name: {
|
|
650
|
+
type: "string",
|
|
651
|
+
description: "New name of the task"
|
|
652
|
+
},
|
|
653
|
+
description: {
|
|
654
|
+
type: "string",
|
|
655
|
+
description: "New description of the task"
|
|
656
|
+
},
|
|
657
|
+
status: {
|
|
658
|
+
type: "string",
|
|
659
|
+
description: "New status of the task"
|
|
660
|
+
},
|
|
661
|
+
priority: {
|
|
662
|
+
type: "number",
|
|
663
|
+
description: "New priority of the task (1-4)"
|
|
664
|
+
},
|
|
665
|
+
dueDate: {
|
|
666
|
+
type: "string",
|
|
667
|
+
description: "New due date of the task (ISO string)"
|
|
668
|
+
}
|
|
669
|
+
},
|
|
670
|
+
required: ["taskId"]
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
]
|
|
674
|
+
};
|
|
675
|
+
});
|
|
676
|
+
/**
|
|
677
|
+
* Handler for executing tools.
|
|
678
|
+
*/
|
|
679
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
79
680
|
try {
|
|
80
|
-
|
|
81
|
-
|
|
681
|
+
switch (request.params.name) {
|
|
682
|
+
case "workspace_hierarchy": {
|
|
683
|
+
const output = await handleWorkspaceHierarchy(clickup, config.teamId);
|
|
684
|
+
return {
|
|
685
|
+
content: [{
|
|
686
|
+
type: "text",
|
|
687
|
+
text: output
|
|
688
|
+
}]
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
case "create_task": {
|
|
692
|
+
const args = request.params.arguments;
|
|
693
|
+
const task = await handleCreateTask(clickup, config.teamId, args);
|
|
694
|
+
return {
|
|
695
|
+
content: [{
|
|
696
|
+
type: "text",
|
|
697
|
+
text: `Created task ${task.id}: ${task.name}`
|
|
698
|
+
}]
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
case "create_bulk_tasks": {
|
|
702
|
+
const args = request.params.arguments;
|
|
703
|
+
let listId = args.listId;
|
|
704
|
+
if (!listId && args.listName) {
|
|
705
|
+
const result = await clickup.findListByNameGlobally(config.teamId, args.listName);
|
|
706
|
+
if (!result) {
|
|
707
|
+
throw new Error(`List with name "${args.listName}" not found`);
|
|
708
|
+
}
|
|
709
|
+
listId = result.list.id;
|
|
710
|
+
}
|
|
711
|
+
if (!listId) {
|
|
712
|
+
throw new Error("Either listId or listName is required");
|
|
713
|
+
}
|
|
714
|
+
if (!args.tasks || !args.tasks.length) {
|
|
715
|
+
throw new Error("At least one task is required");
|
|
716
|
+
}
|
|
717
|
+
const { listId: _, listName: __, tasks } = args;
|
|
718
|
+
const createdTasks = await clickup.createBulkTasks(listId, { tasks });
|
|
719
|
+
return {
|
|
720
|
+
content: [{
|
|
721
|
+
type: "text",
|
|
722
|
+
text: `Created ${createdTasks.length} tasks:\n${createdTasks.map(task => `- ${task.id}: ${task.name}`).join('\n')}`
|
|
723
|
+
}]
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
case "create_list": {
|
|
727
|
+
const args = request.params.arguments;
|
|
728
|
+
if (!args.name) {
|
|
729
|
+
throw new Error("name is required");
|
|
730
|
+
}
|
|
731
|
+
// If folder is specified, create list in folder
|
|
732
|
+
if (args.folderName || args.folderId) {
|
|
733
|
+
let folderId = args.folderId;
|
|
734
|
+
if (!folderId && args.folderName) {
|
|
735
|
+
const result = await clickup.findFolderByNameGlobally(config.teamId, args.folderName);
|
|
736
|
+
if (!result) {
|
|
737
|
+
throw new Error(`Folder with name "${args.folderName}" not found`);
|
|
738
|
+
}
|
|
739
|
+
folderId = result.folder.id;
|
|
740
|
+
}
|
|
741
|
+
if (!folderId) {
|
|
742
|
+
throw new Error("Either folderId or folderName must be provided");
|
|
743
|
+
}
|
|
744
|
+
const { spaceId: _, spaceName: __, folderName: ___, folderId: ____, ...listData } = args;
|
|
745
|
+
const list = await clickup.createListInFolder(folderId, listData);
|
|
746
|
+
return {
|
|
747
|
+
content: [{
|
|
748
|
+
type: "text",
|
|
749
|
+
text: `Created list ${list.id}: ${list.name} in folder`
|
|
750
|
+
}]
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
// Otherwise, create list in space
|
|
754
|
+
let spaceId = args.spaceId;
|
|
755
|
+
if (!spaceId && args.spaceName) {
|
|
756
|
+
const space = await clickup.findSpaceByName(config.teamId, args.spaceName);
|
|
757
|
+
if (!space) {
|
|
758
|
+
throw new Error(`Space with name "${args.spaceName}" not found`);
|
|
759
|
+
}
|
|
760
|
+
spaceId = space.id;
|
|
761
|
+
}
|
|
762
|
+
if (!spaceId) {
|
|
763
|
+
throw new Error("Either spaceId or spaceName must be provided");
|
|
764
|
+
}
|
|
765
|
+
const { spaceId: _, spaceName: __, folderName: ___, folderId: ____, ...listData } = args;
|
|
766
|
+
const list = await clickup.createList(spaceId, listData);
|
|
767
|
+
return {
|
|
768
|
+
content: [{
|
|
769
|
+
type: "text",
|
|
770
|
+
text: `Created list ${list.id}: ${list.name}`
|
|
771
|
+
}]
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
case "create_folder": {
|
|
775
|
+
const args = request.params.arguments;
|
|
776
|
+
if (!args.name) {
|
|
777
|
+
throw new Error("name is required");
|
|
778
|
+
}
|
|
779
|
+
let spaceId = args.spaceId;
|
|
780
|
+
if (!spaceId && args.spaceName) {
|
|
781
|
+
const space = await clickup.findSpaceByName(config.teamId, args.spaceName);
|
|
782
|
+
if (!space) {
|
|
783
|
+
throw new Error(`Space with name "${args.spaceName}" not found`);
|
|
784
|
+
}
|
|
785
|
+
spaceId = space.id;
|
|
786
|
+
}
|
|
787
|
+
if (!spaceId) {
|
|
788
|
+
throw new Error("Either spaceId or spaceName must be provided");
|
|
789
|
+
}
|
|
790
|
+
const { spaceId: _, spaceName: __, ...folderData } = args;
|
|
791
|
+
const folder = await clickup.createFolder(spaceId, folderData);
|
|
792
|
+
return {
|
|
793
|
+
content: [{
|
|
794
|
+
type: "text",
|
|
795
|
+
text: `Created folder ${folder.id}: ${folder.name}`
|
|
796
|
+
}]
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
case "create_list_in_folder": {
|
|
800
|
+
const args = request.params.arguments;
|
|
801
|
+
if (!args.name) {
|
|
802
|
+
throw new Error("name is required");
|
|
803
|
+
}
|
|
804
|
+
let folderId = args.folderId;
|
|
805
|
+
if (!folderId && args.folderName) {
|
|
806
|
+
const result = await clickup.findFolderByNameGlobally(config.teamId, args.folderName);
|
|
807
|
+
if (!result) {
|
|
808
|
+
throw new Error(`Folder with name "${args.folderName}" not found`);
|
|
809
|
+
}
|
|
810
|
+
folderId = result.folder.id;
|
|
811
|
+
}
|
|
812
|
+
if (!folderId) {
|
|
813
|
+
throw new Error("Either folderId or folderName is required");
|
|
814
|
+
}
|
|
815
|
+
const listData = {
|
|
816
|
+
name: args.name,
|
|
817
|
+
content: args.content,
|
|
818
|
+
status: args.status
|
|
819
|
+
};
|
|
820
|
+
try {
|
|
821
|
+
const list = await clickup.createListInFolder(folderId, listData);
|
|
822
|
+
return {
|
|
823
|
+
content: [{
|
|
824
|
+
type: "text",
|
|
825
|
+
text: `Created list ${list.id}: ${list.name} in folder`
|
|
826
|
+
}]
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
catch (error) {
|
|
830
|
+
throw new Error(`Failed to create list: ${error.message}`);
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
case "move_task": {
|
|
834
|
+
const args = request.params.arguments;
|
|
835
|
+
if (!args.taskId) {
|
|
836
|
+
throw new Error("taskId is required");
|
|
837
|
+
}
|
|
838
|
+
let listId = args.listId;
|
|
839
|
+
if (!listId && args.listName) {
|
|
840
|
+
const result = await clickup.findListByNameGlobally(config.teamId, args.listName);
|
|
841
|
+
if (!result) {
|
|
842
|
+
throw new Error(`List with name "${args.listName}" not found`);
|
|
843
|
+
}
|
|
844
|
+
listId = result.list.id;
|
|
845
|
+
}
|
|
846
|
+
if (!listId) {
|
|
847
|
+
throw new Error("Either listId or listName is required");
|
|
848
|
+
}
|
|
849
|
+
const task = await clickup.moveTask(args.taskId, listId);
|
|
850
|
+
return {
|
|
851
|
+
content: [{
|
|
852
|
+
type: "text",
|
|
853
|
+
text: `Moved task ${task.id} to list ${listId}`
|
|
854
|
+
}]
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
case "duplicate_task": {
|
|
858
|
+
const args = request.params.arguments;
|
|
859
|
+
if (!args.taskId) {
|
|
860
|
+
throw new Error("taskId is required");
|
|
861
|
+
}
|
|
862
|
+
let listId = args.listId;
|
|
863
|
+
if (!listId && args.listName) {
|
|
864
|
+
const result = await clickup.findListByNameGlobally(config.teamId, args.listName);
|
|
865
|
+
if (!result) {
|
|
866
|
+
throw new Error(`List with name "${args.listName}" not found`);
|
|
867
|
+
}
|
|
868
|
+
listId = result.list.id;
|
|
869
|
+
}
|
|
870
|
+
if (!listId) {
|
|
871
|
+
throw new Error("Either listId or listName is required");
|
|
872
|
+
}
|
|
873
|
+
const task = await clickup.duplicateTask(args.taskId, listId);
|
|
874
|
+
return {
|
|
875
|
+
content: [{
|
|
876
|
+
type: "text",
|
|
877
|
+
text: `Duplicated task ${args.taskId} to new task ${task.id} in list ${listId}`
|
|
878
|
+
}]
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
case "update_task": {
|
|
882
|
+
const args = request.params.arguments;
|
|
883
|
+
if (!args.taskId) {
|
|
884
|
+
throw new Error("taskId is required");
|
|
885
|
+
}
|
|
886
|
+
const task = await clickup.updateTask(args.taskId, {
|
|
887
|
+
name: args.name,
|
|
888
|
+
description: args.description,
|
|
889
|
+
status: args.status,
|
|
890
|
+
priority: args.priority,
|
|
891
|
+
due_date: args.due_date
|
|
892
|
+
});
|
|
893
|
+
return {
|
|
894
|
+
content: [{
|
|
895
|
+
type: "text",
|
|
896
|
+
text: `Updated task ${task.id}: ${task.name}`
|
|
897
|
+
}]
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
default:
|
|
901
|
+
throw new Error("Unknown tool");
|
|
902
|
+
}
|
|
82
903
|
}
|
|
83
904
|
catch (error) {
|
|
84
|
-
console.error('
|
|
85
|
-
|
|
905
|
+
console.error('Error executing tool:', error);
|
|
906
|
+
throw error;
|
|
907
|
+
}
|
|
908
|
+
});
|
|
909
|
+
/**
|
|
910
|
+
* Handler for listing available prompts.
|
|
911
|
+
*/
|
|
912
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
913
|
+
return {
|
|
914
|
+
prompts: [
|
|
915
|
+
{
|
|
916
|
+
name: "summarize_tasks",
|
|
917
|
+
description: "Summarize all ClickUp tasks"
|
|
918
|
+
},
|
|
919
|
+
{
|
|
920
|
+
name: "analyze_task_priorities",
|
|
921
|
+
description: "Analyze task priorities"
|
|
922
|
+
}
|
|
923
|
+
]
|
|
924
|
+
};
|
|
925
|
+
});
|
|
926
|
+
/**
|
|
927
|
+
* Handler for getting a specific prompt.
|
|
928
|
+
*/
|
|
929
|
+
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
930
|
+
try {
|
|
931
|
+
switch (request.params.name) {
|
|
932
|
+
case "summarize_tasks": {
|
|
933
|
+
const output = await handleSummarizeTasks(clickup, config.teamId);
|
|
934
|
+
return {
|
|
935
|
+
content: [{
|
|
936
|
+
type: "text",
|
|
937
|
+
text: output
|
|
938
|
+
}]
|
|
939
|
+
};
|
|
940
|
+
}
|
|
941
|
+
case "analyze_task_priorities": {
|
|
942
|
+
const output = await handleAnalyzeTaskPriorities(clickup, config.teamId);
|
|
943
|
+
return {
|
|
944
|
+
content: [{
|
|
945
|
+
type: "text",
|
|
946
|
+
text: output
|
|
947
|
+
}]
|
|
948
|
+
};
|
|
949
|
+
}
|
|
950
|
+
default:
|
|
951
|
+
throw new Error("Prompt not found");
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
catch (error) {
|
|
955
|
+
console.error('Error getting prompt:', error);
|
|
956
|
+
throw error;
|
|
86
957
|
}
|
|
958
|
+
});
|
|
959
|
+
if (process.argv.includes('--stdio')) {
|
|
960
|
+
console.log('Starting server in stdio mode...');
|
|
961
|
+
// Set up stdio transport
|
|
962
|
+
const transport = new StdioServerTransport();
|
|
963
|
+
// Connect server with better error handling
|
|
964
|
+
server.connect(transport)
|
|
965
|
+
.then(() => {
|
|
966
|
+
console.log('Server connected successfully to stdio transport');
|
|
967
|
+
// Keep the process alive
|
|
968
|
+
process.stdin.resume();
|
|
969
|
+
// Handle process termination
|
|
970
|
+
process.on('SIGINT', () => {
|
|
971
|
+
console.log('Received SIGINT. Shutting down...');
|
|
972
|
+
transport.close();
|
|
973
|
+
process.exit(0);
|
|
974
|
+
});
|
|
975
|
+
process.on('SIGTERM', () => {
|
|
976
|
+
console.log('Received SIGTERM. Shutting down...');
|
|
977
|
+
transport.close();
|
|
978
|
+
process.exit(0);
|
|
979
|
+
});
|
|
980
|
+
})
|
|
981
|
+
.catch(error => {
|
|
982
|
+
console.error('Failed to connect server to transport:', error);
|
|
983
|
+
process.exit(1);
|
|
984
|
+
});
|
|
87
985
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
986
|
+
else {
|
|
987
|
+
console.log('Starting server in standard mode...');
|
|
988
|
+
// Add your non-stdio server initialization here if needed
|
|
989
|
+
}
|
|
990
|
+
// Prevent unhandled promise rejections from crashing the server
|
|
991
|
+
process.on('unhandledRejection', (error) => {
|
|
992
|
+
console.error('Unhandled promise rejection:', error);
|
|
92
993
|
});
|