@taazkareem/clickup-mcp-server 0.6.4 → 0.6.5

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 CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  A Model Context Protocol (MCP) server for integrating ClickUp tasks with AI applications. This server allows AI agents to interact with ClickUp tasks, spaces, lists, and folders through a standardized protocol.
8
8
 
9
- > 🚧 **Status Update:** Rolling out v0.6.3 will add Global Task Lookup with smart disambiguation, Start Date Support for tasks with natural language expressions, Complete Tag Support including natural language tag color commands, Subtasks Support, Custom ID Support, and Logging Fixes
9
+ > 🚧 **Status Update:** Rolling out v0.6.4 will add Global Task Lookup with smart disambiguation, Start Date Support for tasks with natural language expressions, Complete Tag Support including natural language tag color commands, Subtasks Support, Custom ID Support, and Logging Fixes
10
10
 
11
11
  ## Setup
12
12
 
package/build/config.js CHANGED
@@ -43,7 +43,7 @@ export const parseLogLevel = (levelStr) => {
43
43
  case 'WARN': return LogLevel.WARN;
44
44
  case 'ERROR': return LogLevel.ERROR;
45
45
  default:
46
- console.error(`Invalid LOG_LEVEL: ${levelStr}, defaulting to ERROR`);
46
+ // Don't use console.error as it interferes with JSON-RPC communication
47
47
  return LogLevel.ERROR;
48
48
  }
49
49
  };
@@ -54,8 +54,7 @@ const configuration = {
54
54
  enableSponsorMessage: process.env.ENABLE_SPONSOR_MESSAGE !== 'false',
55
55
  logLevel: parseLogLevel(envArgs.logLevel || process.env.LOG_LEVEL)
56
56
  };
57
- // Log the configured log level (but only to console to avoid circular dependency)
58
- console.debug(`Log level set to: ${LogLevel[configuration.logLevel]}`);
57
+ // Don't log to console as it interferes with JSON-RPC communication
59
58
  // Validate only the required variables are present
60
59
  const requiredVars = ['clickupApiKey', 'clickupTeamId'];
61
60
  const missingEnvVars = requiredVars
package/build/index.js CHANGED
@@ -23,43 +23,27 @@
23
23
  */
24
24
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
25
25
  import { configureServer, server } from "./server.js";
26
- import { info, error, warn } from "./logger.js";
27
- import { exec } from 'child_process';
28
- import { promisify } from 'util';
29
- const execAsync = promisify(exec);
30
- /**
31
- * Check if another instance of the server is already running
32
- * @returns Boolean indicating if this is the only instance
33
- */
34
- async function checkSingleInstance() {
35
- try {
36
- const { stdout } = await execAsync(`ps aux | grep "node.*clickup-mcp-server" | grep -v grep | wc -l`);
37
- const instanceCount = parseInt(stdout.trim(), 10);
38
- // If there's more than one instance (including this one), warn and exit
39
- if (instanceCount > 1) {
40
- error(`Multiple server instances detected (${instanceCount}). This may cause issues.`);
41
- info("Use 'pkill -9 -f clickup-mcp-server' to kill all instances before starting a new one.");
42
- return false;
43
- }
44
- return true;
45
- }
46
- catch (err) {
47
- error("Failed to check for other running instances", err);
48
- // Continue execution even if check fails
49
- return true;
50
- }
51
- }
26
+ import { info, error } from "./logger.js";
27
+ import { dirname } from 'path';
28
+ import { fileURLToPath } from 'url';
29
+ // Get directory name for module paths
30
+ const __dirname = dirname(fileURLToPath(import.meta.url));
31
+ // Handle uncaught exceptions
32
+ process.on('uncaughtException', (err) => {
33
+ error("Uncaught Exception", { message: err.message, stack: err.stack });
34
+ process.exit(1);
35
+ });
36
+ // Handle unhandled promise rejections
37
+ process.on('unhandledRejection', (reason, promise) => {
38
+ error("Unhandled Rejection", { reason });
39
+ process.exit(1);
40
+ });
52
41
  /**
53
42
  * Application entry point that configures and starts the MCP server.
54
43
  */
