@taazkareem/clickup-mcp-server 0.4.24 → 0.4.26

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.
Files changed (2) hide show
  1. package/build/index.js +154 -467
  2. package/package.json +1 -1
package/build/index.js CHANGED
@@ -7,15 +7,14 @@
7
7
  *
8
8
  * @module clickup-mcp-server
9
9
  */
10
- import { Server } from "@modelcontextprotocol/sdk/server/index.js";
10
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
11
11
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
12
- import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
13
12
  import { ClickUpService } from "./services/clickup.js";
14
13
  import config from "./config.js";
15
- import { handleWorkspaceHierarchy, handleCreateTask, handleCreateBulkTasks, handleCreateList, handleCreateFolder, handleCreateListInFolder, handleMoveTask, handleDuplicateTask, handleUpdateTask } from "./handlers/tools.js";
14
+ import { handleWorkspaceHierarchy, handleCreateTask, handleCreateBulkTasks, handleCreateList, handleCreateFolder, handleCreateListInFolder } from "./handlers/tools.js";
16
15
  import { handleSummarizeTasks, handleAnalyzeTaskPriorities } from "./handlers/prompts.js";
17
- import { getAllTasks } from "./utils/resolvers.js";
18
16
  import { logError, logInfo, logDebug } from "./utils/logger.js";
17
+ import { z } from 'zod';
19
18
  // Set up global error handlers
