@taazkareem/clickup-mcp-server 0.4.60 → 0.4.63
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 +10 -2
- package/build/config.js +10 -0
- package/build/index.js +9 -1356
- package/build/server.js +120 -0
- package/build/services/clickup/base.js +253 -0
- package/build/services/clickup/bulk.js +116 -0
- package/build/services/clickup/folder.js +133 -0
- package/build/services/clickup/index.js +43 -0
- package/build/services/clickup/initialization.js +28 -0
- package/build/services/clickup/list.js +188 -0
- package/build/services/clickup/task.js +492 -0
- package/build/services/clickup/types.js +4 -0
- package/build/services/clickup/workspace.js +314 -0
- package/build/services/shared.js +15 -0
- package/build/tools/folder.js +356 -0
- package/build/tools/index.js +11 -0
- package/build/tools/list.js +452 -0
- package/build/tools/task.js +1519 -0
- package/build/tools/utils.js +150 -0
- package/build/tools/workspace.js +132 -0
- package/package.json +3 -1
- package/build/services/clickup.js +0 -765
- package/build/types/clickup.js +0 -1
package/build/index.js
CHANGED
|
@@ -34,1366 +34,19 @@
|
|
|
34
34
|
* This implementation follows the Model Context Protocol specification and
|
|
35
35
|
* is designed to be used with AI assistants that support MCP.
|
|
36
36
|
*/
|
|
37
|
-
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
38
37
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
39
|
-
import {
|
|
40
|
-
import {
|
|
41
|
-
import
|
|
42
|
-
// Initialize ClickUp service
|
|
43
|
-
const clickup = ClickUpService.initialize(config.clickupApiKey, config.clickupTeamId);
|
|
38
|
+
import { configureServer, server } from "./server.js";
|
|
39
|
+
import { clickUpServices } from "./services/shared.js";
|
|
40
|
+
import { initializeWorkspaceTool } from "./tools/workspace.js";
|
|
44
41
|
/**
|
|
45
|
-
*
|
|
46
|
-
* Resources have been removed as they are being replaced with direct tool calls.
|
|
47
|
-
*/
|
|
48
|
-
const server = new Server({
|
|
49
|
-
name: "clickup-mcp-server",
|
|
50
|
-
version: "0.4.50",
|
|
51
|
-
}, {
|
|
52
|
-
capabilities: {
|
|
53
|
-
tools: {},
|
|
54
|
-
prompts: {},
|
|
55
|
-
},
|
|
56
|
-
});
|
|
57
|
-
/**
|
|
58
|
-
* Handler that lists available tools.
|
|
59
|
-
* Exposes tools for listing spaces, creating tasks, and updating tasks.
|
|
60
|
-
*/
|
|
61
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
62
|
-
return {
|
|
63
|
-
tools: [
|
|
64
|
-
{
|
|
65
|
-
name: "get_workspace_hierarchy",
|
|
66
|
-
description: "Retrieve the complete ClickUp workspace hierarchy, including all spaces, folders, and lists with their IDs, names, and hierarchical paths. Call this tool only when you need to discover the workspace structure and don't already have this information from recent context. Avoid using for repeated lookups of the same information.",
|
|
67
|
-
inputSchema: {
|
|
68
|
-
type: "object",
|
|
69
|
-
properties: {},
|
|
70
|
-
required: []
|
|
71
|
-
}
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
name: "create_task",
|
|
75
|
-
description: "Create a single task in a ClickUp list. Use this tool for individual task creation only. For multiple tasks, use create_bulk_tasks instead. Before calling this tool, check if you already have the necessary list ID from previous responses in the conversation history, as this avoids redundant lookups. When creating a task, you must provide either a listId or listName.",
|
|
76
|
-
inputSchema: {
|
|
77
|
-
type: "object",
|
|
78
|
-
properties: {
|
|
79
|
-
listId: {
|
|
80
|
-
type: "string",
|
|
81
|
-
description: "ID of the list to create the task in (optional if using listName instead). If you have this ID from a previous response, use it directly rather than looking up by name."
|
|
82
|
-
},
|
|
83
|
-
listName: {
|
|
84
|
-
type: "string",
|
|
85
|
-
description: "Name of the list to create the task in - will automatically find the list by name (optional if using listId instead). Only use this if you don't already have the list ID from previous responses."
|
|
86
|
-
},
|
|
87
|
-
name: {
|
|
88
|
-
type: "string",
|
|
89
|
-
description: "Name of the task. Put a relevant emoji followed by a blank space before the name."
|
|
90
|
-
},
|
|
91
|
-
description: {
|
|
92
|
-
type: "string",
|
|
93
|
-
description: "Plain text description for the task"
|
|
94
|
-
},
|
|
95
|
-
markdown_description: {
|
|
96
|
-
type: "string",
|
|
97
|
-
description: "Markdown formatted description for the task. If provided, this takes precedence over description"
|
|
98
|
-
},
|
|
99
|
-
status: {
|
|
100
|
-
type: "string",
|
|
101
|
-
description: "OPTIONAL: Override the default ClickUp status. In most cases, you should omit this to use ClickUp defaults"
|
|
102
|
-
},
|
|
103
|
-
priority: {
|
|
104
|
-
type: "number",
|
|
105
|
-
description: "Priority of the task (1-4), where 1 is urgent/highest priority and 4 is lowest priority. Only set this when the user explicitly requests a priority level."
|
|
106
|
-
},
|
|
107
|
-
dueDate: {
|
|
108
|
-
type: "string",
|
|
109
|
-
description: "Due date of the task (Unix timestamp in milliseconds). Convert dates to this format before submitting."
|
|
110
|
-
}
|
|
111
|
-
},
|
|
112
|
-
required: ["name"]
|
|
113
|
-
}
|
|
114
|
-
},
|
|
115
|
-
{
|
|
116
|
-
name: "create_bulk_tasks",
|
|
117
|
-
description: "Create multiple tasks in a ClickUp list simultaneously. Use this tool when you need to add several related tasks in one operation. Before calling, check if you already have the necessary list ID from previous responses in the conversation, as this avoids redundant lookups. More efficient than creating tasks one by one for batch operations.",
|
|
118
|
-
inputSchema: {
|
|
119
|
-
type: "object",
|
|
120
|
-
properties: {
|
|
121
|
-
listId: {
|
|
122
|
-
type: "string",
|
|
123
|
-
description: "ID of the list to create the tasks in (optional if using listName instead). If you have this ID from a previous response, use it directly rather than looking up by name."
|
|
124
|
-
},
|
|
125
|
-
listName: {
|
|
126
|
-
type: "string",
|
|
127
|
-
description: "Name of the list to create the tasks in - will automatically find the list by name (optional if using listId instead). Only use this if you don't already have the list ID from previous responses."
|
|
128
|
-
},
|
|
129
|
-
tasks: {
|
|
130
|
-
type: "array",
|
|
131
|
-
description: "Array of tasks to create (at least one task required)",
|
|
132
|
-
items: {
|
|
133
|
-
type: "object",
|
|
134
|
-
properties: {
|
|
135
|
-
name: {
|
|
136
|
-
type: "string",
|
|
137
|
-
description: "Name of the task. Consider adding a relevant emoji before the name."
|
|
138
|
-
},
|
|
139
|
-
description: {
|
|
140
|
-
type: "string",
|
|
141
|
-
description: "Plain text description for the task"
|
|
142
|
-
},
|
|
143
|
-
markdown_description: {
|
|
144
|
-
type: "string",
|
|
145
|
-
description: "Markdown formatted description for the task. If provided, this takes precedence over description"
|
|
146
|
-
},
|
|
147
|
-
status: {
|
|
148
|
-
type: "string",
|
|
149
|
-
description: "OPTIONAL: Override the default ClickUp status. In most cases, you should omit this to use ClickUp defaults"
|
|
150
|
-
},
|
|
151
|
-
priority: {
|
|
152
|
-
type: "number",
|
|
153
|
-
description: "Priority level (1-4), where 1 is urgent/highest priority and 4 is lowest priority. Only set when explicitly requested."
|
|
154
|
-
},
|
|
155
|
-
dueDate: {
|
|
156
|
-
type: "string",
|
|
157
|
-
description: "Due date (Unix timestamp in milliseconds). Convert dates to this format before submitting."
|
|
158
|
-
},
|
|
159
|
-
assignees: {
|
|
160
|
-
type: "array",
|
|
161
|
-
items: {
|
|
162
|
-
type: "number"
|
|
163
|
-
},
|
|
164
|
-
description: "Array of user IDs to assign to the task"
|
|
165
|
-
}
|
|
166
|
-
},
|
|
167
|
-
required: []
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
},
|
|
171
|
-
required: ["tasks"]
|
|
172
|
-
}
|
|
173
|
-
},
|
|
174
|
-
{
|
|
175
|
-
name: "create_list",
|
|
176
|
-
description: "Create a new list directly in a ClickUp space. Use this tool when you need a top-level list not nested inside a folder. Before calling, check if you already have the necessary space ID from previous responses in the conversation, as this avoids redundant lookups. For creating lists inside folders, use create_list_in_folder instead.",
|
|
177
|
-
inputSchema: {
|
|
178
|
-
type: "object",
|
|
179
|
-
properties: {
|
|
180
|
-
spaceId: {
|
|
181
|
-
type: "string",
|
|
182
|
-
description: "ID of the space to create the list in (optional if using spaceName instead). If you have this ID from a previous response, use it directly rather than looking up by name."
|
|
183
|
-
},
|
|
184
|
-
spaceName: {
|
|
185
|
-
type: "string",
|
|
186
|
-
description: "Name of the space to create the list in - will automatically find the space by name (optional if using spaceId instead). Only use this if you don't already have the space ID from previous responses."
|
|
187
|
-
},
|
|
188
|
-
name: {
|
|
189
|
-
type: "string",
|
|
190
|
-
description: "Name of the list"
|
|
191
|
-
},
|
|
192
|
-
content: {
|
|
193
|
-
type: "string",
|
|
194
|
-
description: "Description or content of the list"
|
|
195
|
-
},
|
|
196
|
-
dueDate: {
|
|
197
|
-
type: "string",
|
|
198
|
-
description: "Due date for the list (Unix timestamp in milliseconds). Convert dates to this format before submitting."
|
|
199
|
-
},
|
|
200
|
-
priority: {
|
|
201
|
-
type: "number",
|
|
202
|
-
description: "Priority of the list (1-4), where 1 is urgent/highest priority and 4 is lowest priority. Only set when explicitly requested."
|
|
203
|
-
},
|
|
204
|
-
assignee: {
|
|
205
|
-
type: "number",
|
|
206
|
-
description: "User ID to assign the list to"
|
|
207
|
-
},
|
|
208
|
-
status: {
|
|
209
|
-
type: "string",
|
|
210
|
-
description: "Status of the list"
|
|
211
|
-
}
|
|
212
|
-
},
|
|
213
|
-
required: ["name"]
|
|
214
|
-
}
|
|
215
|
-
},
|
|
216
|
-
{
|
|
217
|
-
name: "create_folder",
|
|
218
|
-
description: "Create a new folder in a ClickUp space for organizing related lists. Use this tool when you need to group multiple lists together. Before calling, check if you already have the necessary space ID from previous responses in the conversation, as this avoids redundant lookups. After creating a folder, you can add lists to it using create_list_in_folder.",
|
|
219
|
-
inputSchema: {
|
|
220
|
-
type: "object",
|
|
221
|
-
properties: {
|
|
222
|
-
spaceId: {
|
|
223
|
-
type: "string",
|
|
224
|
-
description: "ID of the space to create the folder in (optional if using spaceName instead). If you have this ID from a previous response, use it directly rather than looking up by name."
|
|
225
|
-
},
|
|
226
|
-
spaceName: {
|
|
227
|
-
type: "string",
|
|
228
|
-
description: "Name of the space to create the folder in - will automatically find the space by name (optional if using spaceId instead). Only use this if you don't already have the space ID from previous responses."
|
|
229
|
-
},
|
|
230
|
-
name: {
|
|
231
|
-
type: "string",
|
|
232
|
-
description: "Name of the folder"
|
|
233
|
-
},
|
|
234
|
-
override_statuses: {
|
|
235
|
-
type: "boolean",
|
|
236
|
-
description: "Whether to override space statuses with folder-specific statuses"
|
|
237
|
-
}
|
|
238
|
-
},
|
|
239
|
-
required: ["name"]
|
|
240
|
-
}
|
|
241
|
-
},
|
|
242
|
-
{
|
|
243
|
-
name: "create_list_in_folder",
|
|
244
|
-
description: "Create a new list within a ClickUp folder. Use this tool when you need to add a list to an existing folder structure. Before calling, check if you already have the necessary folder ID and space ID from previous responses in the conversation, as this avoids redundant lookups. For top-level lists not in folders, use create_list instead.",
|
|
245
|
-
inputSchema: {
|
|
246
|
-
type: "object",
|
|
247
|
-
properties: {
|
|
248
|
-
name: {
|
|
249
|
-
type: "string",
|
|
250
|
-
description: "Name of the list"
|
|
251
|
-
},
|
|
252
|
-
folderId: {
|
|
253
|
-
type: "string",
|
|
254
|
-
description: "ID of the folder to create the list in (optional if using folderName instead). If you have this ID from a previous response, use it directly rather than looking up by name."
|
|
255
|
-
},
|
|
256
|
-
folderName: {
|
|
257
|
-
type: "string",
|
|
258
|
-
description: "Name of the folder to create the list in - will automatically find the folder by name (optional if using folderId instead). Only use this if you don't already have the folder ID from previous responses."
|
|
259
|
-
},
|
|
260
|
-
spaceId: {
|
|
261
|
-
type: "string",
|
|
262
|
-
description: "ID of the space containing the folder (optional if using spaceName instead). If you have this ID from a previous response, use it directly rather than looking up by name."
|
|
263
|
-
},
|
|
264
|
-
spaceName: {
|
|
265
|
-
type: "string",
|
|
266
|
-
description: "Name of the space containing the folder - will automatically find the space by name (optional if using spaceId instead). Only use this if you don't already have the space ID from previous responses."
|
|
267
|
-
},
|
|
268
|
-
content: {
|
|
269
|
-
type: "string",
|
|
270
|
-
description: "Description or content of the list"
|
|
271
|
-
},
|
|
272
|
-
status: {
|
|
273
|
-
type: "string",
|
|
274
|
-
description: "Status of the list (uses folder default if not specified)"
|
|
275
|
-
}
|
|
276
|
-
},
|
|
277
|
-
required: ["name"]
|
|
278
|
-
}
|
|
279
|
-
},
|
|
280
|
-
{
|
|
281
|
-
name: "move_task",
|
|
282
|
-
description: "Move an existing task from its current list to a different list. Use this tool when you need to relocate a task within your workspace hierarchy. Before calling, check if you already have the necessary task ID and list ID from previous responses in the conversation, as this avoids redundant lookups. Task statuses may be reset if the destination list uses different status options.",
|
|
283
|
-
inputSchema: {
|
|
284
|
-
type: "object",
|
|
285
|
-
properties: {
|
|
286
|
-
taskId: {
|
|
287
|
-
type: "string",
|
|
288
|
-
description: "ID of the task to move (optional if using taskName instead). If you have this ID from a previous response, use it directly rather than looking up by name."
|
|
289
|
-
},
|
|
290
|
-
taskName: {
|
|
291
|
-
type: "string",
|
|
292
|
-
description: "Name of the task to move - will automatically find the task by name (optional if using taskId instead). Only use this if you don't already have the task ID from previous responses."
|
|
293
|
-
},
|
|
294
|
-
sourceListName: {
|
|
295
|
-
type: "string",
|
|
296
|
-
description: "Optional: Name of the source list to narrow down task search when multiple tasks have the same name"
|
|
297
|
-
},
|
|
298
|
-
listId: {
|
|
299
|
-
type: "string",
|
|
300
|
-
description: "ID of the destination list (optional if using listName instead). If you have this ID from a previous response, use it directly rather than looking up by name."
|
|
301
|
-
},
|
|
302
|
-
listName: {
|
|
303
|
-
type: "string",
|
|
304
|
-
description: "Name of the destination list - will automatically find the list by name (optional if using listId instead). Only use this if you don't already have the list ID from previous responses."
|
|
305
|
-
}
|
|
306
|
-
},
|
|
307
|
-
required: []
|
|
308
|
-
}
|
|
309
|
-
},
|
|
310
|
-
{
|
|
311
|
-
name: "duplicate_task",
|
|
312
|
-
description: "Create a copy of an existing task in the same or different list. Use this tool when you need to replicate a task's content and properties. Before calling, check if you already have the necessary task ID and list ID from previous responses in the conversation, as this avoids redundant lookups. The duplicate will preserve name, description, priority, and other attributes from the original task.",
|
|
313
|
-
inputSchema: {
|
|
314
|
-
type: "object",
|
|
315
|
-
properties: {
|
|
316
|
-
taskId: {
|
|
317
|
-
type: "string",
|
|
318
|
-
description: "ID of the task to duplicate (optional if using taskName instead). If you have this ID from a previous response, use it directly rather than looking up by name."
|
|
319
|
-
},
|
|
320
|
-
taskName: {
|
|
321
|
-
type: "string",
|
|
322
|
-
description: "Name of the task to duplicate - will automatically find the task by name (optional if using taskId instead). Only use this if you don't already have the task ID from previous responses."
|
|
323
|
-
},
|
|
324
|
-
sourceListName: {
|
|
325
|
-
type: "string",
|
|
326
|
-
description: "Optional: Name of the source list to narrow down task search when multiple tasks have the same name"
|
|
327
|
-
},
|
|
328
|
-
listId: {
|
|
329
|
-
type: "string",
|
|
330
|
-
description: "ID of the list to create the duplicate in (optional if using listName instead). If you have this ID from a previous response, use it directly rather than looking up by name."
|
|
331
|
-
},
|
|
332
|
-
listName: {
|
|
333
|
-
type: "string",
|
|
334
|
-
description: "Name of the list to create the duplicate in - will automatically find the list by name (optional if using listId instead). Only use this if you don't already have the list ID from previous responses."
|
|
335
|
-
}
|
|
336
|
-
},
|
|
337
|
-
required: []
|
|
338
|
-
}
|
|
339
|
-
},
|
|
340
|
-
{
|
|
341
|
-
name: "update_task",
|
|
342
|
-
description: "Modify the properties of an existing task. Use this tool when you need to change a task's name, description, status, priority, or due date. Before calling, check if you already have the necessary task ID from previous responses in the conversation, as this avoids redundant lookups. Only the fields you specify will be updated; other fields will remain unchanged.",
|
|
343
|
-
inputSchema: {
|
|
344
|
-
type: "object",
|
|
345
|
-
properties: {
|
|
346
|
-
taskId: {
|
|
347
|
-
type: "string",
|
|
348
|
-
description: "ID of the task to update (optional if using taskName instead). If you have this ID from a previous response, use it directly rather than looking up by name."
|
|
349
|
-
},
|
|
350
|
-
taskName: {
|
|
351
|
-
type: "string",
|
|
352
|
-
description: "Name of the task to update - will automatically find the task by name (optional if using taskId instead). Only use this if you don't already have the task ID from previous responses."
|
|
353
|
-
},
|
|
354
|
-
listName: {
|
|
355
|
-
type: "string",
|
|
356
|
-
description: "Optional: Name of the list to narrow down task search when multiple tasks have the same name"
|
|
357
|
-
},
|
|
358
|
-
name: {
|
|
359
|
-
type: "string",
|
|
360
|
-
description: "New name for the task"
|
|
361
|
-
},
|
|
362
|
-
description: {
|
|
363
|
-
type: "string",
|
|
364
|
-
description: "New plain text description for the task"
|
|
365
|
-
},
|
|
366
|
-
markdown_description: {
|
|
367
|
-
type: "string",
|
|
368
|
-
description: "New markdown formatted description for the task. If provided, this takes precedence over description"
|
|
369
|
-
},
|
|
370
|
-
status: {
|
|
371
|
-
type: "string",
|
|
372
|
-
description: "New status for the task (must be a valid status in the task's list)"
|
|
373
|
-
},
|
|
374
|
-
priority: {
|
|
375
|
-
type: ["number", "null"],
|
|
376
|
-
enum: [1, 2, 3, 4, null],
|
|
377
|
-
description: "New priority for the task (1-4 or null), where 1 is urgent/highest priority and 4 is lowest priority. Set to null to clear priority.",
|
|
378
|
-
optional: true
|
|
379
|
-
}
|
|
380
|
-
},
|
|
381
|
-
required: []
|
|
382
|
-
}
|
|
383
|
-
},
|
|
384
|
-
{
|
|
385
|
-
name: "get_tasks",
|
|
386
|
-
description: "Retrieve tasks from a ClickUp list with optional filtering capabilities. Use this tool when you need to see existing tasks or analyze your current workload. Before calling, check if you already have the necessary list ID from previous responses in the conversation, as this avoids redundant lookups. Results can be filtered by status, assignees, dates, and more.",
|
|
387
|
-
inputSchema: {
|
|
388
|
-
type: "object",
|
|
389
|
-
properties: {
|
|
390
|
-
listId: {
|
|
391
|
-
type: "string",
|
|
392
|
-
description: "ID of the list to get tasks from (optional if using listName instead). If you have this ID from a previous response, use it directly rather than looking up by name."
|
|
393
|
-
},
|
|
394
|
-
listName: {
|
|
395
|
-
type: "string",
|
|
396
|
-
description: "Name of the list to get tasks from - will automatically find the list by name (optional if using listId instead). Only use this if you don't already have the list ID from previous responses."
|
|
397
|
-
},
|
|
398
|
-
archived: {
|
|
399
|
-
type: "boolean",
|
|
400
|
-
description: "Set to true to include archived tasks in the results"
|
|
401
|
-
},
|
|
402
|
-
page: {
|
|
403
|
-
type: "number",
|
|
404
|
-
description: "Page number for pagination when dealing with many tasks (starts at 0)"
|
|
405
|
-
},
|
|
406
|
-
order_by: {
|
|
407
|
-
type: "string",
|
|
408
|
-
description: "Field to order tasks by (e.g., 'due_date', 'created', 'updated')"
|
|
409
|
-
},
|
|
410
|
-
reverse: {
|
|
411
|
-
type: "boolean",
|
|
412
|
-
description: "Set to true to reverse the sort order (descending instead of ascending)"
|
|
413
|
-
},
|
|
414
|
-
subtasks: {
|
|
415
|
-
type: "boolean",
|
|
416
|
-
description: "Set to true to include subtasks in the results"
|
|
417
|
-
},
|
|
418
|
-
statuses: {
|
|
419
|
-
type: "array",
|
|
420
|
-
items: { type: "string" },
|
|
421
|
-
description: "Array of status names to filter tasks by (e.g., ['To Do', 'In Progress'])"
|
|
422
|
-
},
|
|
423
|
-
include_closed: {
|
|
424
|
-
type: "boolean",
|
|
425
|
-
description: "Set to true to include tasks with 'Closed' status"
|
|
426
|
-
},
|
|
427
|
-
assignees: {
|
|
428
|
-
type: "array",
|
|
429
|
-
items: { type: "string" },
|
|
430
|
-
description: "Array of user IDs to filter tasks by assignee"
|
|
431
|
-
},
|
|
432
|
-
due_date_gt: {
|
|
433
|
-
type: "number",
|
|
434
|
-
description: "Filter tasks due after this timestamp (Unix milliseconds)"
|
|
435
|
-
},
|
|
436
|
-
due_date_lt: {
|
|
437
|
-
type: "number",
|
|
438
|
-
description: "Filter tasks due before this timestamp (Unix milliseconds)"
|
|
439
|
-
},
|
|
440
|
-
date_created_gt: {
|
|
441
|
-
type: "number",
|
|
442
|
-
description: "Filter tasks created after this timestamp (Unix milliseconds)"
|
|
443
|
-
},
|
|
444
|
-
date_created_lt: {
|
|
445
|
-
type: "number",
|
|
446
|
-
description: "Filter tasks created before this timestamp (Unix milliseconds)"
|
|
447
|
-
},
|
|
448
|
-
date_updated_gt: {
|
|
449
|
-
type: "number",
|
|
450
|
-
description: "Filter tasks updated after this timestamp (Unix milliseconds)"
|
|
451
|
-
},
|
|
452
|
-
date_updated_lt: {
|
|
453
|
-
type: "number",
|
|
454
|
-
description: "Filter tasks updated before this timestamp (Unix milliseconds)"
|
|
455
|
-
},
|
|
456
|
-
custom_fields: {
|
|
457
|
-
type: "object",
|
|
458
|
-
description: "Object with custom field IDs as keys and desired values for filtering"
|
|
459
|
-
}
|
|
460
|
-
},
|
|
461
|
-
required: []
|
|
462
|
-
}
|
|
463
|
-
},
|
|
464
|
-
{
|
|
465
|
-
name: "get_task",
|
|
466
|
-
description: "Retrieve comprehensive details about a specific ClickUp task. Use this tool when you need in-depth information about a particular task, including its description, custom fields, attachments, and other metadata. Before calling, check if you already have the necessary task ID from previous responses in the conversation, as this avoids redundant lookups.",
|
|
467
|
-
inputSchema: {
|
|
468
|
-
type: "object",
|
|
469
|
-
properties: {
|
|
470
|
-
taskId: {
|
|
471
|
-
type: "string",
|
|
472
|
-
description: "ID of the task to retrieve (optional if using taskName instead). If you have this ID from a previous response, use it directly rather than looking up by name."
|
|
473
|
-
},
|
|
474
|
-
taskName: {
|
|
475
|
-
type: "string",
|
|
476
|
-
description: "Name of the task to retrieve - will automatically find the task by name (optional if using taskId instead). Only use this if you don't already have the task ID from previous responses."
|
|
477
|
-
},
|
|
478
|
-
listName: {
|
|
479
|
-
type: "string",
|
|
480
|
-
description: "Optional: Name of the list to narrow down task search when multiple tasks have the same name"
|
|
481
|
-
}
|
|
482
|
-
},
|
|
483
|
-
required: []
|
|
484
|
-
}
|
|
485
|
-
},
|
|
486
|
-
{
|
|
487
|
-
name: "delete_task",
|
|
488
|
-
description: "Permanently remove a task from your ClickUp workspace. Use this tool with caution as deletion cannot be undone. Before calling, check if you already have the necessary task ID from previous responses in the conversation, as this avoids redundant lookups. For safety, the task ID is required.",
|
|
489
|
-
inputSchema: {
|
|
490
|
-
type: "object",
|
|
491
|
-
properties: {
|
|
492
|
-
taskId: {
|
|
493
|
-
type: "string",
|
|
494
|
-
description: "ID of the task to delete - this is required for safety to prevent accidental deletions. If you have this ID from a previous response, use it directly."
|
|
495
|
-
},
|
|
496
|
-
taskName: {
|
|
497
|
-
type: "string",
|
|
498
|
-
description: "Name of the task to delete - will automatically find the task by name (optional if using taskId instead). Only use this if you don't already have the task ID from previous responses."
|
|
499
|
-
},
|
|
500
|
-
listName: {
|
|
501
|
-
type: "string",
|
|
502
|
-
description: "Optional: Name of the list to narrow down task search when multiple tasks have the same name"
|
|
503
|
-
}
|
|
504
|
-
},
|
|
505
|
-
required: []
|
|
506
|
-
}
|
|
507
|
-
},
|
|
508
|
-
{
|
|
509
|
-
name: "get_folder",
|
|
510
|
-
description: "Retrieve details about a specific ClickUp folder including its name, status, and other metadata. Before calling, check if you already have the necessary folder ID from previous responses in the conversation history, as this avoids redundant lookups. Helps you understand folder structure before creating or updating lists.",
|
|
511
|
-
inputSchema: {
|
|
512
|
-
type: "object",
|
|
513
|
-
properties: {
|
|
514
|
-
folderId: {
|
|
515
|
-
type: "string",
|
|
516
|
-
description: "ID of the folder to retrieve (optional if using folderName instead). If you have this ID from a previous response, use it directly rather than looking up by name."
|
|
517
|
-
},
|
|
518
|
-
folderName: {
|
|
519
|
-
type: "string",
|
|
520
|
-
description: "Name of the folder to retrieve - will automatically find the folder by name (optional if using folderId instead). Only use this if you don't already have the folder ID from previous responses."
|
|
521
|
-
},
|
|
522
|
-
spaceId: {
|
|
523
|
-
type: "string",
|
|
524
|
-
description: "ID of the space containing the folder (optional if using spaceName instead, and only needed when using folderName). If you have this ID from a previous response, use it directly rather than looking up by name."
|
|
525
|
-
},
|
|
526
|
-
spaceName: {
|
|
527
|
-
type: "string",
|
|
528
|
-
description: "Name of the space containing the folder (optional if using spaceId instead, and only needed when using folderName). Only use this if you don't already have the space ID from previous responses."
|
|
529
|
-
}
|
|
530
|
-
},
|
|
531
|
-
required: []
|
|
532
|
-
}
|
|
533
|
-
},
|
|
534
|
-
{
|
|
535
|
-
name: "update_folder",
|
|
536
|
-
description: "Modify an existing ClickUp folder's properties, such as name or status settings. Before calling, check if you already have the necessary folder ID from previous responses in the conversation history, as this avoids redundant lookups. Use when reorganizing or renaming workspace elements.",
|
|
537
|
-
inputSchema: {
|
|
538
|
-
type: "object",
|
|
539
|
-
properties: {
|
|
540
|
-
folderId: {
|
|
541
|
-
type: "string",
|
|
542
|
-
description: "ID of the folder to update (optional if using folderName instead). If you have this ID from a previous response, use it directly rather than looking up by name."
|
|
543
|
-
},
|
|
544
|
-
folderName: {
|
|
545
|
-
type: "string",
|
|
546
|
-
description: "Name of the folder to update - will automatically find the folder by name (optional if using folderId instead). Only use this if you don't already have the folder ID from previous responses."
|
|
547
|
-
},
|
|
548
|
-
spaceId: {
|
|
549
|
-
type: "string",
|
|
550
|
-
description: "ID of the space containing the folder (optional if using spaceName instead, and only needed when using folderName). If you have this ID from a previous response, use it directly rather than looking up by name."
|
|
551
|
-
},
|
|
552
|
-
spaceName: {
|
|
553
|
-
type: "string",
|
|
554
|
-
description: "Name of the space containing the folder (optional if using spaceId instead, and only needed when using folderName). Only use this if you don't already have the space ID from previous responses."
|
|
555
|
-
},
|
|
556
|
-
name: {
|
|
557
|
-
type: "string",
|
|
558
|
-
description: "New name for the folder"
|
|
559
|
-
},
|
|
560
|
-
override_statuses: {
|
|
561
|
-
type: "boolean",
|
|
562
|
-
description: "Whether to override space statuses with folder-specific statuses"
|
|
563
|
-
}
|
|
564
|
-
},
|
|
565
|
-
required: []
|
|
566
|
-
}
|
|
567
|
-
},
|
|
568
|
-
{
|
|
569
|
-
name: "delete_folder",
|
|
570
|
-
description: "Permanently remove a folder from your ClickUp workspace. Use with caution as deletion cannot be undone and will remove all lists and tasks within the folder. Before calling, check if you already have the necessary folder ID from previous responses in the conversation history, as this avoids redundant lookups.",
|
|
571
|
-
inputSchema: {
|
|
572
|
-
type: "object",
|
|
573
|
-
properties: {
|
|
574
|
-
folderId: {
|
|
575
|
-
type: "string",
|
|
576
|
-
description: "ID of the folder to delete (optional if using folderName instead). If you have this ID from a previous response, use it directly rather than looking up by name."
|
|
577
|
-
},
|
|
578
|
-
folderName: {
|
|
579
|
-
type: "string",
|
|
580
|
-
description: "Name of the folder to delete - will automatically find the folder by name (optional if using folderId instead). Only use this if you don't already have the folder ID from previous responses."
|
|
581
|
-
},
|
|
582
|
-
spaceId: {
|
|
583
|
-
type: "string",
|
|
584
|
-
description: "ID of the space containing the folder (optional if using spaceName instead, and only needed when using folderName). If you have this ID from a previous response, use it directly rather than looking up by name."
|
|
585
|
-
},
|
|
586
|
-
spaceName: {
|
|
587
|
-
type: "string",
|
|
588
|
-
description: "Name of the space containing the folder (optional if using spaceId instead, and only needed when using folderName). Only use this if you don't already have the space ID from previous responses."
|
|
589
|
-
}
|
|
590
|
-
},
|
|
591
|
-
required: []
|
|
592
|
-
}
|
|
593
|
-
},
|
|
594
|
-
{
|
|
595
|
-
name: "get_list",
|
|
596
|
-
description: "Retrieve details about a specific ClickUp list including its name, content, status options, and other metadata. Before calling, check if you already have the necessary list ID from previous responses in the conversation history, as this avoids redundant lookups. Useful to understand list structure before creating or updating tasks.",
|
|
597
|
-
inputSchema: {
|
|
598
|
-
type: "object",
|
|
599
|
-
properties: {
|
|
600
|
-
listId: {
|
|
601
|
-
type: "string",
|
|
602
|
-
description: "ID of the list to retrieve (optional if using listName instead). If you have this ID from a previous response, use it directly rather than looking up by name."
|
|
603
|
-
},
|
|
604
|
-
listName: {
|
|
605
|
-
type: "string",
|
|
606
|
-
description: "Name of the list to retrieve - will automatically find the list by name (optional if using listId instead). Only use this if you don't already have the list ID from previous responses."
|
|
607
|
-
}
|
|
608
|
-
},
|
|
609
|
-
required: []
|
|
610
|
-
}
|
|
611
|
-
},
|
|
612
|
-
{
|
|
613
|
-
name: "update_list",
|
|
614
|
-
description: "Modify an existing ClickUp list's properties, such as name, content, or status options. Before calling, check if you already have the necessary list ID from previous responses in the conversation history, as this avoids redundant lookups. Use when reorganizing or renaming workspace elements.",
|
|
615
|
-
inputSchema: {
|
|
616
|
-
type: "object",
|
|
617
|
-
properties: {
|
|
618
|
-
listId: {
|
|
619
|
-
type: "string",
|
|
620
|
-
description: "ID of the list to update (optional if using listName instead). If you have this ID from a previous response, use it directly rather than looking up by name."
|
|
621
|
-
},
|
|
622
|
-
listName: {
|
|
623
|
-
type: "string",
|
|
624
|
-
description: "Name of the list to update - will automatically find the list by name (optional if using listId instead). Only use this if you don't already have the list ID from previous responses."
|
|
625
|
-
},
|
|
626
|
-
name: {
|
|
627
|
-
type: "string",
|
|
628
|
-
description: "New name for the list"
|
|
629
|
-
},
|
|
630
|
-
content: {
|
|
631
|
-
type: "string",
|
|
632
|
-
description: "New description or content for the list"
|
|
633
|
-
},
|
|
634
|
-
status: {
|
|
635
|
-
type: "string",
|
|
636
|
-
description: "New status for the list"
|
|
637
|
-
}
|
|
638
|
-
},
|
|
639
|
-
required: []
|
|
640
|
-
}
|
|
641
|
-
},
|
|
642
|
-
{
|
|
643
|
-
name: "delete_list",
|
|
644
|
-
description: "Permanently remove a list from your ClickUp workspace. Use with caution as deletion cannot be undone and will remove all tasks within the list. Before calling, check if you already have the necessary list ID from previous responses in the conversation history, as this avoids redundant lookups.",
|
|
645
|
-
inputSchema: {
|
|
646
|
-
type: "object",
|
|
647
|
-
properties: {
|
|
648
|
-
listId: {
|
|
649
|
-
type: "string",
|
|
650
|
-
description: "ID of the list to delete (optional if using listName instead). If you have this ID from a previous response, use it directly rather than looking up by name."
|
|
651
|
-
},
|
|
652
|
-
listName: {
|
|
653
|
-
type: "string",
|
|
654
|
-
description: "Name of the list to delete - will automatically find the list by name (optional if using listId instead). Only use this if you don't already have the list ID from previous responses."
|
|
655
|
-
}
|
|
656
|
-
},
|
|
657
|
-
required: []
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
]
|
|
661
|
-
};
|
|
662
|
-
});
|
|
663
|
-
/**
|
|
664
|
-
* Handler for the CallToolRequestSchema.
|
|
665
|
-
* Handles the execution of tools like listing spaces, creating tasks, and updating tasks.
|
|
666
|
-
*/
|
|
667
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
668
|
-
try {
|
|
669
|
-
switch (request.params.name) {
|
|
670
|
-
case "get_workspace_hierarchy": {
|
|
671
|
-
const hierarchy = await clickup.getWorkspaceHierarchy();
|
|
672
|
-
return {
|
|
673
|
-
content: [{
|
|
674
|
-
type: "text",
|
|
675
|
-
text: JSON.stringify({
|
|
676
|
-
workspace: {
|
|
677
|
-
id: hierarchy.root.id,
|
|
678
|
-
name: hierarchy.root.name,
|
|
679
|
-
spaces: hierarchy.root.children.map((space) => ({
|
|
680
|
-
id: space.id,
|
|
681
|
-
name: space.name,
|
|
682
|
-
lists: space.children
|
|
683
|
-
.filter((node) => node.type === 'list')
|
|
684
|
-
.map((list) => ({
|
|
685
|
-
id: list.id,
|
|
686
|
-
name: list.name,
|
|
687
|
-
path: `${space.name} > ${list.name}`
|
|
688
|
-
})),
|
|
689
|
-
folders: space.children
|
|
690
|
-
.filter((node) => node.type === 'folder')
|
|
691
|
-
.map((folder) => ({
|
|
692
|
-
id: folder.id,
|
|
693
|
-
name: folder.name,
|
|
694
|
-
path: `${space.name} > ${folder.name}`,
|
|
695
|
-
lists: folder.children.map((list) => ({
|
|
696
|
-
id: list.id,
|
|
697
|
-
name: list.name,
|
|
698
|
-
path: `${space.name} > ${folder.name} > ${list.name}`
|
|
699
|
-
}))
|
|
700
|
-
}))
|
|
701
|
-
}))
|
|
702
|
-
}
|
|
703
|
-
}, null, 2)
|
|
704
|
-
}]
|
|
705
|
-
};
|
|
706
|
-
}
|
|
707
|
-
case "create_task": {
|
|
708
|
-
const args = request.params.arguments;
|
|
709
|
-
if (!args.listId && !args.listName) {
|
|
710
|
-
throw new Error("Either listId or listName is required");
|
|
711
|
-
}
|
|
712
|
-
if (!args.name) {
|
|
713
|
-
throw new Error("name is required");
|
|
714
|
-
}
|
|
715
|
-
let listId = args.listId;
|
|
716
|
-
if (!listId && args.listName) {
|
|
717
|
-
const hierarchy = await clickup.getWorkspaceHierarchy();
|
|
718
|
-
const result = clickup.findIDByNameInHierarchy(hierarchy, args.listName, 'list');
|
|
719
|
-
if (!result) {
|
|
720
|
-
throw new Error(`List with name "${args.listName}" not found`);
|
|
721
|
-
}
|
|
722
|
-
listId = result.id;
|
|
723
|
-
}
|
|
724
|
-
const { listId: _, listName: __, ...taskData } = args;
|
|
725
|
-
const task = await clickup.createTask(listId, taskData);
|
|
726
|
-
return {
|
|
727
|
-
content: [{
|
|
728
|
-
type: "text",
|
|
729
|
-
text: `Created task ${task.id}: ${task.name}`
|
|
730
|
-
}]
|
|
731
|
-
};
|
|
732
|
-
}
|
|
733
|
-
case "create_bulk_tasks": {
|
|
734
|
-
const args = request.params.arguments;
|
|
735
|
-
// First validate tasks array
|
|
736
|
-
if (!args.tasks || !Array.isArray(args.tasks) || args.tasks.length === 0) {
|
|
737
|
-
throw new Error("tasks array is required and must not be empty");
|
|
738
|
-
}
|
|
739
|
-
// Validate each task has required fields
|
|
740
|
-
args.tasks.forEach((task, index) => {
|
|
741
|
-
if (!task.name) {
|
|
742
|
-
throw new Error(`Task at index ${index} is missing required field 'name'`);
|
|
743
|
-
}
|
|
744
|
-
});
|
|
745
|
-
// Get listId from name if needed
|
|
746
|
-
let listId = args.listId;
|
|
747
|
-
if (!listId && args.listName) {
|
|
748
|
-
const result = await clickup.findListIDByName(args.listName);
|
|
749
|
-
if (!result) {
|
|
750
|
-
throw new Error(`List with name "${args.listName}" not found`);
|
|
751
|
-
}
|
|
752
|
-
listId = result.id;
|
|
753
|
-
}
|
|
754
|
-
// Now validate we have a listId
|
|
755
|
-
if (!listId) {
|
|
756
|
-
throw new Error("Either listId or listName must be provided");
|
|
757
|
-
}
|
|
758
|
-
const { listId: _, listName: __, tasks } = args;
|
|
759
|
-
const createdTasks = await clickup.createBulkTasks(listId, { tasks });
|
|
760
|
-
return {
|
|
761
|
-
content: [{
|
|
762
|
-
type: "text",
|
|
763
|
-
text: JSON.stringify({
|
|
764
|
-
message: `Created ${createdTasks.length} tasks`,
|
|
765
|
-
tasks: createdTasks.map(task => ({
|
|
766
|
-
id: task.id,
|
|
767
|
-
name: task.name,
|
|
768
|
-
url: task.url
|
|
769
|
-
}))
|
|
770
|
-
}, null, 2)
|
|
771
|
-
}]
|
|
772
|
-
};
|
|
773
|
-
}
|
|
774
|
-
case "create_list": {
|
|
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 foundId = await clickup.findSpaceIDByName(args.spaceName);
|
|
782
|
-
if (!foundId) {
|
|
783
|
-
throw new Error(`Space with name "${args.spaceName}" not found`);
|
|
784
|
-
}
|
|
785
|
-
spaceId = foundId;
|
|
786
|
-
}
|
|
787
|
-
if (!spaceId) {
|
|
788
|
-
throw new Error("Either spaceId or spaceName must be provided");
|
|
789
|
-
}
|
|
790
|
-
const { spaceId: _, spaceName: __, ...listData } = args;
|
|
791
|
-
const list = await clickup.createList(spaceId, listData);
|
|
792
|
-
return {
|
|
793
|
-
content: [{
|
|
794
|
-
type: "text",
|
|
795
|
-
text: `Created list ${list.id}: ${list.name}`
|
|
796
|
-
}]
|
|
797
|
-
};
|
|
798
|
-
}
|
|
799
|
-
case "create_folder": {
|
|
800
|
-
const args = request.params.arguments;
|
|
801
|
-
if (!args.name) {
|
|
802
|
-
throw new Error("name is required");
|
|
803
|
-
}
|
|
804
|
-
let spaceId = args.spaceId;
|
|
805
|
-
if (!spaceId && args.spaceName) {
|
|
806
|
-
const foundId = await clickup.findSpaceIDByName(args.spaceName);
|
|
807
|
-
if (!foundId) {
|
|
808
|
-
throw new Error(`Space with name "${args.spaceName}" not found`);
|
|
809
|
-
}
|
|
810
|
-
spaceId = foundId;
|
|
811
|
-
}
|
|
812
|
-
if (!spaceId) {
|
|
813
|
-
throw new Error("Either spaceId or spaceName must be provided");
|
|
814
|
-
}
|
|
815
|
-
const { spaceId: _, spaceName: __, ...folderData } = args;
|
|
816
|
-
const folder = await clickup.createFolder(spaceId, folderData);
|
|
817
|
-
return {
|
|
818
|
-
content: [{
|
|
819
|
-
type: "text",
|
|
820
|
-
text: `Created folder ${folder.id}: ${folder.name}`
|
|
821
|
-
}]
|
|
822
|
-
};
|
|
823
|
-
}
|
|
824
|
-
case "create_list_in_folder": {
|
|
825
|
-
const args = request.params.arguments;
|
|
826
|
-
if (!args.name) {
|
|
827
|
-
throw new Error("name is required");
|
|
828
|
-
}
|
|
829
|
-
let folderId = args.folderId;
|
|
830
|
-
if (!folderId && args.folderName) {
|
|
831
|
-
const result = await clickup.findFolderIDByName(args.folderName);
|
|
832
|
-
if (!result) {
|
|
833
|
-
throw new Error(`Folder with name "${args.folderName}" not found`);
|
|
834
|
-
}
|
|
835
|
-
folderId = result.id;
|
|
836
|
-
}
|
|
837
|
-
if (!folderId) {
|
|
838
|
-
throw new Error("Either folderId or folderName must be provided");
|
|
839
|
-
}
|
|
840
|
-
const { folderId: _, folderName: __, spaceId: ___, spaceName: ____, ...listData } = args;
|
|
841
|
-
const list = await clickup.createListInFolder(folderId, listData);
|
|
842
|
-
return {
|
|
843
|
-
content: [{
|
|
844
|
-
type: "text",
|
|
845
|
-
text: `Created list ${list.id}: ${list.name} in folder`
|
|
846
|
-
}]
|
|
847
|
-
};
|
|
848
|
-
}
|
|
849
|
-
case "move_task": {
|
|
850
|
-
const args = request.params.arguments;
|
|
851
|
-
if (!args.taskId && !args.taskName) {
|
|
852
|
-
throw new Error("Either taskId or taskName is required");
|
|
853
|
-
}
|
|
854
|
-
if (!args.listId && !args.listName) {
|
|
855
|
-
throw new Error("Either listId or listName is required");
|
|
856
|
-
}
|
|
857
|
-
let taskId = args.taskId;
|
|
858
|
-
if (!taskId && args.taskName) {
|
|
859
|
-
const result = await clickup.findTaskByName(args.taskName, undefined, args.sourceListName);
|
|
860
|
-
if (!result) {
|
|
861
|
-
throw new Error(`Task with name "${args.taskName}" not found${args.sourceListName ? ` in list "${args.sourceListName}"` : ''}`);
|
|
862
|
-
}
|
|
863
|
-
taskId = result.id;
|
|
864
|
-
}
|
|
865
|
-
let listId = args.listId;
|
|
866
|
-
if (!listId && args.listName) {
|
|
867
|
-
const result = await clickup.findListIDByName(args.listName);
|
|
868
|
-
if (!result) {
|
|
869
|
-
throw new Error(`List with name "${args.listName}" not found`);
|
|
870
|
-
}
|
|
871
|
-
listId = result.id;
|
|
872
|
-
}
|
|
873
|
-
// Get the original task details for the response message
|
|
874
|
-
const originalTask = await clickup.getTask(taskId);
|
|
875
|
-
const newTask = await clickup.moveTask(taskId, listId);
|
|
876
|
-
return {
|
|
877
|
-
content: [{
|
|
878
|
-
type: "text",
|
|
879
|
-
text: `Moved task "${originalTask.name}" from "${originalTask.list.name}" to "${newTask.list.name}"`
|
|
880
|
-
}]
|
|
881
|
-
};
|
|
882
|
-
}
|
|
883
|
-
case "duplicate_task": {
|
|
884
|
-
const args = request.params.arguments;
|
|
885
|
-
// Require either taskId or taskName
|
|
886
|
-
if (!args.taskId && !args.taskName) {
|
|
887
|
-
throw new Error("Either taskId or taskName is required");
|
|
888
|
-
}
|
|
889
|
-
// Require either listId or listName
|
|
890
|
-
if (!args.listId && !args.listName) {
|
|
891
|
-
throw new Error("Either listId or listName is required");
|
|
892
|
-
}
|
|
893
|
-
// Get taskId from taskName if needed
|
|
894
|
-
let taskId = args.taskId;
|
|
895
|
-
if (!taskId && args.taskName) {
|
|
896
|
-
const result = await clickup.findTaskByName(args.taskName, undefined, args.sourceListName);
|
|
897
|
-
if (!result) {
|
|
898
|
-
throw new Error(`Task with name "${args.taskName}" not found${args.sourceListName ? ` in list "${args.sourceListName}"` : ''}`);
|
|
899
|
-
}
|
|
900
|
-
taskId = result.id;
|
|
901
|
-
}
|
|
902
|
-
// Get listId from listName if needed
|
|
903
|
-
let listId = args.listId;
|
|
904
|
-
if (!listId && args.listName) {
|
|
905
|
-
const result = await clickup.findListIDByName(args.listName);
|
|
906
|
-
if (!result) {
|
|
907
|
-
throw new Error(`List with name "${args.listName}" not found`);
|
|
908
|
-
}
|
|
909
|
-
listId = result.id;
|
|
910
|
-
}
|
|
911
|
-
// Get the original task details for the response message
|
|
912
|
-
const originalTask = await clickup.getTask(taskId);
|
|
913
|
-
const newTask = await clickup.duplicateTask(taskId, listId);
|
|
914
|
-
return {
|
|
915
|
-
content: [{
|
|
916
|
-
type: "text",
|
|
917
|
-
text: `Duplicated task "${originalTask.name}" from "${originalTask.list.name}" to "${newTask.list.name}"`
|
|
918
|
-
}]
|
|
919
|
-
};
|
|
920
|
-
}
|
|
921
|
-
case "update_task": {
|
|
922
|
-
const args = request.params.arguments;
|
|
923
|
-
// Require either taskId or taskName
|
|
924
|
-
if (!args.taskId && !args.taskName) {
|
|
925
|
-
throw new Error("Either taskId or taskName is required");
|
|
926
|
-
}
|
|
927
|
-
// Get taskId from taskName if needed
|
|
928
|
-
let taskId = args.taskId;
|
|
929
|
-
if (!taskId && args.taskName) {
|
|
930
|
-
const result = await clickup.findTaskByName(args.taskName, undefined, args.listName);
|
|
931
|
-
if (!result) {
|
|
932
|
-
throw new Error(`Task with name "${args.taskName}" not found${args.listName ? ` in list "${args.listName}"` : ''}`);
|
|
933
|
-
}
|
|
934
|
-
taskId = result.id;
|
|
935
|
-
}
|
|
936
|
-
// Remove helper fields before updating
|
|
937
|
-
const { taskId: _, taskName: __, listName: ___, ...updateData } = args;
|
|
938
|
-
// Ensure priority is properly handled
|
|
939
|
-
if (updateData.priority !== undefined && updateData.priority !== null) {
|
|
940
|
-
const priority = Number(updateData.priority);
|
|
941
|
-
if (isNaN(priority) || ![1, 2, 3, 4].includes(priority)) {
|
|
942
|
-
throw new Error("Priority must be a number between 1 and 4, or null to clear priority");
|
|
943
|
-
}
|
|
944
|
-
updateData.priority = priority;
|
|
945
|
-
}
|
|
946
|
-
const task = await clickup.updateTask(taskId, updateData);
|
|
947
|
-
return {
|
|
948
|
-
content: [{
|
|
949
|
-
type: "text",
|
|
950
|
-
text: `Updated task ${task.id}: ${task.name}`
|
|
951
|
-
}]
|
|
952
|
-
};
|
|
953
|
-
}
|
|
954
|
-
case "get_tasks": {
|
|
955
|
-
const args = request.params.arguments;
|
|
956
|
-
// Enforce required listName field as specified in the schema
|
|
957
|
-
if (!args.listId && !args.listName) {
|
|
958
|
-
throw new Error("Either listId or listName is required");
|
|
959
|
-
}
|
|
960
|
-
let listId = args.listId;
|
|
961
|
-
if (!listId && args.listName) {
|
|
962
|
-
const result = await clickup.findListIDByName(args.listName);
|
|
963
|
-
if (!result) {
|
|
964
|
-
throw new Error(`List with name "${args.listName}" not found`);
|
|
965
|
-
}
|
|
966
|
-
listId = result.id;
|
|
967
|
-
}
|
|
968
|
-
// Remove listId and listName from filters
|
|
969
|
-
const { listId: _, listName: __, ...filters } = args;
|
|
970
|
-
const { tasks, statuses } = await clickup.getTasks(listId, filters);
|
|
971
|
-
return {
|
|
972
|
-
content: [{
|
|
973
|
-
type: "text",
|
|
974
|
-
text: JSON.stringify({ tasks, available_statuses: statuses }, null, 2)
|
|
975
|
-
}]
|
|
976
|
-
};
|
|
977
|
-
}
|
|
978
|
-
case "get_task": {
|
|
979
|
-
const args = request.params.arguments;
|
|
980
|
-
// Enforce required taskName field as specified in the schema
|
|
981
|
-
if (!args.taskId && !args.taskName) {
|
|
982
|
-
throw new Error("Either taskId or taskName is required");
|
|
983
|
-
}
|
|
984
|
-
let taskId = args.taskId;
|
|
985
|
-
if (!taskId && args.taskName) {
|
|
986
|
-
const result = await clickup.findTaskByName(args.taskName, undefined, args.listName);
|
|
987
|
-
if (!result) {
|
|
988
|
-
throw new Error(`Task with name "${args.taskName}" not found${args.listName ? ` in list "${args.listName}"` : ''}`);
|
|
989
|
-
}
|
|
990
|
-
taskId = result.id;
|
|
991
|
-
}
|
|
992
|
-
const task = await clickup.getTask(taskId);
|
|
993
|
-
return {
|
|
994
|
-
content: [{
|
|
995
|
-
type: "text",
|
|
996
|
-
text: JSON.stringify(task, null, 2)
|
|
997
|
-
}]
|
|
998
|
-
};
|
|
999
|
-
}
|
|
1000
|
-
case "delete_task": {
|
|
1001
|
-
const args = request.params.arguments;
|
|
1002
|
-
if (!args.taskId && !args.taskName) {
|
|
1003
|
-
throw new Error("Either taskId or taskName is required");
|
|
1004
|
-
}
|
|
1005
|
-
await clickup.deleteTask(args.taskId, args.taskName, args.listName);
|
|
1006
|
-
return {
|
|
1007
|
-
content: [{
|
|
1008
|
-
type: "text",
|
|
1009
|
-
text: `Successfully deleted task${args.taskName ? ` "${args.taskName}"` : ` with ID ${args.taskId}`}`
|
|
1010
|
-
}]
|
|
1011
|
-
};
|
|
1012
|
-
}
|
|
1013
|
-
case "get_folder": {
|
|
1014
|
-
const args = request.params.arguments;
|
|
1015
|
-
if (!args.folderId && !args.folderName) {
|
|
1016
|
-
throw new Error("Either folderId or folderName is required");
|
|
1017
|
-
}
|
|
1018
|
-
let folderId = args.folderId;
|
|
1019
|
-
if (!folderId && args.folderName) {
|
|
1020
|
-
// If we need to look up by name, we might need the space
|
|
1021
|
-
let spaceId = args.spaceId;
|
|
1022
|
-
if (!spaceId && args.spaceName) {
|
|
1023
|
-
const foundId = await clickup.findSpaceIDByName(args.spaceName);
|
|
1024
|
-
if (!foundId) {
|
|
1025
|
-
throw new Error(`Space with name "${args.spaceName}" not found`);
|
|
1026
|
-
}
|
|
1027
|
-
spaceId = foundId;
|
|
1028
|
-
}
|
|
1029
|
-
if (!spaceId) {
|
|
1030
|
-
// Try to find folder directly by name (will search across all spaces)
|
|
1031
|
-
const result = await clickup.findFolderIDByName(args.folderName);
|
|
1032
|
-
if (!result) {
|
|
1033
|
-
throw new Error(`Folder with name "${args.folderName}" not found`);
|
|
1034
|
-
}
|
|
1035
|
-
folderId = result.id;
|
|
1036
|
-
}
|
|
1037
|
-
else {
|
|
1038
|
-
// Look in a specific space
|
|
1039
|
-
const folder = await clickup.findFolderByName(spaceId, args.folderName);
|
|
1040
|
-
if (!folder) {
|
|
1041
|
-
throw new Error(`Folder with name "${args.folderName}" not found in specified space`);
|
|
1042
|
-
}
|
|
1043
|
-
folderId = folder.id;
|
|
1044
|
-
}
|
|
1045
|
-
}
|
|
1046
|
-
// Ensure folderId is defined at this point
|
|
1047
|
-
if (!folderId) {
|
|
1048
|
-
throw new Error("Failed to determine folder ID");
|
|
1049
|
-
}
|
|
1050
|
-
const folder = await clickup.getFolder(folderId);
|
|
1051
|
-
return {
|
|
1052
|
-
content: [{
|
|
1053
|
-
type: "text",
|
|
1054
|
-
text: JSON.stringify(folder, null, 2)
|
|
1055
|
-
}]
|
|
1056
|
-
};
|
|
1057
|
-
}
|
|
1058
|
-
case "update_folder": {
|
|
1059
|
-
const args = request.params.arguments;
|
|
1060
|
-
if (!args.folderId && !args.folderName) {
|
|
1061
|
-
throw new Error("Either folderId or folderName is required");
|
|
1062
|
-
}
|
|
1063
|
-
let folderId = args.folderId;
|
|
1064
|
-
if (!folderId && args.folderName) {
|
|
1065
|
-
// If we need to look up by name, we might need the space
|
|
1066
|
-
let spaceId = args.spaceId;
|
|
1067
|
-
if (!spaceId && args.spaceName) {
|
|
1068
|
-
const foundId = await clickup.findSpaceIDByName(args.spaceName);
|
|
1069
|
-
if (!foundId) {
|
|
1070
|
-
throw new Error(`Space with name "${args.spaceName}" not found`);
|
|
1071
|
-
}
|
|
1072
|
-
spaceId = foundId;
|
|
1073
|
-
}
|
|
1074
|
-
if (!spaceId) {
|
|
1075
|
-
// Try to find folder directly by name (will search across all spaces)
|
|
1076
|
-
const result = await clickup.findFolderIDByName(args.folderName);
|
|
1077
|
-
if (!result) {
|
|
1078
|
-
throw new Error(`Folder with name "${args.folderName}" not found`);
|
|
1079
|
-
}
|
|
1080
|
-
folderId = result.id;
|
|
1081
|
-
}
|
|
1082
|
-
else {
|
|
1083
|
-
// Look in a specific space
|
|
1084
|
-
const folder = await clickup.findFolderByName(spaceId, args.folderName);
|
|
1085
|
-
if (!folder) {
|
|
1086
|
-
throw new Error(`Folder with name "${args.folderName}" not found in specified space`);
|
|
1087
|
-
}
|
|
1088
|
-
folderId = folder.id;
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
|
-
// Ensure folderId is defined at this point
|
|
1092
|
-
if (!folderId) {
|
|
1093
|
-
throw new Error("Failed to determine folder ID");
|
|
1094
|
-
}
|
|
1095
|
-
// Extract update data
|
|
1096
|
-
const { folderId: _, folderName: __, spaceId: ___, spaceName: ____, ...updateData } = args;
|
|
1097
|
-
// Call the updateFolder method
|
|
1098
|
-
const updatedFolder = await clickup.updateFolder(folderId, updateData);
|
|
1099
|
-
return {
|
|
1100
|
-
content: [{
|
|
1101
|
-
type: "text",
|
|
1102
|
-
text: `Updated folder ${updatedFolder.id}: ${updatedFolder.name}`
|
|
1103
|
-
}]
|
|
1104
|
-
};
|
|
1105
|
-
}
|
|
1106
|
-
case "delete_folder": {
|
|
1107
|
-
const args = request.params.arguments;
|
|
1108
|
-
if (!args.folderId && !args.folderName) {
|
|
1109
|
-
throw new Error("Either folderId or folderName is required");
|
|
1110
|
-
}
|
|
1111
|
-
let folderId = args.folderId;
|
|
1112
|
-
if (!folderId && args.folderName) {
|
|
1113
|
-
// If we need to look up by name, we might need the space
|
|
1114
|
-
let spaceId = args.spaceId;
|
|
1115
|
-
if (!spaceId && args.spaceName) {
|
|
1116
|
-
const foundId = await clickup.findSpaceIDByName(args.spaceName);
|
|
1117
|
-
if (!foundId) {
|
|
1118
|
-
throw new Error(`Space with name "${args.spaceName}" not found`);
|
|
1119
|
-
}
|
|
1120
|
-
spaceId = foundId;
|
|
1121
|
-
}
|
|
1122
|
-
if (!spaceId) {
|
|
1123
|
-
// Try to find folder directly by name (will search across all spaces)
|
|
1124
|
-
const result = await clickup.findFolderIDByName(args.folderName);
|
|
1125
|
-
if (!result) {
|
|
1126
|
-
throw new Error(`Folder with name "${args.folderName}" not found`);
|
|
1127
|
-
}
|
|
1128
|
-
folderId = result.id;
|
|
1129
|
-
}
|
|
1130
|
-
else {
|
|
1131
|
-
// Look in a specific space
|
|
1132
|
-
const folder = await clickup.findFolderByName(spaceId, args.folderName);
|
|
1133
|
-
if (!folder) {
|
|
1134
|
-
throw new Error(`Folder with name "${args.folderName}" not found in specified space`);
|
|
1135
|
-
}
|
|
1136
|
-
folderId = folder.id;
|
|
1137
|
-
}
|
|
1138
|
-
}
|
|
1139
|
-
// Ensure folderId is defined at this point
|
|
1140
|
-
if (!folderId) {
|
|
1141
|
-
throw new Error("Failed to determine folder ID");
|
|
1142
|
-
}
|
|
1143
|
-
// Store the folder name before deletion for the response message
|
|
1144
|
-
let folderName = args.folderName;
|
|
1145
|
-
if (!folderName) {
|
|
1146
|
-
try {
|
|
1147
|
-
const folderDetails = await clickup.getFolder(folderId);
|
|
1148
|
-
folderName = folderDetails.name;
|
|
1149
|
-
}
|
|
1150
|
-
catch (error) {
|
|
1151
|
-
// If we can't get the folder details, just use the ID in the response
|
|
1152
|
-
}
|
|
1153
|
-
}
|
|
1154
|
-
await clickup.deleteFolder(folderId);
|
|
1155
|
-
return {
|
|
1156
|
-
content: [{
|
|
1157
|
-
type: "text",
|
|
1158
|
-
text: `Successfully deleted folder ${folderName || folderId}`
|
|
1159
|
-
}]
|
|
1160
|
-
};
|
|
1161
|
-
}
|
|
1162
|
-
case "get_list": {
|
|
1163
|
-
const args = request.params.arguments;
|
|
1164
|
-
if (!args.listId && !args.listName) {
|
|
1165
|
-
throw new Error("Either listId or listName is required");
|
|
1166
|
-
}
|
|
1167
|
-
let listId = args.listId;
|
|
1168
|
-
if (!listId && args.listName) {
|
|
1169
|
-
const result = await clickup.findListIDByName(args.listName);
|
|
1170
|
-
if (!result) {
|
|
1171
|
-
throw new Error(`List with name "${args.listName}" not found`);
|
|
1172
|
-
}
|
|
1173
|
-
listId = result.id;
|
|
1174
|
-
}
|
|
1175
|
-
// Ensure listId is defined at this point
|
|
1176
|
-
if (!listId) {
|
|
1177
|
-
throw new Error("Failed to determine list ID");
|
|
1178
|
-
}
|
|
1179
|
-
const listDetails = await clickup.getList(listId);
|
|
1180
|
-
return {
|
|
1181
|
-
content: [{
|
|
1182
|
-
type: "text",
|
|
1183
|
-
text: JSON.stringify(listDetails, null, 2)
|
|
1184
|
-
}]
|
|
1185
|
-
};
|
|
1186
|
-
}
|
|
1187
|
-
case "update_list": {
|
|
1188
|
-
const args = request.params.arguments;
|
|
1189
|
-
if (!args.listId && !args.listName) {
|
|
1190
|
-
throw new Error("Either listId or listName is required");
|
|
1191
|
-
}
|
|
1192
|
-
let listId = args.listId;
|
|
1193
|
-
if (!listId && args.listName) {
|
|
1194
|
-
const result = await clickup.findListIDByName(args.listName);
|
|
1195
|
-
if (!result) {
|
|
1196
|
-
throw new Error(`List with name "${args.listName}" not found`);
|
|
1197
|
-
}
|
|
1198
|
-
listId = result.id;
|
|
1199
|
-
}
|
|
1200
|
-
// Ensure listId is defined at this point
|
|
1201
|
-
if (!listId) {
|
|
1202
|
-
throw new Error("Failed to determine list ID");
|
|
1203
|
-
}
|
|
1204
|
-
// Extract update data
|
|
1205
|
-
const { listId: _, listName: __, ...updateData } = args;
|
|
1206
|
-
const updatedList = await clickup.updateList(listId, updateData);
|
|
1207
|
-
return {
|
|
1208
|
-
content: [{
|
|
1209
|
-
type: "text",
|
|
1210
|
-
text: `Updated list ${updatedList.id}: ${updatedList.name}`
|
|
1211
|
-
}]
|
|
1212
|
-
};
|
|
1213
|
-
}
|
|
1214
|
-
case "delete_list": {
|
|
1215
|
-
const args = request.params.arguments;
|
|
1216
|
-
if (!args.listId && !args.listName) {
|
|
1217
|
-
throw new Error("Either listId or listName is required");
|
|
1218
|
-
}
|
|
1219
|
-
let listId = args.listId;
|
|
1220
|
-
if (!listId && args.listName) {
|
|
1221
|
-
const result = await clickup.findListIDByName(args.listName);
|
|
1222
|
-
if (!result) {
|
|
1223
|
-
throw new Error(`List with name "${args.listName}" not found`);
|
|
1224
|
-
}
|
|
1225
|
-
listId = result.id;
|
|
1226
|
-
}
|
|
1227
|
-
// Ensure listId is defined at this point
|
|
1228
|
-
if (!listId) {
|
|
1229
|
-
throw new Error("Failed to determine list ID");
|
|
1230
|
-
}
|
|
1231
|
-
// Store the list name before deletion for the response message
|
|
1232
|
-
let listName = args.listName;
|
|
1233
|
-
if (!listName) {
|
|
1234
|
-
try {
|
|
1235
|
-
const listDetails = await clickup.getList(listId);
|
|
1236
|
-
listName = listDetails.name;
|
|
1237
|
-
}
|
|
1238
|
-
catch (error) {
|
|
1239
|
-
// If we can't get the list details, just use the ID in the response
|
|
1240
|
-
}
|
|
1241
|
-
}
|
|
1242
|
-
await clickup.deleteList(listId);
|
|
1243
|
-
return {
|
|
1244
|
-
content: [{
|
|
1245
|
-
type: "text",
|
|
1246
|
-
text: `Successfully deleted list ${listName || listId}`
|
|
1247
|
-
}]
|
|
1248
|
-
};
|
|
1249
|
-
}
|
|
1250
|
-
default:
|
|
1251
|
-
throw new Error(`Unknown tool: ${request.params.name}`);
|
|
1252
|
-
}
|
|
1253
|
-
}
|
|
1254
|
-
catch (error) {
|
|
1255
|
-
console.error('Error in tool call:', error);
|
|
1256
|
-
return {
|
|
1257
|
-
content: [{
|
|
1258
|
-
type: "text",
|
|
1259
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
1260
|
-
}]
|
|
1261
|
-
};
|
|
1262
|
-
}
|
|
1263
|
-
});
|
|
1264
|
-
/**
|
|
1265
|
-
* Add handlers for listing and getting prompts.
|
|
1266
|
-
* Prompts include summarizing tasks, analyzing priorities, and generating task descriptions.
|
|
1267
|
-
*/
|
|
1268
|
-
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
1269
|
-
return {
|
|
1270
|
-
prompts: [
|
|
1271
|
-
{
|
|
1272
|
-
name: "summarize_tasks",
|
|
1273
|
-
description: "Generate a comprehensive summary of tasks in a ClickUp list or workspace. The summary includes a high-level overview, groups tasks by status, highlights priority items, and identifies potential task relationships or dependencies. Useful for project status reports and team updates.",
|
|
1274
|
-
},
|
|
1275
|
-
{
|
|
1276
|
-
name: "analyze_priorities",
|
|
1277
|
-
description: "Evaluate task priority distribution across your workspace and identify optimization opportunities. The analysis examines current priority assignments, identifies misaligned priorities, suggests adjustments, and recommends task sequencing based on priorities. Helpful for workload management and project planning.",
|
|
1278
|
-
},
|
|
1279
|
-
{
|
|
1280
|
-
name: "generate_description",
|
|
1281
|
-
description: "Create a detailed, well-structured task description with clearly defined objectives, success criteria, required resources, dependencies, and risk assessments. This prompt helps ensure tasks are comprehensively documented with all necessary information for successful execution.",
|
|
1282
|
-
}
|
|
1283
|
-
]
|
|
1284
|
-
};
|
|
1285
|
-
});
|
|
1286
|
-
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
1287
|
-
try {
|
|
1288
|
-
switch (request.params.name) {
|
|
1289
|
-
case "summarize_tasks": {
|
|
1290
|
-
const spaces = await clickup.getSpaces(config.clickupTeamId);
|
|
1291
|
-
const tasks = [];
|
|
1292
|
-
// Gather all tasks
|
|
1293
|
-
for (const space of spaces) {
|
|
1294
|
-
const lists = await clickup.getLists(space.id);
|
|
1295
|
-
for (const list of lists) {
|
|
1296
|
-
const { tasks: listTasks } = await clickup.getTasks(list.id);
|
|
1297
|
-
tasks.push(...listTasks.map((task) => ({
|
|
1298
|
-
type: "resource",
|
|
1299
|
-
resource: {
|
|
1300
|
-
uri: `clickup://task/${task.id}`,
|
|
1301
|
-
mimeType: "application/json",
|
|
1302
|
-
text: JSON.stringify(task, null, 2)
|
|
1303
|
-
}
|
|
1304
|
-
})));
|
|
1305
|
-
}
|
|
1306
|
-
}
|
|
1307
|
-
return {
|
|
1308
|
-
messages: [
|
|
1309
|
-
{
|
|
1310
|
-
role: "user",
|
|
1311
|
-
content: {
|
|
1312
|
-
type: "text",
|
|
1313
|
-
text: "Please provide a summary of the following ClickUp tasks:"
|
|
1314
|
-
}
|
|
1315
|
-
},
|
|
1316
|
-
...tasks.map(task => ({
|
|
1317
|
-
role: "user",
|
|
1318
|
-
content: task
|
|
1319
|
-
})),
|
|
1320
|
-
{
|
|
1321
|
-
role: "user",
|
|
1322
|
-
content: {
|
|
1323
|
-
type: "text",
|
|
1324
|
-
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"
|
|
1325
|
-
}
|
|
1326
|
-
}
|
|
1327
|
-
]
|
|
1328
|
-
};
|
|
1329
|
-
}
|
|
1330
|
-
case "analyze_priorities": {
|
|
1331
|
-
const spaces = await clickup.getSpaces(config.clickupTeamId);
|
|
1332
|
-
const tasks = [];
|
|
1333
|
-
for (const space of spaces) {
|
|
1334
|
-
const lists = await clickup.getLists(space.id);
|
|
1335
|
-
for (const list of lists) {
|
|
1336
|
-
const { tasks: listTasks } = await clickup.getTasks(list.id);
|
|
1337
|
-
tasks.push(...listTasks.map((task) => ({
|
|
1338
|
-
type: "resource",
|
|
1339
|
-
resource: {
|
|
1340
|
-
uri: `clickup://task/${task.id}`,
|
|
1341
|
-
mimeType: "application/json",
|
|
1342
|
-
text: JSON.stringify(task, null, 2)
|
|
1343
|
-
}
|
|
1344
|
-
})));
|
|
1345
|
-
}
|
|
1346
|
-
}
|
|
1347
|
-
return {
|
|
1348
|
-
messages: [
|
|
1349
|
-
{
|
|
1350
|
-
role: "user",
|
|
1351
|
-
content: {
|
|
1352
|
-
type: "text",
|
|
1353
|
-
text: "Analyze the priorities of the following ClickUp tasks:"
|
|
1354
|
-
}
|
|
1355
|
-
},
|
|
1356
|
-
...tasks.map(task => ({
|
|
1357
|
-
role: "user",
|
|
1358
|
-
content: task
|
|
1359
|
-
})),
|
|
1360
|
-
{
|
|
1361
|
-
role: "user",
|
|
1362
|
-
content: {
|
|
1363
|
-
type: "text",
|
|
1364
|
-
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"
|
|
1365
|
-
}
|
|
1366
|
-
}
|
|
1367
|
-
]
|
|
1368
|
-
};
|
|
1369
|
-
}
|
|
1370
|
-
case "generate_description": {
|
|
1371
|
-
return {
|
|
1372
|
-
messages: [
|
|
1373
|
-
{
|
|
1374
|
-
role: "user",
|
|
1375
|
-
content: {
|
|
1376
|
-
type: "text",
|
|
1377
|
-
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."
|
|
1378
|
-
}
|
|
1379
|
-
}
|
|
1380
|
-
]
|
|
1381
|
-
};
|
|
1382
|
-
}
|
|
1383
|
-
default:
|
|
1384
|
-
throw new Error("Unknown prompt");
|
|
1385
|
-
}
|
|
1386
|
-
}
|
|
1387
|
-
catch (error) {
|
|
1388
|
-
console.error('Error handling prompt:', error);
|
|
1389
|
-
throw error;
|
|
1390
|
-
}
|
|
1391
|
-
});
|
|
1392
|
-
/**
|
|
1393
|
-
* Start the server using stdio transport.
|
|
1394
|
-
* This allows the server to communicate via standard input/output streams.
|
|
42
|
+
* Application entry point that configures and starts the MCP server.
|
|
1395
43
|
*/
|
|
1396
44
|
async function main() {
|
|
45
|
+
// Initialize tools with services
|
|
46
|
+
initializeWorkspaceTool(clickUpServices);
|
|
47
|
+
// Configure the server with all handlers
|
|
48
|
+
await configureServer();
|
|
49
|
+
// Connect using stdio transport
|
|
1397
50
|
const transport = new StdioServerTransport();
|
|
1398
51
|
await server.connect(transport);
|
|
1399
52
|
}
|