55
44
  async function main() {
56
45
  try {
57
46
  info("Starting ClickUp MCP Server...");
58
- // Check if we're the only instance
59
- const isSingleInstance = await checkSingleInstance();
60
- if (!isSingleInstance) {
61
- warn("Continuing startup despite multiple instances detected");
62
- }
63
47
  // Log essential information about the environment
64
48
  info("Server environment", {
65
49
  pid: process.pid,
@@ -77,11 +61,11 @@ async function main() {
77
61
  info("Server startup complete - ready to handle requests");
78
62
  }
79
63
  catch (err) {
80
- error("Error during server startup", err);
64
+ error("Error during server startup", { message: err.message, stack: err.stack });
81
65
  process.exit(1);
82
66
  }
83
67
  }
84
68
  main().catch((err) => {
85
- error("Unhandled server error", err);
69
+ error("Unhandled server error", { message: err.message, stack: err.stack });
86
70
  process.exit(1);
87
71
  });
package/build/logger.js CHANGED
@@ -5,7 +5,7 @@
5
5
  * Logger module for MCP Server
6
6
  *
7
7
  * This module provides logging functionality for the server,
8
- * writing logs to both the console and a log file in the build folder.
8
+ * writing logs to only the log file to avoid interfering with JSON-RPC.
9
9
  */
10
10
  import { createWriteStream } from 'fs';
11
11
  import { join, dirname } from 'path';
@@ -18,7 +18,8 @@ const pid = process.pid;
18
18
  // Create a write stream for logging - use a fixed filename in the build directory
19
19
  const logFileName = 'server.log';
20
20
  const logStream = createWriteStream(join(__dirname, logFileName), { flags: 'w' });
21
- console.error(`Logging to ${join(__dirname, logFileName)}`);
21
+ // Write init message to log file only
22
+ logStream.write(`Logging initialized to ${join(__dirname, logFileName)}\n`);
22
23
  // Use the configured log level from config.ts
23
24
  const configuredLevel = config.logLevel;
24
25
  // Re-export LogLevel enum
@@ -32,7 +33,7 @@ export function isLevelEnabled(level) {
32
33
  return level >= configuredLevel;
33
34
  }
34
35
  /**
35
- * Log function that writes to both console and file
36
+ * Log function that writes only to file to avoid interfering with JSON-RPC
36
37
  * @param level Log level (trace, debug, info, warn, error)
37
38
  * @param message Message to log
38
39
  * @param data Optional data to include in log
@@ -74,9 +75,7 @@ export function log(level, message, data) {
74
75
  logMessage += '\n' + JSON.stringify(data, null, 2);
75
76
  }
76
77
  }
77
- // When using stdio transport, log to stderr which is captured by host application
78
- console.error(logMessage);
79
- // Write to file
78
+ // Write to file only, not to stderr which would interfere with JSON-RPC
80
79
  logStream.write(logMessage + '\n');
81
80
  }
82
81
  /**
package/build/server.js CHANGED
@@ -5,12 +5,12 @@
5
5
  * MCP Server for ClickUp integration
6
6
  */
7
7
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
8
- import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
8
+ import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, ListResourcesRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
9
9
  import { workspaceHierarchyTool, handleGetWorkspaceHierarchy } from "./tools/workspace.js";
10
10
  import { createTaskTool, updateTaskTool, moveTaskTool, duplicateTaskTool, getTaskTool, getTasksTool, deleteTaskTool, getTaskCommentsTool, createTaskCommentTool, createBulkTasksTool, updateBulkTasksTool, moveBulkTasksTool, deleteBulkTasksTool, attachTaskFileTool, getWorkspaceTasksTool, handleCreateTask, handleUpdateTask, handleMoveTask, handleDuplicateTask, handleGetTasks, handleDeleteTask, handleGetTaskComments, handleCreateTaskComment, handleCreateBulkTasks, handleUpdateBulkTasks, handleMoveBulkTasks, handleDeleteBulkTasks, handleGetTask, handleAttachTaskFile, handleGetWorkspaceTasks } from "./tools/task/index.js";
11
11
  import { createListTool, handleCreateList, createListInFolderTool, handleCreateListInFolder, getListTool, handleGetList, updateListTool, handleUpdateList, deleteListTool, handleDeleteList } from "./tools/list.js";
12
12
  import { createFolderTool, handleCreateFolder, getFolderTool, handleGetFolder, updateFolderTool, handleUpdateFolder, deleteFolderTool, handleDeleteFolder } from "./tools/folder.js";
13
- import { getSpaceTagsTool, handleGetSpaceTags, createSpaceTagTool, handleCreateSpaceTag, updateSpaceTagTool, handleUpdateSpaceTag, deleteSpaceTagTool, handleDeleteSpaceTag, addTagToTaskTool, handleAddTagToTask, removeTagFromTaskTool, handleRemoveTagFromTask } from "./tools/tag.js";
13
+ import { getSpaceTagsTool, handleGetSpaceTags, addTagToTaskTool, handleAddTagToTask, removeTagFromTaskTool, handleRemoveTagFromTask } from "./tools/tag.js";
14
14
  import { Logger } from "./logger.js";
15
15
  import { clickUpServices } from "./services/shared.js";
16
16
  // Create a logger instance for server
@@ -19,11 +19,12 @@ const logger = new Logger('Server');
19
19
  const { workspace } = clickUpServices;
20
20
  export const server = new Server({
21
21
  name: "clickup-mcp-server",
22
- version: "0.6.4",
22
+ version: "0.6.5",
23
23
  }, {
24
24
  capabilities: {
25
25
  tools: {},
26
26
  prompts: {},
27
+ resources: {},
27
28
  },
28
29
  });
29
30
  /**
@@ -62,17 +63,19 @@ export function configureServer() {
62
63
  updateFolderTool,
63
64
  deleteFolderTool,
64
65
  getSpaceTagsTool,
65
- createSpaceTagTool,
66
- updateSpaceTagTool,
67
- deleteSpaceTagTool,
68
66
  addTagToTaskTool,
69
67
  removeTagFromTaskTool
70
68
  ]
71
69
  };
72
70
  });
71
+ // Add handler for resources/list
72
+ server.setRequestHandler(ListResourcesRequestSchema, async (req) => {
73
+ logger.debug("Received ListResources request");
74
+ return { resources: [] };
75
+ });
73
76
  // Register CallTool handler with proper logging
74
77
  logger.info("Registering tool handlers", {
75
- toolCount: 31,
78
+ toolCount: 28,
76
79
  categories: ["workspace", "task", "list", "folder", "tag"]
77
80
  });
78
81
  server.setRequestHandler(CallToolRequestSchema, async (req) => {
@@ -136,24 +139,39 @@ export function configureServer() {
136
139
  return handleDeleteFolder(params);
137
140
  case "get_space_tags":
138
141
  return handleGetSpaceTags(params);
139
- case "create_space_tag":
140
- return handleCreateSpaceTag(params);
141
- case "update_space_tag":
142
- return handleUpdateSpaceTag(params);
143
- case "delete_space_tag":
144
- return handleDeleteSpaceTag(params);
145
142
  case "add_tag_to_task":
146
143
  return handleAddTagToTask(params);
147
144
  case "remove_tag_from_task":
148
145
  return handleRemoveTagFromTask(params);
149
146
  default:
150
147
  logger.error(`Unknown tool requested: ${name}`);
151
- throw new Error(`Unknown tool: ${name}`);
148
+ const error = new Error(`Unknown tool: ${name}`);
149
+ error.name = "UnknownToolError";
150
+ throw error;
152
151
  }
153
152
  }
154
153
  catch (err) {
155
154
  logger.error(`Error executing tool: ${name}`, err);
156
- throw err;
155
+ // Transform error to a more descriptive JSON-RPC error
156
+ if (err.name === "UnknownToolError") {
157
+ throw {
158
+ code: -32601,
159
+ message: `Method not found: ${name}`
160
+ };
161
+ }
162
+ else if (err.name === "ValidationError") {
163
+ throw {
164
+ code: -32602,
165
+ message: `Invalid params for tool ${name}: ${err.message}`
166
+ };
167
+ }
168
+ else {
169
+ // Generic server error
170
+ throw {
171
+ code: -32000,
172
+ message: `Error executing tool ${name}: ${err.message}`
173
+ };
174
+ }
157
175
  }
158
176
  });
159
177
  server.setRequestHandler(ListPromptsRequestSchema, async () => {
@@ -26,15 +26,11 @@ export const getSpaceTagsTool = {
26
26
  description: `Purpose: Get all tags available in a ClickUp space.
27
27
 
28
28
  Valid Usage:
29
- 1. Provide spaceId (preferred if available)
30
- 2. Provide spaceName (will be resolved to a space ID)
29
+ 1. Provide spaceId (preferred)
30
+ 2. Provide spaceName
31
31
 
32
32
  Requirements:
33
- - EITHER spaceId OR spaceName is REQUIRED
34
-
35
- Notes:
36
- - Tags are defined at the space level in ClickUp
37
- - You need to know the available tags before adding them to tasks`,
33
+ - Space identification: EITHER spaceId OR spaceName REQUIRED`,
38
34
  inputSchema: {
39
35
  type: "object",
40
36
  properties: {
@@ -57,18 +53,15 @@ export const createSpaceTagTool = {
57
53
  description: `Purpose: Create a new tag in a ClickUp space.
58
54
 
59
55
  Valid Usage:
60
- 1. Provide spaceId (preferred if available)
61
- 2. Provide spaceName (will be resolved to a space ID)
56
+ 1. Provide spaceId + tagName (preferred)
57
+ 2. Provide spaceName + tagName
62
58
 
63
59
  Requirements:
64
60
  - tagName: REQUIRED
65
- - EITHER spaceId OR spaceName: REQUIRED
61
+ - Space identification: EITHER spaceId OR spaceName REQUIRED
66
62
 
67
63
  Notes:
68
- - New tag will be available for all tasks in the space
69
- - You can specify background and foreground colors in HEX format (e.g., #FF0000)
70
- - You can also provide a color command (e.g., "blue tag") to automatically generate colors
71
- - After creating a tag, you can add it to tasks using add_tag_to_task`,
64
+ - Specify colors with HEX values or natural language command`,
72
65
  inputSchema: {
73
66
  type: "object",
74
67
  properties: {
@@ -33,39 +33,23 @@ export const attachTaskFileTool = {
33
33
  description: `Purpose: Attaches a file to a ClickUp task.
34
34
 
35
35
  Valid Usage:
36
- 1. Use taskId alone (preferred) - works with both regular and custom IDs
37
- 2. Use taskName alone (will search across all lists)
38
- 3. Use taskName + listName (for faster, targeted search)
36
+ 1. Use taskId (preferred) - works with both regular and custom IDs
37
+ 2. Use taskName + listName for targeted search
39
38
 
40
- File Source Options:
41
- 1. Upload from base64: Provide file_data + file_name
42
- 2. Upload from URL: Provide file_url starting with http:// or https://
43
- 3. Upload from local file: Provide file_url as absolute path (starting with / or drive letter)
44
- 4. For large files: Use chunk_* parameters for advanced chunked uploading
39
+ File Sources:
40
+ - Base64: Provide file_data + file_name
41
+ - URL: Provide file_url starting with http:// or https://
42
+ - Local file: Provide file_url as absolute path
43
+ - Chunked upload: Use chunk_* parameters for large files
45
44
 
46
45
  Requirements:
47
- - EITHER taskId OR taskName: REQUIRED
48
- - listName: Optional, but recommended when using taskName
49
- - File Source: ONE of the following is REQUIRED:
50
- - file_data + file_name
51
- - file_url (web URL or local path)
52
- - chunk_session (for continuing chunked upload)
46
+ - Task identification: EITHER taskId OR taskName REQUIRED
47
+ - File source: EITHER file_data+file_name OR file_url OR chunk_session REQUIRED
53
48
 
54
49
  Notes:
55
- - The tool automatically searches for tasks using smart name matching
56
- - When only taskName is provided, it searches across all lists
57
- - Adding listName narrows the search to a specific list for better performance
58
- - The system automatically selects the best upload method based on file size and source:
59
- - Base64 method: Limited to 10MB due to encoding overhead
60
- - URL method: Works for files hosted online
61
- - Local file method: Works with absolute paths only
62
- - Large files: Automatically uses chunked uploading
63
-
64
- Warning:
65
- - Using taskName without listName may match multiple tasks
66
- - If multiple matches are found, the operation will fail with a disambiguation error
67
- - For local files, relative paths are not supported
68
- - Base64 uploads over 10MB will automatically switch to chunked upload mode`,
50
+ - System automatically selects best upload method based on file size
51
+ - Base64 uploads limited to 10MB
52
+ - Using taskName without listName may match multiple tasks`,
69
53
  inputSchema: {
70
54
  type: "object",
71
55
  properties: {
@@ -81,13 +81,11 @@ Valid Usage:
81
81
 
82
82
  Requirements:
83
83
  - tasks: REQUIRED (array of tasks, each with at least a name)
84
- - EITHER listId OR listName: REQUIRED
85
- - All tasks will be created in the specified list
84
+ - List identification: EITHER listId OR listName REQUIRED
86
85
 
87
86
  Notes:
88
- - Configure batch size and concurrency via options for performance
89
- - Each task should have a name with emoji prefix
90
- - Custom fields can be set for each task using the custom_fields property (array of {id, value} objects)`,
87
+ - Configure batch processing via options parameter
88
+ - Custom fields supported for each task`,
91
89
  inputSchema: {
92
90
  type: "object",
93
91
  properties: {
@@ -170,22 +168,16 @@ export const updateBulkTasksTool = {
170
168
  description: `Purpose: Update multiple tasks efficiently in a single operation.
171
169
 
172
170
  Valid Usage:
173
- 1. For each task, provide taskId (preferred)
174
- 2. For each task, provide taskName + listName
171
+ 1. Provide array of tasks with taskId (preferred)
172
+ 2. Provide array of tasks with taskName + listName
175
173
 
176
174
  Requirements:
177
175
  - tasks: REQUIRED (array of tasks to update)
178
- - For each task entry, EITHER taskId OR (taskName + listName) is REQUIRED
179
- - At least one update field per task (name, description, status, priority, dueDate)
176
+ - Each task needs identification and update fields
180
177
 
181
178
  Notes:
182
179
  - Only specified fields will be updated for each task
183
- - Configure batch size and concurrency via options for performance
184
- - Each task can have different fields to update
185
- - Custom fields can be updated using the custom_fields property (array of {id, value} objects)
186
-
187
- Warning:
188
- - Using taskName without listName will fail as tasks may have identical names across lists`,
180
+ - Configure batch processing via options parameter`,
189
181
  inputSchema: {
190
182
  type: "object",
191
183
  properties: {
@@ -269,21 +261,14 @@ export const moveBulkTasksTool = {
269
261
  description: `Purpose: Move multiple tasks to a different list efficiently.
270
262
 
271
263
  Valid Usage:
272
- 1. For each task, provide taskId + target list (preferred)
273
- 2. For each task, provide taskName + listName + target list
264
+ 1. Provide tasks array + target list
274
265
 
275
266
  Requirements:
276
- - tasks: REQUIRED (array of tasks to move)
277
- - EITHER targetListId OR targetListName: REQUIRED
278
- - For each task entry, EITHER taskId OR (taskName + listName) is REQUIRED
279
-
280
- Notes:
281
- - Configure batch size and concurrency via options for performance
282
- - All tasks will be moved to the same destination list
267
+ - tasks: REQUIRED (array of task identifiers)
268
+ - Target list: EITHER targetListId OR targetListName REQUIRED
283
269
 
284
270
  Warning:
285
- - Task statuses may reset if destination list has different status options
286
- - Using taskName without listName will fail as tasks may have identical names across lists`,
271
+ - Task statuses may reset if destination list has different status options`,
287
272
  inputSchema: {
288
273
  type: "object",
289
274
  properties: {
@@ -333,20 +318,15 @@ export const deleteBulkTasksTool = {
333
318
  description: `Purpose: PERMANENTLY DELETE multiple tasks at once.
334
319
 
335
320
  Valid Usage:
336
- 1. For each task, provide taskId (preferred and safest)
337
- 2. For each task, provide taskName + listName
321
+ 1. Provide array of tasks with taskId (preferred)
322
+ 2. Provide array of tasks with taskName + listName
338
323
 
339
324
  Requirements:
340
- - tasks: REQUIRED (array of tasks to delete)
341
- - For each task entry, EITHER taskId OR (taskName + listName) is REQUIRED
342
-
343
- Notes:
344
- - Configure batch size and concurrency via options for performance
325
+ - tasks: REQUIRED (array of task identifiers)
345
326
 
346
327
  Warning:
347
- - This action CANNOT be undone for any of the tasks
348
- - Using taskName without listName is dangerous as names may not be unique
349
- - Always provide listName when using taskName for safer targeting`,
328
+ - This action CANNOT be undone
329
+ - Always provide listName when using taskName`,
350
330
  inputSchema: {
351
331
  type: "object",
352
332
  properties: {
@@ -52,17 +52,16 @@ export const createTaskTool = {
52
52
 
53
53
  Valid Usage:
54
54
  1. Provide listId (preferred if available)
55
- 2. Provide listName (system will look up the list ID)
55
+ 2. Provide listName (will look up the list ID)
56
56
 
57
57
  Requirements:
58
58
  - name: REQUIRED
59
- - EITHER listId OR listName: REQUIRED
59
+ - List identification: EITHER listId OR listName REQUIRED
60
60
 
61
61
  Notes:
62
- - For multiple tasks, use create_bulk_tasks instead
63
- - Reuse list IDs from previous responses when possible to avoid redundant lookups
64
- - To create a subtask, set the parent parameter to the ID of the parent task
65
- - Custom fields can be set using the custom_fields parameter (array of {id, value} objects)`,
62
+ - Use create_bulk_tasks for multiple tasks
63
+ - Set parent parameter to create a subtask
64
+ - Custom fields can be set via custom_fields parameter`,
66
65
  inputSchema: {
67
66
  type: "object",
68
67
  properties: {
@@ -145,25 +144,17 @@ export const updateTaskTool = {
145
144
  description: `Purpose: Modify properties of an existing task.
146
145
 
147
146
  Valid Usage:
148
- 1. Use taskId alone (preferred) - works with both regular and custom IDs
149
- 2. Use taskName alone (will search across all lists)
150
- 3. Use taskName + listName (for faster, targeted search)
147
+ 1. Use taskId (preferred) - works with both regular and custom IDs
148
+ 2. Use taskName + listName for targeted search
151
149
 
152
150
  Requirements:
153
- - At least one update field (name, description, status, priority, dueDate) must be provided
154
- - EITHER taskId OR taskName: REQUIRED
155
- - listName: Optional, but recommended when using taskName
151
+ - Task identification: EITHER taskId OR taskName REQUIRED
152
+ - Updates: At least one update field (name, description, status, priority, dueDate) REQUIRED
156
153
 
157
154
  Notes:
158
- - The tool automatically searches for tasks using smart name matching
159
- - When only taskName is provided, it searches across all lists
160
- - Adding listName narrows the search to a specific list for better performance
161
155
  - Only specified fields will be updated
162
- - Custom fields can be set using the custom_fields parameter (array of {id, value} objects)
163
-
164
- Warning:
165
- - Using taskName without listName may match multiple tasks
166
- - If multiple matches are found, the operation will fail with a disambiguation error`,
156
+ - Custom fields can be set using the custom_fields parameter
157
+ - Using taskName without listName may match multiple tasks`,
167
158
  inputSchema: {
168
159
  type: "object",
169
160
  properties: {
@@ -236,16 +227,15 @@ export const moveTaskTool = {
236
227
  description: `Purpose: Move a task to a different list.
237
228
 
238
229
  Valid Usage:
239
- 1. Use taskId + (listId OR listName) - preferred
240
- 2. Use taskName + sourceListName + (listId OR listName)
230
+ 1. Use taskId + destination list (preferred)
231
+ 2. Use taskName + sourceListName + destination list
241
232
 
242
233
  Requirements:
243
- - Destination list: EITHER listId OR listName REQUIRED
244
- - When using taskName, sourceListName is REQUIRED
234
+ - Task identification: EITHER taskId OR (taskName + sourceListName) REQUIRED
235
+ - Destination: EITHER listId OR listName REQUIRED
245
236
 
246
237
  Warning:
247
- - Task statuses may reset if destination list has different status options
248
- - System cannot find a task by name without knowing which list to search in`,
238
+ - Task statuses may reset if destination list has different status options`,
249
239
  inputSchema: {
250
240
  type: "object",
251
241
  properties: {
@@ -281,18 +271,15 @@ export const duplicateTaskTool = {
281
271
  description: `Purpose: Create a copy of a task in the same or different list.
282
272
 
283
273
  Valid Usage:
284
- 1. Use taskId + optional (listId OR listName) - preferred
285
- 2. Use taskName + sourceListName + optional (listId OR listName)
274
+ 1. Use taskId (preferred)
275
+ 2. Use taskName + sourceListName
286
276
 
287
277
  Requirements:
288
- - When using taskName, sourceListName is REQUIRED
278
+ - Task identification: EITHER taskId OR (taskName + sourceListName) REQUIRED
279
+ - Destination: OPTIONAL - defaults to original list
289
280
 
290
281
  Notes:
291
- - The duplicate preserves the original task's properties
292
- - If no destination list specified, uses same list as original task
293
-
294
- Warning:
295
- - System cannot find a task by name without knowing which list to search in`,
282
+ - The duplicate preserves the original task's properties`,
296
283
  inputSchema: {
297
284
  type: "object",
298
285
  properties: {
@@ -328,18 +315,14 @@ export const getTaskTool = {
328
315
  description: `Purpose: Retrieve detailed information about a specific task.
329
316
 
330
317
  Valid Usage:
331
- 1. Use taskId alone (preferred) - works with both regular and custom IDs (like "DEV-1234")
332
- 2. Use taskName + listName
333
- 3. Use customTaskId for explicit custom ID lookup
318
+ 1. Use taskId (preferred) - works with both regular and custom IDs
319
+ 2. Use taskName + listName for targeted search
334
320
 
335
321
  Requirements:
336
- - When using taskName, listName is REQUIRED
337
- - When using customTaskId, listName is recommended for faster lookup
322
+ - Task identification: EITHER taskId OR (taskName + listName) REQUIRED
338
323
 
339
- Note:
340
- - Task names are only unique within a list, so the system needs to know which list to search in
341
- - Regular task IDs are always 9 characters long (e.g., "86b394eqa")
342
- - Custom IDs have an uppercase prefix followed by a hyphen and number (e.g., "DEV-1234")
324
+ Notes:
325
+ - Task names are only unique within a list
343
326
  - Set subtasks=true to include all subtasks in the response`,
344
327
  inputSchema: {
345
328
  type: "object",
@@ -379,12 +362,11 @@ Valid Usage:
379
362
  2. Use listName
380
363
 
381
364
  Requirements:
382
- - EITHER listId OR listName is REQUIRED
365
+ - List identification: EITHER listId OR listName REQUIRED
383
366
 
384
367
  Notes:
385
- - Use filters (archived, statuses, etc.) to narrow down results
386
- - Pagination available through page parameter
387
- - Sorting available through order_by and reverse parameters`,
368
+ - Use filters (archived, statuses) to narrow down results
369
+ - Pagination and sorting available`,
388
370
  inputSchema: {
389
371
  type: "object",
390
372
  properties: {
@@ -434,12 +416,14 @@ export const getTaskCommentsTool = {
434
416
 
435
417
  Valid Usage:
436
418
  1. Use taskId (preferred)
437
- 2. Use taskName + optional listName
419
+ 2. Use taskName + listName for targeted search
420
+
421
+ Requirements:
422
+ - Task identification: EITHER taskId OR taskName REQUIRED
438
423
 
439
424
  Notes:
440
- - If using taskName, providing listName helps locate the correct task
441
425
  - Task names may not be unique across different lists
442
- - Use start and startId parameters for pagination through comments`,
426
+ - Use start/startId parameters for pagination`,
443
427
  inputSchema: {
444
428
  type: "object",
445
429
  properties: {
@@ -478,13 +462,11 @@ Valid Usage:
478
462
  2. Use taskName + listName
479
463
 
480
464
  Requirements:
481
- - EITHER taskId OR (taskName + listName) is REQUIRED
482
- - commentText is REQUIRED
465
+ - Task identification: EITHER taskId OR (taskName + listName) REQUIRED
466
+ - commentText: REQUIRED
483
467
 
484
468
  Notes:
485
- - When using taskName, providing listName helps locate the correct task
486
- - Set notifyAll to true to send notifications to all task assignees
487
- - Use assignee to assign the comment to a specific user (optional)`,
469
+ - Set notifyAll=true to notify all task assignees`,
488
470
  inputSchema: {
489
471
  type: "object",
490
472
  properties: {
@@ -524,24 +506,15 @@ export const deleteTaskTool = {
524
506
  description: `Purpose: PERMANENTLY DELETE a task.
525
507
 
526
508
  Valid Usage:
527
- 1. Use taskId alone (preferred and safest)
528
- 2. Use taskName alone (will search across all lists)
529
- 3. Use taskName + listName (for faster, targeted search)
509
+ 1. Use taskId (preferred and safest)
510
+ 2. Use taskName + listName for targeted search
530
511
 
531
512
  Requirements:
532
- - EITHER taskId OR taskName: REQUIRED
533
- - listName: Optional, but recommended when using taskName
534
-
535
- Notes:
536
- - The tool automatically searches for tasks using smart name matching
537
- - When only taskName is provided, it searches across all lists
538
- - Adding listName narrows the search to a specific list for better performance
539
- - Supports both regular task IDs and custom IDs (like 'DEV-1234')
513
+ - Task identification: EITHER taskId OR taskName REQUIRED
540
514
 
541
515
  Warning:
542
516
  - This action CANNOT be undone
543
- - Using taskName without listName may match multiple tasks
544
- - If multiple matches are found, the operation will fail with a disambiguation error`,
517
+ - Using taskName without listName may match multiple tasks`,
545
518
  inputSchema: {
546
519
  type: "object",
547
520
  properties: {
@@ -12,27 +12,20 @@
12
12
  */
13
13
  export const getWorkspaceTasksTool = {
14
14
  name: "get_workspace_tasks",
15
- description: `Purpose: Retrieve tasks from across the entire workspace with powerful filtering options, including tag-based filtering.
15
+ description: `Purpose: Retrieve tasks from across the entire workspace with filtering.
16
16
 
17
17
  Valid Usage:
18
- 1. Apply any combination of filters (tags, lists, folders, spaces, statuses, etc.)
19
- 2. Use pagination to manage large result sets
18
+ 1. Apply any combination of filters (tags, lists, statuses, etc.)
19
+ 2. Use pagination for large result sets
20
20
 
21
21
  Requirements:
22
- - At least one filter parameter is REQUIRED (tags, list_ids, folder_ids, space_ids, statuses, assignees, or date filters)
23
- - Pagination parameters (page, order_by, reverse) alone are not considered filters
22
+ - At least one filter parameter REQUIRED (tags, list_ids, statuses, etc.)
24
23
 
25
24
  Notes:
26
- - Provides workspace-wide task access (unlike get_tasks which only searches in one list)
27
- - Returns complete task details including descriptions, assignees, custom fields, and all metadata
28
- - Tag filtering is especially useful for cross-list organization (e.g., "project-x", "blocker", "needs-review")
29
- - Combine multiple filters to narrow down your search scope
30
- - Use pagination for large result sets
31
- - Use the detail_level parameter to control the amount of data returned:
32
- - "summary": Returns lightweight task data (name, status, list, tags)
33
- - "detailed": Returns complete task data with all fields (DEFAULT if not specified)
34
- - Responses exceeding 50,000 tokens automatically switch to summary format to avoid hitting LLM token limits
35
- `,
25
+ - Searches across all lists in the workspace
26
+ - Tag filtering allows cross-list organization
27
+ - Set detail_level=summary for lightweight responses
28
+ - detail_level=detailed (default) returns complete data`,
36
29
  parameters: {
37
30
  type: 'object',
38
31
  properties: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taazkareem/clickup-mcp-server",
3
- "version": "0.6.4",
3
+ "version": "0.6.5",
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",