20
19
  process.on('uncaughtException', (error) => {
21
20
  logError('server.uncaught', error);
@@ -30,10 +29,7 @@ logInfo('config', {
30
29
  clickupApiKey: config.clickupApiKey ? '***' : 'missing',
31
30
  teamId: config.teamId || 'missing'
32
31
  });
33
- /**
34
- * Initialize ClickUp service singleton
35
- * This must be done before any other ClickUp operations
36
- */
32
+ // Initialize ClickUp service singleton
37
33
  let clickup;
38
34
  try {
39
35
  logDebug('clickup', { status: 'initializing' });
@@ -44,470 +40,164 @@ catch (error) {
44
40
  logError('clickup.initialization', error);
45
41
  process.exit(1);
46
42
  }
47
- /**
48
- * Create and configure the MCP server instance
49
- * Sets up capabilities, tools, and error handling
50
- */
43
+ // Create and configure the MCP server instance
51
44
  logDebug('mcp', { status: 'creating' });
52
- // Define server capabilities
53
- const serverCapabilities = {
54
- tools: {
55
- workspace_hierarchy: {
56
- description: "List complete hierarchy of the ClickUp workspace",
57
- inputSchema: {
58
- type: "object",
59
- properties: {},
60
- required: []
61
- }
62
- },
63
- create_task: {
64
- description: "Create a new task in ClickUp",
65
- inputSchema: {
66
- type: "object",
67
- properties: {
68
- listId: {
69
- type: "string",
70
- description: "ID of the list to create the task in (optional if listName is provided)"
71
- },
72
- listName: {
73
- type: "string",
74
- description: "Name of the list to create the task in (optional if listId is provided)"
75
- },
76
- name: {
77
- type: "string",
78
- description: "Name of the task"
79
- },
80
- description: {
81
- type: "string",
82
- description: "Description of the task"
83
- },
84
- status: {
85
- type: "string",
86
- description: "Status of the task"
87
- },
88
- priority: {
89
- type: "number",
90
- description: "Priority of the task (1-4)"
91
- },
92
- dueDate: {
93
- type: "string",
94
- description: "Due date of the task (ISO string)"
95
- }
96
- },
97
- required: ["name"]
98
- }
99
- },
100
- create_bulk_tasks: {
101
- description: "Create multiple tasks simultaneously in a list",
102
- inputSchema: {
103
- type: "object",
104
- properties: {
105
- listId: {
106
- type: "string",
107
- description: "ID of the list to create tasks in (optional if listName is provided)"
108
- },
109
- listName: {
110
- type: "string",
111
- description: "Name of the list to create tasks in (optional if listId is provided)"
112
- },
113
- tasks: {
114
- type: "array",
115
- description: "Array of tasks to create",
116
- items: {
117
- type: "object",
118
- properties: {
119
- name: {
120
- type: "string",
121
- description: "Name of the task"
122
- },
123
- description: {
124
- type: "string",
125
- description: "Description of the task"
126
- },
127
- status: {
128
- type: "string",
129
- description: "Status of the task"
130
- },
131
- priority: {
132
- type: "number",
133
- description: "Priority of the task (1-4)"
134
- },
135
- dueDate: {
136
- type: "string",
137
- description: "Due date of the task (ISO string)"
138
- }
139
- },
140
- required: ["name"]
141
- }
142
- }
143
- },
144
- required: ["tasks"]
145
- }
146
- },
147
- create_list: {
148
- description: "Create a new list in a space",
149
- inputSchema: {
150
- type: "object",
151
- properties: {
152
- spaceId: {
153
- type: "string",
154
- description: "ID of the space (optional if spaceName is provided)"
155
- },
156
- spaceName: {
157
- type: "string",
158
- description: "Name of the space (optional if spaceId is provided)"
159
- },
160
- name: {
161
- type: "string",
162
- description: "Name of the list"
163
- },
164
- content: {
165
- type: "string",
166
- description: "List description"
167
- }
168
- },
169
- required: ["name"]
170
- }
171
- },
172
- create_folder: {
173
- description: "Create a new folder in a space",
174
- inputSchema: {
175
- type: "object",
176
- properties: {
177
- spaceId: {
178
- type: "string",
179
- description: "ID of the space (optional if spaceName is provided)"
180
- },
181
- spaceName: {
182
- type: "string",
183
- description: "Name of the space (optional if spaceId is provided)"
184
- },
185
- name: {
186
- type: "string",
187
- description: "Name of the folder"
188
- },
189
- override_statuses: {
190
- type: "boolean",
191
- description: "Whether to override space statuses"
192
- }
193
- },
194
- required: ["name"]
195
- }
196
- },
197
- create_list_in_folder: {
198
- description: "Create a new list within a folder",
199
- inputSchema: {
200
- type: "object",
201
- properties: {
202
- folderId: {
203
- type: "string",
204
- description: "ID of the folder (optional if using folderName)"
205
- },
206
- folderName: {
207
- type: "string",
208
- description: "Name of the folder"
209
- },
210
- spaceId: {
211
- type: "string",
212
- description: "ID of the space (required if using folderName)"
213
- },
214
- spaceName: {
215
- type: "string",
216
- description: "Name of the space (alternative to spaceId)"
217
- },
218
- name: {
219
- type: "string",
220
- description: "Name of the list"
221
- },
222
- content: {
223
- type: "string",
224
- description: "List description"
225
- }
226
- },
227
- required: ["name"]
228
- }
229
- },
230
- move_task: {
231
- description: "Move a task to a different list",
232
- inputSchema: {
233
- type: "object",
234
- properties: {
235
- taskId: {
236
- type: "string",
237
- description: "ID of the task to move"
238
- },
239
- listId: {
240
- type: "string",
241
- description: "ID of destination list (optional if listName is provided)"
242
- },
243
- listName: {
244
- type: "string",
245
- description: "Name of destination list (optional if listId is provided)"
246
- }
247
- },
248
- required: ["taskId"]
249
- }
250
- },
251
- duplicate_task: {
252
- description: "Create a copy of a task in a specified list",
253
- inputSchema: {
254
- type: "object",
255
- properties: {
256
- taskId: {
257
- type: "string",
258
- description: "ID of the task to duplicate"
259
- },
260
- listId: {
261
- type: "string",
262
- description: "ID of destination list (optional if listName is provided)"
263
- },
264
- listName: {
265
- type: "string",
266
- description: "Name of destination list (optional if listId is provided)"
267
- }
268
- },
269
- required: ["taskId"]
270
- }
271
- },
272
- update_task: {
273
- description: "Update an existing task",
274
- inputSchema: {
275
- type: "object",
276
- properties: {
277
- taskId: {
278
- type: "string",
279
- description: "ID of the task to update"
280
- },
281
- name: {
282
- type: "string",
283
- description: "New task name"
284
- },
285
- description: {
286
- type: "string",
287
- description: "New description"
288
- },
289
- status: {
290
- type: "string",
291
- description: "New status"
292
- },
293
- priority: {
294
- type: "number",
295
- description: "New priority level (1-4)"
296
- },
297
- dueDate: {
298
- type: "string",
299
- description: "New due date (ISO string)"
300
- }
301
- },
302
- required: ["taskId"]
303
- }
304
- }
305
- },
306
- prompts: {
307
- summarize_tasks: {
308
- description: "Summarize all ClickUp tasks"
309
- },
310
- analyze_task_priorities: {
311
- description: "Analyze task priorities"
312
- }
313
- },
314
- resources: {
315
- list: true,
316
- read: true
317
- }
318
- };
319
- // Create server instance with capabilities
320
- const server = new Server({
45
+ const mcpServer = new McpServer({
321
46
  name: "clickup-mcp-server",
322
- version: "0.4.23",
323
- capabilities: {
324
- tools: serverCapabilities.tools,
325
- prompts: serverCapabilities.prompts,
326
- resources: {
327
- list: true,
328
- read: true
329
- }
330
- },
331
- errorHandler: (error) => {
332
- logError('mcp', error);
333
- }
47
+ version: "0.4.25"
334
48
  });
335
- // Server startup logic
336
- if (process.argv.includes('--stdio')) {
337
- logInfo('server', { status: 'stdio.starting' });
338
- // Register handlers BEFORE connection
339
- try {
340
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
341
- try {
342
- logDebug('tool.request', { name: request.params.name });
343
- switch (request.params.name) {
344
- case "workspace_hierarchy": {
345
- return await handleWorkspaceHierarchy(clickup, config.teamId);
346
- }
347
- case "create_task": {
348
- const args = request.params.arguments;
349
- return await handleCreateTask(clickup, config.teamId, args);
350
- }
351
- case "create_bulk_tasks": {
352
- const args = request.params.arguments;
353
- return await handleCreateBulkTasks(clickup, config.teamId, args);
354
- }
355
- case "create_list": {
356
- const args = request.params.arguments;
357
- return await handleCreateList(clickup, config.teamId, args);
358
- }
359
- case "create_folder": {
360
- const args = request.params.arguments;
361
- return await handleCreateFolder(clickup, config.teamId, args);
362
- }
363
- case "create_list_in_folder": {
364
- const args = request.params.arguments;
365
- return await handleCreateListInFolder(clickup, config.teamId, args);
366
- }
367
- case "move_task": {
368
- const args = request.params.arguments;
369
- return await handleMoveTask(clickup, config.teamId, args);
370
- }
371
- case "duplicate_task": {
372
- const args = request.params.arguments;
373
- return await handleDuplicateTask(clickup, config.teamId, args);
374
- }
375
- case "update_task": {
376
- const args = request.params.arguments;
377
- return await handleUpdateTask(clickup, config.teamId, args);
378
- }
379
- default:
380
- throw new Error(`Unknown tool: ${request.params.name}`);
49
+ // Tool schemas as raw shapes
50
+ const workspaceHierarchySchema = {
51
+ teamId: z.string().optional()
52
+ };
53
+ const taskSchema = {
54
+ name: z.string(),
55
+ description: z.string().optional(),
56
+ status: z.string().optional(),
57
+ priority: z.number().optional(),
58
+ dueDate: z.string().optional(),
59
+ listId: z.string().optional(),
60
+ listName: z.string().optional()
61
+ };
62
+ const bulkTasksSchema = {
63
+ tasks: z.array(z.object(taskSchema)),
64
+ listId: z.string().optional(),
65
+ listName: z.string().optional()
66
+ };
67
+ const listSchema = {
68
+ name: z.string(),
69
+ spaceId: z.string().optional(),
70
+ spaceName: z.string().optional(),
71
+ content: z.string().optional()
72
+ };
73
+ const folderSchema = {
74
+ name: z.string(),
75
+ spaceId: z.string().optional(),
76
+ spaceName: z.string().optional(),
77
+ override_statuses: z.boolean().optional()
78
+ };
79
+ const listInFolderSchema = {
80
+ name: z.string(),
81
+ folderId: z.string().optional(),
82
+ folderName: z.string().optional(),
83
+ spaceId: z.string().optional(),
84
+ spaceName: z.string().optional(),
85
+ content: z.string().optional()
86
+ };
87
+ // Register tools with proper schemas
88
+ mcpServer.tool('workspace_hierarchy', 'List complete hierarchy of the ClickUp workspace', workspaceHierarchySchema, async (args) => {
89
+ const result = await handleWorkspaceHierarchy(clickup, config.teamId);
90
+ return {
91
+ content: [{
92
+ type: "text",
93
+ text: JSON.stringify(result, null, 2)
94
+ }]
95
+ };
96
+ });
97
+ mcpServer.tool('create_task', 'Create a new task in ClickUp', taskSchema, async (args) => {
98
+ const result = await handleCreateTask(clickup, config.teamId, args);
99
+ return {
100
+ content: [{
101
+ type: "text",
102
+ text: JSON.stringify(result, null, 2)
103
+ }]
104
+ };
105
+ });
106
+ mcpServer.tool('create_bulk_tasks', 'Create multiple tasks simultaneously in a list', bulkTasksSchema, async (args) => {
107
+ const result = await handleCreateBulkTasks(clickup, config.teamId, args);
108
+ return {
109
+ content: [{
110
+ type: "text",
111
+ text: JSON.stringify(result, null, 2)
112
+ }]
113
+ };
114
+ });
115
+ mcpServer.tool('create_list', 'Create a new list in a space', listSchema, async (args) => {
116
+ const result = await handleCreateList(clickup, config.teamId, args);
117
+ return {
118
+ content: [{
119
+ type: "text",
120
+ text: JSON.stringify(result, null, 2)
121
+ }]
122
+ };
123
+ });
124
+ mcpServer.tool('create_folder', 'Create a new folder in a space', folderSchema, async (args) => {
125
+ const result = await handleCreateFolder(clickup, config.teamId, args);
126
+ return {
127
+ content: [{
128
+ type: "text",
129
+ text: JSON.stringify(result, null, 2)
130
+ }]
131
+ };
132
+ });
133
+ mcpServer.tool('create_list_in_folder', 'Create a new list within a folder', listInFolderSchema, async (args) => {
134
+ const result = await handleCreateListInFolder(clickup, config.teamId, args);
135
+ return {
136
+ content: [{
137
+ type: "text",
138
+ text: JSON.stringify(result, null, 2)
139
+ }]
140
+ };
141
+ });
142
+ // Register prompts with descriptions
143
+ mcpServer.prompt('summarize_tasks', 'Provide a comprehensive summary of tasks', async () => {
144
+ const summary = await handleSummarizeTasks(clickup, config.teamId);
145
+ return {
146
+ messages: [{
147
+ role: 'assistant',
148
+ content: {
149
+ type: 'text',
150
+ text: summary
381
151
  }
382
- }
383
- catch (error) {
384
- logError(`tool.${request.params.name}`, error);
385
- throw error;
386
- }
387
- });
388
- server.setRequestHandler(ListResourcesRequestSchema, async () => {
389
- logDebug('resources', { action: 'listing' });
390
- try {
391
- const { tasks, spaces } = await getAllTasks(clickup, config.teamId);
392
- return {
393
- resources: tasks.map(task => ({
394
- uri: `clickup://task/${task.id}`,
395
- mimeType: "application/json",
396
- name: task.name,
397
- description: task.description || `Task in ${task.list.name} (${task.space.name})`,
398
- tags: []
399
- }))
400
- };
401
- }
402
- catch (error) {
403
- logError('resources.list', error);
404
- throw error;
405
- }
406
- });
407
- server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
408
- try {
409
- const url = new URL(request.params.uri);
410
- const taskId = url.pathname.replace(/^\/task\//, '');
411
- logDebug('resources.read', { taskId });
412
- const task = await clickup.getTask(taskId);
413
- return {
414
- contents: [{
415
- uri: request.params.uri,
416
- mimeType: "application/json",
417
- text: JSON.stringify(task, null, 2),
418
- tags: []
419
- }]
420
- };
421
- }
422
- catch (error) {
423
- logError('resources.read', error);
424
- throw error;
425
- }
426
- });
427
- server.setRequestHandler(ListToolsRequestSchema, async () => {
428
- logDebug('tools', { action: 'listing' });
429
- const toolCapabilities = server.capabilities?.tools || {};
430
- const tools = Object.entries(toolCapabilities).map(([name, tool]) => ({
431
- name,
432
- description: tool.description,
433
- inputSchema: tool.inputSchema
434
- }));
435
- logDebug('tools', { count: tools.length });
436
- return { tools };
437
- });
438
- server.setRequestHandler(ListPromptsRequestSchema, async () => {
439
- return {
440
- prompts: [
441
- {
442
- name: "summarize_tasks",
443
- description: "Summarize all ClickUp tasks"
444
- },
445
- {
446
- name: "analyze_task_priorities",
447
- description: "Analyze task priorities"
448
- }
449
- ]
450
- };
451
- });
452
- server.setRequestHandler(GetPromptRequestSchema, async (request) => {
453
- try {
454
- switch (request.params.name) {
455
- case "summarize_tasks": {
456
- const output = await handleSummarizeTasks(clickup, config.teamId);
457
- return {
458
- content: [{
459
- type: "text",
460
- text: output
461
- }]
462
- };
463
- }
464
- case "analyze_task_priorities": {
465
- const output = await handleAnalyzeTaskPriorities(clickup, config.teamId);
466
- return {
467
- content: [{
468
- type: "text",
469
- text: output
470
- }]
471
- };
472
- }
473
- default:
474
- throw new Error("Prompt not found");
152
+ }],
153
+ description: 'Task Summary'
154
+ };
155
+ });
156
+ mcpServer.prompt('analyze_task_priorities', 'Analyze task priorities and provide recommendations', async () => {
157
+ const analysis = await handleAnalyzeTaskPriorities(clickup, config.teamId);
158
+ return {
159
+ messages: [{
160
+ role: 'assistant',
161
+ content: {
162
+ type: 'text',
163
+ text: analysis
475
164
  }
476
- }
477
- catch (error) {
478
- logError('prompt', error);
479
- throw error;
480
- }
481
- });
482
- logInfo('server', { status: 'handlers.registered' });
483
- }
484
- catch (error) {
485
- logError('server.handlers', error);
486
- process.exit(1);
165
+ }],
166
+ description: 'Priority Analysis'
167
+ };
168
+ });
169
+ // TODO: Implement resource handler properly after consulting MCP SDK documentation
170
+ // Resource handler temporarily disabled due to type issues
171
+ /*
172
+ mcpServer.resource(
173
+ 'clickup',
174
+ 'clickup://task/{id}',
175
+ async (uri: URL) => {
176
+ try {
177
+ const taskId = uri.pathname.split('/').pop() || '';
178
+ const task = await clickup.getTask(taskId);
179
+ return {
180
+ uri: uri.toString(),
181
+ mimeType: "application/json",
182
+ text: JSON.stringify(task, null, 2),
183
+ tags: []
184
+ };
185
+ } catch (error) {
186
+ logError('resources.read', error);
187
+ throw error;
487
188
  }
488
- // Set up stdio transport and connect first
189
+ }
190
+ );
191
+ */
192
+ // Server startup logic
193
+ if (process.argv.includes('--stdio')) {
194
+ logInfo('server', { status: 'stdio.starting' });
195
+ // Create stdio transport
489
196
  const transport = new StdioServerTransport();
490
197
  // Connect server with better error handling
491
- server.connect(transport)
492
- .then(async () => {
198
+ mcpServer.server.connect(transport)
199
+ .then(() => {
493
200
  logInfo('server', { status: 'connected' });
494
- // Send initial handshake message with more details
495
- const capabilities = {
496
- tools: server.capabilities?.tools || {},
497
- prompts: server.capabilities?.prompts || {},
498
- resources: {
499
- list: true,
500
- read: true
501
- }
502
- };
503
- logInfo('mcp', { status: 'handshake.preparing' });
504
- logInfo('mcp', {
505
- status: 'handshake',
506
- name: "clickup-mcp-server",
507
- version: "0.4.19",
508
- hasTools: Object.keys(capabilities.tools).length > 0,
509
- hasPrompts: Object.keys(capabilities.prompts).length > 0
510
- });
511
201
  logInfo('server', { status: 'ready' });
512
202
  // Keep the process alive
513
203
  process.stdin.resume();
@@ -528,10 +218,7 @@ if (process.argv.includes('--stdio')) {
528
218
  process.exit(1);
529
219
  });
530
220
  }
531
- else {
532
- logInfo('server', { status: 'standard.starting' });
533
- // Add your non-stdio server initialization here if needed
534
- }
221
+ // Note: Non-stdio initialization removed as it was unused
535
222
  // Prevent unhandled promise rejections from crashing the server
536
223
  process.on('unhandledRejection', (error) => {
537
224
  logError('server.unhandled', error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taazkareem/clickup-mcp-server",
3
- "version": "0.4.24",
3
+ "version": "0.4.26",
4
4
  "description": "ClickUp MCP Server - Integrate ClickUp tasks with AI through Model Context Protocol",
5
5
  "type": "module",
6
6
  "main": "./build/index.js",