@taazkareem/clickup-mcp-server 0.4.25 → 0.4.27

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 +157 -476
  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,481 +40,169 @@ 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.24",
47
+ version: "0.4.25",
323
48
  capabilities: {
324
- tools: {
325
- enabled: true,
326
- call: true,
327
- list: true,
328
- schemas: serverCapabilities.tools
329
- },
330
- prompts: {
331
- enabled: true,
332
- list: true,
333
- get: true,
334
- schemas: serverCapabilities.prompts
335
- },
336
- resources: {
337
- enabled: true,
338
- list: true,
339
- read: true
340
- }
341
- },
342
- errorHandler: (error) => {
343
- logError('mcp', error);
49
+ tools: true,
50
+ prompts: true,
51
+ resources: true
344
52
  }
345
53
  });
346
- // Server startup logic
347
- if (process.argv.includes('--stdio')) {
348
- logInfo('server', { status: 'stdio.starting' });
349
- // Register handlers BEFORE connection
350
- try {
351
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
352
- try {
353
- logDebug('tool.request', { name: request.params.name });
354
- switch (request.params.name) {
355
- case "workspace_hierarchy": {
356
- return await handleWorkspaceHierarchy(clickup, config.teamId);
357
- }
358
- case "create_task": {
359
- const args = request.params.arguments;
360
- return await handleCreateTask(clickup, config.teamId, args);
361
- }
362
- case "create_bulk_tasks": {
363
- const args = request.params.arguments;
364
- return await handleCreateBulkTasks(clickup, config.teamId, args);
365
- }
366
- case "create_list": {
367
- const args = request.params.arguments;
368
- return await handleCreateList(clickup, config.teamId, args);
369
- }
370
- case "create_folder": {
371
- const args = request.params.arguments;
372
- return await handleCreateFolder(clickup, config.teamId, args);
373
- }
374
- case "create_list_in_folder": {
375
- const args = request.params.arguments;
376
- return await handleCreateListInFolder(clickup, config.teamId, args);
377
- }
378
- case "move_task": {
379
- const args = request.params.arguments;
380
- return await handleMoveTask(clickup, config.teamId, args);
381
- }
382
- case "duplicate_task": {
383
- const args = request.params.arguments;
384
- return await handleDuplicateTask(clickup, config.teamId, args);
385
- }
386
- case "update_task": {
387
- const args = request.params.arguments;
388
- return await handleUpdateTask(clickup, config.teamId, args);
389
- }
390
- default:
391
- throw new Error(`Unknown tool: ${request.params.name}`);
54
+ // Tool schemas as raw shapes
55
+ const workspaceHierarchySchema = {
56
+ teamId: z.string().optional()
57
+ };
58
+ const taskSchema = {
59
+ name: z.string(),
60
+ description: z.string().optional(),
61
+ status: z.string().optional(),
62
+ priority: z.number().optional(),
63
+ dueDate: z.string().optional(),
64
+ listId: z.string().optional(),
65
+ listName: z.string().optional()
66
+ };
67
+ const bulkTasksSchema = {
68
+ tasks: z.array(z.object(taskSchema)),
69
+ listId: z.string().optional(),
70
+ listName: z.string().optional()
71
+ };
72
+ const listSchema = {
73
+ name: z.string(),
74
+ spaceId: z.string().optional(),
75
+ spaceName: z.string().optional(),
76
+ content: z.string().optional()
77
+ };
78
+ const folderSchema = {
79
+ name: z.string(),
80
+ spaceId: z.string().optional(),
81
+ spaceName: z.string().optional(),
82
+ override_statuses: z.boolean().optional()
83
+ };
84
+ const listInFolderSchema = {
85
+ name: z.string(),
86
+ folderId: z.string().optional(),
87
+ folderName: z.string().optional(),
88
+ spaceId: z.string().optional(),
89
+ spaceName: z.string().optional(),
90
+ content: z.string().optional()
91
+ };
92
+ // Register tools with proper schemas
93
+ mcpServer.tool('workspace_hierarchy', 'List complete hierarchy of the ClickUp workspace', workspaceHierarchySchema, async (args) => {
94
+ const result = await handleWorkspaceHierarchy(clickup, config.teamId);
95
+ return {
96
+ content: [{
97
+ type: "text",
98
+ text: JSON.stringify(result, null, 2)
99
+ }]
100
+ };
101
+ });
102
+ mcpServer.tool('create_task', 'Create a new task in ClickUp', taskSchema, async (args) => {
103
+ const result = await handleCreateTask(clickup, config.teamId, args);
104
+ return {
105
+ content: [{
106
+ type: "text",
107
+ text: JSON.stringify(result, null, 2)
108
+ }]
109
+ };
110
+ });
111
+ mcpServer.tool('create_bulk_tasks', 'Create multiple tasks simultaneously in a list', bulkTasksSchema, async (args) => {
112
+ const result = await handleCreateBulkTasks(clickup, config.teamId, args);
113
+ return {
114
+ content: [{
115
+ type: "text",
116
+ text: JSON.stringify(result, null, 2)
117
+ }]
118
+ };
119
+ });
120
+ mcpServer.tool('create_list', 'Create a new list in a space', listSchema, async (args) => {
121
+ const result = await handleCreateList(clickup, config.teamId, args);
122
+ return {
123
+ content: [{
124
+ type: "text",
125
+ text: JSON.stringify(result, null, 2)
126
+ }]
127
+ };
128
+ });
129
+ mcpServer.tool('create_folder', 'Create a new folder in a space', folderSchema, async (args) => {
130
+ const result = await handleCreateFolder(clickup, config.teamId, args);
131
+ return {
132
+ content: [{
133
+ type: "text",
134
+ text: JSON.stringify(result, null, 2)
135
+ }]
136
+ };
137
+ });
138
+ mcpServer.tool('create_list_in_folder', 'Create a new list within a folder', listInFolderSchema, async (args) => {
139
+ const result = await handleCreateListInFolder(clickup, config.teamId, args);
140
+ return {
141
+ content: [{
142
+ type: "text",
143
+ text: JSON.stringify(result, null, 2)
144
+ }]
145
+ };
146
+ });
147
+ // Register prompts with descriptions
148
+ mcpServer.prompt('summarize_tasks', 'Provide a comprehensive summary of tasks', async () => {
149
+ const summary = await handleSummarizeTasks(clickup, config.teamId);
150
+ return {
151
+ messages: [{
152
+ role: 'assistant',
153
+ content: {
154
+ type: 'text',
155
+ text: summary
392
156
  }
393
- }
394
- catch (error) {
395
- logError(`tool.${request.params.name}`, error);
396
- throw error;
397
- }
398
- });
399
- server.setRequestHandler(ListResourcesRequestSchema, async () => {
400
- logDebug('resources', { action: 'listing' });
401
- try {
402
- const { tasks, spaces } = await getAllTasks(clickup, config.teamId);
403
- return {
404
- resources: tasks.map(task => ({
405
- uri: `clickup://task/${task.id}`,
406
- mimeType: "application/json",
407
- name: task.name,
408
- description: task.description || `Task in ${task.list.name} (${task.space.name})`,
409
- tags: []
410
- }))
411
- };
412
- }
413
- catch (error) {
414
- logError('resources.list', error);
415
- throw error;
416
- }
417
- });
418
- server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
419
- try {
420
- const url = new URL(request.params.uri);
421
- const taskId = url.pathname.replace(/^\/task\//, '');
422
- logDebug('resources.read', { taskId });
423
- const task = await clickup.getTask(taskId);
424
- return {
425
- contents: [{
426
- uri: request.params.uri,
427
- mimeType: "application/json",
428
- text: JSON.stringify(task, null, 2),
429
- tags: []
430
- }]
431
- };
432
- }
433
- catch (error) {
434
- logError('resources.read', error);
435
- throw error;
436
- }
437
- });
438
- server.setRequestHandler(ListToolsRequestSchema, async () => {
439
- logDebug('tools', { action: 'listing' });
440
- const toolCapabilities = server.capabilities?.tools || {};
441
- const tools = Object.entries(toolCapabilities).map(([name, tool]) => ({
442
- name,
443
- description: tool.description,
444
- inputSchema: tool.inputSchema
445
- }));
446
- logDebug('tools', { count: tools.length });
447
- return { tools };
448
- });
449
- server.setRequestHandler(ListPromptsRequestSchema, async () => {
450
- return {
451
- prompts: [
452
- {
453
- name: "summarize_tasks",
454
- description: "Summarize all ClickUp tasks"
455
- },
456
- {
457
- name: "analyze_task_priorities",
458
- description: "Analyze task priorities"
459
- }
460
- ]
461
- };
462
- });
463
- server.setRequestHandler(GetPromptRequestSchema, async (request) => {
464
- try {
465
- switch (request.params.name) {
466
- case "summarize_tasks": {
467
- const output = await handleSummarizeTasks(clickup, config.teamId);
468
- return {
469
- content: [{
470
- type: "text",
471
- text: output
472
- }]
473
- };
474
- }
475
- case "analyze_task_priorities": {
476
- const output = await handleAnalyzeTaskPriorities(clickup, config.teamId);
477
- return {
478
- content: [{
479
- type: "text",
480
- text: output
481
- }]
482
- };
483
- }
484
- default:
485
- throw new Error("Prompt not found");
157
+ }],
158
+ description: 'Task Summary'
159
+ };
160
+ });
161
+ mcpServer.prompt('analyze_task_priorities', 'Analyze task priorities and provide recommendations', async () => {
162
+ const analysis = await handleAnalyzeTaskPriorities(clickup, config.teamId);
163
+ return {
164
+ messages: [{
165
+ role: 'assistant',
166
+ content: {
167
+ type: 'text',
168
+ text: analysis
486
169
  }
487
- }
488
- catch (error) {
489
- logError('prompt', error);
490
- throw error;
491
- }
492
- });
493
- logInfo('server', { status: 'handlers.registered' });
494
- }
495
- catch (error) {
496
- logError('server.handlers', error);
497
- process.exit(1);
170
+ }],
171
+ description: 'Priority Analysis'
172
+ };
173
+ });
174
+ // TODO: Implement resource handler properly after consulting MCP SDK documentation
175
+ // Resource handler temporarily disabled due to type issues
176
+ /*
177
+ mcpServer.resource(
178
+ 'clickup',
179
+ 'clickup://task/{id}',
180
+ async (uri: URL) => {
181
+ try {
182
+ const taskId = uri.pathname.split('/').pop() || '';
183
+ const task = await clickup.getTask(taskId);
184
+ return {
185
+ uri: uri.toString(),
186
+ mimeType: "application/json",
187
+ text: JSON.stringify(task, null, 2),
188
+ tags: []
189
+ };
190
+ } catch (error) {
191
+ logError('resources.read', error);
192
+ throw error;
498
193
  }
499
- // Set up stdio transport and connect first
194
+ }
195
+ );
196
+ */
197
+ // Server startup logic
198
+ if (process.argv.includes('--stdio')) {
199
+ logInfo('server', { status: 'stdio.starting' });
200
+ // Create stdio transport
500
201
  const transport = new StdioServerTransport();
501
202
  // Connect server with better error handling
502
- server.connect(transport)
503
- .then(async () => {
203
+ mcpServer.server.connect(transport)
204
+ .then(() => {
504
205
  logInfo('server', { status: 'connected' });
505
- // Send initial handshake message with more details
506
- const capabilities = {
507
- tools: server.capabilities?.tools || {},
508
- prompts: server.capabilities?.prompts || {},
509
- resources: {
510
- list: true,
511
- read: true
512
- }
513
- };
514
- logInfo('mcp', { status: 'handshake.preparing' });
515
- logInfo('mcp', {
516
- status: 'handshake',
517
- name: "clickup-mcp-server",
518
- version: "0.4.19",
519
- hasTools: Object.keys(capabilities.tools).length > 0,
520
- hasPrompts: Object.keys(capabilities.prompts).length > 0
521
- });
522
206
  logInfo('server', { status: 'ready' });
523
207
  // Keep the process alive
524
208
  process.stdin.resume();
@@ -539,10 +223,7 @@ if (process.argv.includes('--stdio')) {
539
223
  process.exit(1);
540
224
  });
541
225
  }
542
- else {
543
- logInfo('server', { status: 'standard.starting' });
544
- // Add your non-stdio server initialization here if needed
545
- }
226
+ // Note: Non-stdio initialization removed as it was unused
546
227
  // Prevent unhandled promise rejections from crashing the server
547
228
  process.on('unhandledRejection', (error) => {
548
229
  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.25",
3
+ "version": "0.4.27",
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",