@taazkareem/clickup-mcp-server 0.6.5 → 0.6.7

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.
@@ -16,19 +16,7 @@ const { folder: folderService, workspace: workspaceService } = clickUpServices;
16
16
  */
17
17
  export const createFolderTool = {
18
18
  name: "create_folder",
19
- description: `Purpose: Create a new folder in a ClickUp space for organizing related lists.
20
-
21
- Valid Usage:
22
- 1. Provide spaceId (preferred) + folder name
23
- 2. Provide spaceName + folder name
24
-
25
- Requirements:
26
- - name: REQUIRED
27
- - EITHER spaceId OR spaceName: REQUIRED
28
-
29
- Notes:
30
- - After creating a folder, you can add lists to it using create_list_in_folder
31
- - Use override_statuses to set folder-specific statuses`,
19
+ description: `Creates folder in ClickUp space. Use spaceId (preferred) or spaceName + folder name. Optional: override_statuses for folder-specific statuses. Use create_list_in_folder to add lists after creation.`,
32
20
  inputSchema: {
33
21
  type: "object",
34
22
  properties: {
@@ -53,22 +41,11 @@ Notes:
53
41
  }
54
42
  };
55
43
  /**
56
- * Tool definition for getting folder details
44
+ * Tool definition for retrieving folder details
57
45
  */
58
46
  export const getFolderTool = {
59
47
  name: "get_folder",
60
- description: `Purpose: Retrieve details about a specific folder including name, status, and metadata.
61
-
62
- Valid Usage:
63
- 1. Use folderId alone (preferred)
64
- 2. Use folderName + (spaceId or spaceName)
65
-
66
- Requirements:
67
- - EITHER folderId OR (folderName + space information) is REQUIRED
68
- - When using folderName, you MUST provide EITHER spaceId OR spaceName
69
-
70
- Notes:
71
- - Helps you understand folder structure before creating or updating lists`,
48
+ description: `Gets folder details. Use folderId (preferred) or folderName + (spaceId/spaceName). Helps understand folder structure before creating/updating lists.`,
72
49
  inputSchema: {
73
50
  type: "object",
74
51
  properties: {
@@ -97,19 +74,7 @@ Notes:
97
74
  */
98
75
  export const updateFolderTool = {
99
76
  name: "update_folder",
100
- description: `Purpose: Modify an existing folder's properties.
101
-
102
- Valid Usage:
103
- 1. Use folderId alone (preferred)
104
- 2. Use folderName + (spaceId or spaceName)
105
-
106
- Requirements:
107
- - At least one update field (name or override_statuses) must be provided
108
- - EITHER folderId OR (folderName + space information) is REQUIRED
109
- - When using folderName, you MUST provide EITHER spaceId OR spaceName
110
-
111
- Notes:
112
- - Changes apply immediately to all lists within the folder`,
77
+ description: `Updates folder properties. Use folderId (preferred) or folderName + (spaceId/spaceName). At least one update field (name/override_statuses) required. Changes apply to all lists in folder.`,
113
78
  inputSchema: {
114
79
  type: "object",
115
80
  properties: {
@@ -146,20 +111,7 @@ Notes:
146
111
  */
147
112
  export const deleteFolderTool = {
148
113
  name: "delete_folder",
149
- description: `Purpose: PERMANENTLY DELETE a folder and all its contents.
150
-
151
- Valid Usage:
152
- 1. Use folderId alone (preferred and safest)
153
- 2. Use folderName + (spaceId or spaceName)
154
-
155
- Requirements:
156
- - EITHER folderId OR (folderName + space information) is REQUIRED
157
- - When using folderName, you MUST provide EITHER spaceId OR spaceName
158
-
159
- Warning:
160
- - This action CANNOT be undone
161
- - All lists and tasks within the folder will also be permanently deleted
162
- - Using folderName is risky as names may not be unique across different spaces`,
114
+ description: `PERMANENTLY deletes folder and all contents. Use folderId (preferred/safest) or folderName + (spaceId/spaceName). WARNING: Cannot be undone, all lists/tasks deleted, folderName risky if not unique.`,
163
115
  inputSchema: {
164
116
  type: "object",
165
117
  properties: {
@@ -16,19 +16,7 @@ import { sponsorService } from '../utils/sponsor-service.js';
16
16
  */
17
17
  export const createListTool = {
18
18
  name: "create_list",
19
- description: `Purpose: Create a new list directly in a ClickUp space (not in a folder).
20
-
21
- Valid Usage:
22
- 1. Provide spaceId + list name (preferred)
23
- 2. Provide spaceName + list name
24
-
25
- Requirements:
26
- - name: REQUIRED
27
- - EITHER spaceId OR spaceName: REQUIRED
28
-
29
- Notes:
30
- - For creating lists inside folders, use create_list_in_folder instead
31
- - Optional fields include content, dueDate, priority, assignee, and status`,
19
+ description: `Creates a list in a ClickUp space. Use spaceId (preferred) or spaceName + list name. Name is required. For lists in folders, use create_list_in_folder. Optional: content, dueDate, priority, assignee, status.`,
32
20
  inputSchema: {
33
21
  type: "object",
34
22
  properties: {
@@ -73,21 +61,7 @@ Notes:
73
61
  */
74
62
  export const createListInFolderTool = {
75
63
  name: "create_list_in_folder",
76
- description: `Purpose: Create a new list within a ClickUp folder.
77
-
78
- Valid Usage:
79
- 1. Provide folderId + list name (preferred)
80
- 2. Provide folderName + (spaceId OR spaceName) + list name
81
-
82
- Requirements:
83
- - name: REQUIRED
84
- - EITHER folderId OR (folderName + space information): REQUIRED
85
- - When using folderName, EITHER spaceId OR spaceName is REQUIRED
86
-
87
- Notes:
88
- - Folder names may not be unique across spaces, which is why space information
89
- is required when using folderName
90
- - Optional fields include content and status`,
64
+ description: `Creates a list in a ClickUp folder. Use folderId (preferred) or folderName + space info + list name. Name is required. When using folderName, spaceId/spaceName required as folder names may not be unique. Optional: content, status.`,
91
65
  inputSchema: {
92
66
  type: "object",
93
67
  properties: {
@@ -128,18 +102,7 @@ Notes:
128
102
  */
129
103
  export const getListTool = {
130
104
  name: "get_list",
131
- description: `Purpose: Retrieve details about a specific ClickUp list.
132
-
133
- Valid Usage:
134
- 1. Provide listId (preferred)
135
- 2. Provide listName
136
-
137
- Requirements:
138
- - EITHER listId OR listName: REQUIRED
139
-
140
- Notes:
141
- - Using listId is more reliable as list names might not be unique
142
- - Returns list details including name, content, and space information`,
105
+ description: `Gets details of a ClickUp list. Use listId (preferred) or listName. Returns list details including name, content, and space info. ListId more reliable as names may not be unique.`,
143
106
  inputSchema: {
144
107
  type: "object",
145
108
  properties: {
@@ -160,19 +123,7 @@ Notes:
160
123
  */
161
124
  export const updateListTool = {
162
125
  name: "update_list",
163
- description: `Purpose: Update an existing ClickUp list's properties.
164
-
165
- Valid Usage:
166
- 1. Provide listId + update fields (preferred)
167
- 2. Provide listName + update fields
168
-
169
- Requirements:
170
- - EITHER listId OR listName: REQUIRED
171
- - At least one field to update (name, content, or status): REQUIRED
172
-
173
- Notes:
174
- - Using listId is more reliable as list names might not be unique
175
- - Only specified fields will be updated`,
126
+ description: `Updates a ClickUp list. Use listId (preferred) or listName + at least one update field (name/content/status). ListId more reliable as names may not be unique. Only specified fields updated.`,
176
127
  inputSchema: {
177
128
  type: "object",
178
129
  properties: {
@@ -205,19 +156,7 @@ Notes:
205
156
  */
206
157
  export const deleteListTool = {
207
158
  name: "delete_list",
208
- description: `Purpose: Permanently delete a ClickUp list and all its tasks.
209
-
210
- Valid Usage:
211
- 1. Provide listId (preferred and safest)
212
- 2. Provide listName
213
-
214
- Requirements:
215
- - EITHER listId OR listName: REQUIRED
216
-
217
- Warning:
218
- - This action CANNOT be undone
219
- - All tasks within the list will also be permanently deleted
220
- - Using listName is risky as names may not be unique`,
159
+ description: `PERMANENTLY deletes a ClickUp list and all its tasks. Use listId (preferred/safest) or listName. WARNING: Cannot be undone, all tasks will be deleted, listName risky if not unique.`,
221
160
  inputSchema: {
222
161
  type: "object",
223
162
  properties: {
@@ -13,24 +13,20 @@ import { clickUpServices } from '../services/shared.js';
13
13
  import { Logger } from '../logger.js';
14
14
  import { sponsorService } from '../utils/sponsor-service.js';
15
15
  import { processColorCommand } from '../utils/color-processor.js';
16
+ import { validateTaskIdentification } from './task/utilities.js';
16
17
  // Create a logger specific to tag tools
17
18
  const logger = new Logger('TagTools');
19
+ // Use shared services instance
20
+ const { task: taskService } = clickUpServices;
18
21
  //=============================================================================
19
22
  // TOOL DEFINITIONS
20
23
  //=============================================================================
21
24
  /**
22
- * Tool definition for getting tags in a space
25
+ * Tool definition for getting space tags
23
26
  */
24
27
  export const getSpaceTagsTool = {
25
28
  name: "get_space_tags",
26
- description: `Purpose: Get all tags available in a ClickUp space.
27
-
28
- Valid Usage:
29
- 1. Provide spaceId (preferred)
30
- 2. Provide spaceName
31
-
32
- Requirements:
33
- - Space identification: EITHER spaceId OR spaceName REQUIRED`,
29
+ description: `Gets all tags in a ClickUp space. Use spaceId (preferred) or spaceName. Tags are defined at space level - check available tags before adding to tasks.`,
34
30
  inputSchema: {
35
31
  type: "object",
36
32
  properties: {
@@ -53,15 +49,18 @@ export const createSpaceTagTool = {
53
49
  description: `Purpose: Create a new tag in a ClickUp space.
54
50
 
55
51
  Valid Usage:
56
- 1. Provide spaceId + tagName (preferred)
57
- 2. Provide spaceName + tagName
52
+ 1. Provide spaceId (preferred if available)
53
+ 2. Provide spaceName (will be resolved to a space ID)
58
54
 
59
55
  Requirements:
60
56
  - tagName: REQUIRED
61
- - Space identification: EITHER spaceId OR spaceName REQUIRED
57
+ - EITHER spaceId OR spaceName: REQUIRED
62
58
 
63
59
  Notes:
64
- - Specify colors with HEX values or natural language command`,
60
+ - New tag will be available for all tasks in the space
61
+ - You can specify background and foreground colors in HEX format (e.g., #FF0000)
62
+ - You can also provide a color command (e.g., "blue tag") to automatically generate colors
63
+ - After creating a tag, you can add it to tasks using add_tag_to_task`,
65
64
  inputSchema: {
66
65
  type: "object",
67
66
  properties: {
@@ -190,25 +189,7 @@ Warning:
190
189
  */
191
190
  export const addTagToTaskTool = {
192
191
  name: "add_tag_to_task",
193
- description: `Purpose: Add an existing tag to a ClickUp task.
194
-
195
- Valid Usage:
196
- 1. Provide taskId (preferred if available)
197
- 2. Provide taskName + listName
198
-
199
- Requirements:
200
- - tagName: REQUIRED
201
- - EITHER taskId OR (taskName + listName): REQUIRED
202
- - The tag MUST exist in the space containing the task before calling this tool
203
-
204
- Warning:
205
- - The operation will fail if the tag does not exist in the space
206
- - Always use get_space_tags first to verify the tag exists
207
- - If the tag doesn't exist, create it using create_space_tag before adding it to the task
208
-
209
- Notes:
210
- - Use get_space_tags to see available tags
211
- - Use create_space_tag to create a new tag if needed`,
192
+ description: `Adds existing tag to task. Use taskId (preferred) or taskName + optional listName. Tag must exist in space (use get_space_tags to verify, create_space_tag if needed). WARNING: Will fail if tag doesn't exist.`,
212
193
  inputSchema: {
213
194
  type: "object",
214
195
  properties: {
@@ -222,11 +203,11 @@ Notes:
222
203
  },
223
204
  taskName: {
224
205
  type: "string",
225
- description: "Name of the task to add tag to. When using this parameter, you MUST also provide listName."
206
+ description: "Name of the task to add tag to. Will search across all lists unless listName is provided."
226
207
  },
227
208
  listName: {
228
209
  type: "string",
229
- description: "Name of the list containing the task. REQUIRED when using taskName."
210
+ description: "Optional: Name of the list containing the task. Use to disambiguate when multiple tasks have the same name."
230
211
  },
231
212
  tagName: {
232
213
  type: "string",
@@ -241,19 +222,7 @@ Notes:
241
222
  */
242
223
  export const removeTagFromTaskTool = {
243
224
  name: "remove_tag_from_task",
244
- description: `Purpose: Remove a tag from a ClickUp task.
245
-
246
- Valid Usage:
247
- 1. Provide taskId (preferred if available)
248
- 2. Provide taskName + listName
249
-
250
- Requirements:
251
- - tagName: REQUIRED
252
- - EITHER taskId OR (taskName + listName): REQUIRED
253
-
254
- Notes:
255
- - This only removes the association between the tag and task
256
- - The tag will still exist in the space`,
225
+ description: `Removes tag from task. Use taskId (preferred) or taskName + optional listName. Only removes tag-task association, tag remains in space. For multiple tasks, provide listName to disambiguate.`,
257
226
  inputSchema: {
258
227
  type: "object",
259
228
  properties: {
@@ -267,11 +236,11 @@ Notes:
267
236
  },
268
237
  taskName: {
269
238
  type: "string",
270
- description: "Name of the task to remove tag from. When using this parameter, you MUST also provide listName."
239
+ description: "Name of the task to remove tag from. Will search across all lists unless listName is provided."
271
240
  },
272
241
  listName: {
273
242
  type: "string",
274
- description: "Name of the list containing the task. REQUIRED when using taskName."
243
+ description: "Optional: Name of the list containing the task. Use to disambiguate when multiple tasks have the same name."
275
244
  },
276
245
  tagName: {
277
246
  type: "string",
@@ -334,10 +303,18 @@ export const handleDeleteSpaceTag = createHandlerWrapper(deleteSpaceTag, () => (
334
303
  /**
335
304
  * Wrapper for addTagToTask handler
336
305
  */
337
- export const handleAddTagToTask = createHandlerWrapper(addTagToTask, () => ({
338
- success: true,
339
- message: "Tag added to task successfully"
340
- }));
306
+ export const handleAddTagToTask = createHandlerWrapper(addTagToTask, (result) => {
307
+ if (!result.success) {
308
+ return {
309
+ success: false,
310
+ error: result.error
311
+ };
312
+ }
313
+ return {
314
+ success: true,
315
+ message: "Tag added to task successfully"
316
+ };
317
+ });
341
318
  /**
342
319
  * Wrapper for removeTagFromTask handler
343
320
  */
@@ -666,28 +643,42 @@ export async function deleteSpaceTag(params) {
666
643
  */
667
644
  async function resolveTaskId(params) {
668
645
  const { taskId, customTaskId, taskName, listName } = params;
669
- // If we have a direct taskId, use it
670
- if (taskId) {
671
- return { success: true, taskId };
672
- }
673
- // Custom task ID handling
674
- if (customTaskId) {
675
- return { success: true, taskId: customTaskId };
646
+ try {
647
+ // First validate task identification with global lookup enabled
648
+ const validationResult = validateTaskIdentification({ taskId, customTaskId, taskName, listName }, { useGlobalLookup: true });
649
+ if (!validationResult.isValid) {
650
+ return {
651
+ success: false,
652
+ error: { message: validationResult.errorMessage }
653
+ };
654
+ }
655
+ const result = await taskService.findTasks({
656
+ taskId,
657
+ customTaskId,
658
+ taskName,
659
+ listName,
660
+ allowMultipleMatches: false,
661
+ useSmartDisambiguation: true,
662
+ includeFullDetails: false
663
+ });
664
+ if (!result || Array.isArray(result)) {
665
+ return {
666
+ success: false,
667
+ error: { message: 'Task not found with the provided identification' }
668
+ };
669
+ }
670
+ return { success: true, taskId: result.id };
676
671
  }
677
- // Task name lookup (requires list name)
678
- if (taskName && listName) {
679
- // Implementation would go here
672
+ catch (error) {
680
673
  return {
681
674
  success: false,
682
- error: { message: 'Task name resolution not implemented yet' }
675
+ error: {
676
+ message: error.message || 'Failed to resolve task ID',
677
+ code: error.code,
678
+ details: error.data
679
+ }
683
680
  };
684
681
  }
685
- return {
686
- success: false,
687
- error: {
688
- message: 'Task identifier is required (taskId, customTaskId, or taskName+listName)'
689
- }
690
- };
691
682
  }
692
683
  /**
693
684
  * Add a tag to a task
@@ -705,12 +696,12 @@ export async function addTagToTask(params) {
705
696
  }
706
697
  };
707
698
  }
708
- if (!taskId && !customTaskId && !(taskName && listName)) {
709
- logger.error('addTagToTask called without proper task identifier');
699
+ if (!taskId && !customTaskId && !taskName) {
700
+ logger.error('addTagToTask called without task identifier');
710
701
  return {
711
702
  success: false,
712
703
  error: {
713
- message: 'Either taskId, customTaskId, or both taskName and listName are required'
704
+ message: 'Either taskId, customTaskId, or taskName is required'
714
705
  }
715
706
  };
716
707
  }
@@ -728,6 +719,31 @@ export async function addTagToTask(params) {
728
719
  const result = await clickUpServices.tag.addTagToTask(taskIdResult.taskId, tagName);
729
720
  if (!result.success) {
730
721
  logger.error('Failed to add tag to task', result.error);
722
+ // Provide more specific error messages based on error code
723
+ if (result.error?.code === 'TAG_NOT_FOUND') {
724
+ return {
725
+ success: false,
726
+ error: {
727
+ message: `The tag "${tagName}" does not exist in the space. Please create it first using create_space_tag.`
728
+ }
729
+ };
730
+ }
731
+ else if (result.error?.code === 'SPACE_NOT_FOUND') {
732
+ return {
733
+ success: false,
734
+ error: {
735
+ message: 'Could not determine which space the task belongs to.'
736
+ }
737
+ };
738
+ }
739
+ else if (result.error?.code === 'TAG_VERIFICATION_FAILED') {
740
+ return {
741
+ success: false,
742
+ error: {
743
+ message: 'The tag addition could not be verified. Please check if the tag was added manually.'
744
+ }
745
+ };
746
+ }
731
747
  return {
732
748
  success: false,
733
749
  error: result.error || {
@@ -768,12 +784,12 @@ export async function removeTagFromTask(params) {
768
784
  }
769
785
  };
770
786
  }
771
- if (!taskId && !customTaskId && !(taskName && listName)) {
772
- logger.error('removeTagFromTask called without proper task identifier');
787
+ if (!taskId && !customTaskId && !taskName) {
788
+ logger.error('removeTagFromTask called without task identifier');
773
789
  return {
774
790
  success: false,
775
791
  error: {
776
- message: 'Either taskId, customTaskId, or both taskName and listName are required'
792
+ message: 'Either taskId, customTaskId, or taskName is required'
777
793
  }
778
794
  };
779
795
  }
@@ -10,8 +10,11 @@
10
10
  import { clickUpServices } from '../../services/shared.js';
11
11
  import { validateTaskIdentification } from './utilities.js';
12
12
  import { sponsorService } from '../../utils/sponsor-service.js';
13
+ import { Logger } from '../../logger.js';
13
14
  // Use shared services instance
14
15
  const { task: taskService } = clickUpServices;
16
+ // Create a logger instance for attachments
17
+ const logger = new Logger('TaskAttachments');
15
18
  // Session storage for chunked uploads (in-memory for demonstration)
16
19
  const chunkSessions = new Map();
17
20
  // Clean up expired sessions periodically
@@ -21,7 +24,7 @@ setInterval(() => {
21
24
  for (const [token, session] of chunkSessions.entries()) {
22
25
  if (now - session.timestamp > expired) {
23
26
  chunkSessions.delete(token);
24
- console.log(`Cleaned up expired upload session: ${token}`);
27
+ logger.debug(`Cleaned up expired upload session: ${token}`);
25
28
  }
26
29
  }
27
30
  }, 3600 * 1000); // Check every hour
@@ -30,26 +33,7 @@ setInterval(() => {
30
33
  */
31
34
  export const attachTaskFileTool = {
32
35
  name: "attach_task_file",
33
- description: `Purpose: Attaches a file to a ClickUp task.
34
-
35
- Valid Usage:
36
- 1. Use taskId (preferred) - works with both regular and custom IDs
37
- 2. Use taskName + listName for targeted search
38
-
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
44
-
45
- Requirements:
46
- - Task identification: EITHER taskId OR taskName REQUIRED
47
- - File source: EITHER file_data+file_name OR file_url OR chunk_session REQUIRED
48
-
49
- Notes:
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`,
36
+ description: `Attaches file to task. Use taskId (preferred) or taskName + optional listName. File sources: 1) base64 + filename (≤10MB), 2) URL (http/https), 3) local path (absolute), 4) chunked for large files. WARNING: taskName without listName may match multiple tasks.`,
53
37
  inputSchema: {
54
38
  type: "object",
55
39
  properties: {
@@ -106,9 +90,12 @@ Notes:
106
90
  */
107
91
  async function attachTaskFileHandler(params) {
108
92
  // Extract common parameters
109
- const { taskId, taskName, listName, file_name, file_data, file_url, auth_header, chunk_total, chunk_size, chunk_index, session_id } = params;
93
+ const { taskId, taskName, listName, customTaskId, file_name, file_data, file_url, auth_header, chunk_total, chunk_size, chunk_index, session_id } = params;
110
94
  // Validate task identification
111
- validateTaskIdentification(params);
95
+ const validationResult = validateTaskIdentification({ taskId, taskName, listName, customTaskId }, { useGlobalLookup: true });
96
+ if (!validationResult.isValid) {
97
+ throw new Error(validationResult.errorMessage);
98
+ }
112
99
  // Validate file source - either file_data or file_url must be provided
113
100
  if (!file_data && !file_url && !session_id) {
114
101
  throw new Error("Either file_data, file_url, or session_id must be provided");
@@ -134,13 +121,13 @@ async function attachTaskFileHandler(params) {
134
121
  // CASE 2: URL-based upload or local file path
135
122
  if (file_url) {
136
123
  // Check if it's a local file path
137
- console.log(`Checking if path is local: ${file_url}`);
124
+ logger.debug(`Checking if path is local: ${file_url}`);
138
125
  if (file_url.startsWith('/') || /^[A-Za-z]:\\/.test(file_url)) {
139
- console.log(`Detected as local path, proceeding to handle: ${file_url}`);
126
+ logger.debug(`Detected as local path, proceeding to handle: ${file_url}`);
140
127
  return await handleLocalFileUpload(resolvedTaskId, file_url, file_name);
141
128
  }
142
129
  else if (file_url.startsWith('http://') || file_url.startsWith('https://')) {
143
- console.log(`Detected as URL, proceeding with URL upload: ${file_url}`);
130
+ logger.debug(`Detected as URL, proceeding with URL upload: ${file_url}`);
144
131
  return await handleUrlUpload(resolvedTaskId, file_url, file_name, auth_header);
145
132
  }
146
133
  else {
@@ -167,7 +154,7 @@ async function attachTaskFileHandler(params) {
167
154
  throw new Error("Invalid parameters: Unable to determine upload method");
168
155
  }
169
156
  catch (error) {
170
- console.error(`Error attaching file to task:`, error);
157
+ logger.error(`Error attaching file to task:`, error);
171
158
  throw error;
172
159
  }
173
160
  }
@@ -315,7 +302,7 @@ async function handleLocalFileUpload(taskId, filePath, fileName) {
315
302
  // Import fs and path modules
316
303
  const fs = await import('fs');
317
304
  const path = await import('path');
318
- console.log(`Processing absolute file path: ${filePath}`);
305
+ logger.debug(`Processing absolute file path: ${filePath}`);
319
306
  // Normalize the path to prevent directory traversal attacks
320
307
  const normalizedPath = path.normalize(filePath);
321
308
  // Check if file exists
@@ -332,7 +319,7 @@ async function handleLocalFileUpload(taskId, filePath, fileName) {
332
319
  // Read file
333
320
  const fileBuffer = fs.readFileSync(normalizedPath);
334
321
  const fileSize = fileBuffer.length;
335
- console.log(`Successfully read file: ${extractedFileName} (${fileSize} bytes)`);
322
+ logger.debug(`Successfully read file: ${extractedFileName} (${fileSize} bytes)`);
336
323
  // Choose upload method based on file size
337
324
  if (fileSize > 10 * 1024 * 1024) {
338
325
  // For large files, start chunked upload process
@@ -73,19 +73,7 @@ const taskIdentifierSchema = {
73
73
  */
74
74
  export const createBulkTasksTool = {
75
75
  name: "create_bulk_tasks",
76
- description: `Purpose: Create multiple tasks in a list efficiently.
77
-
78
- Valid Usage:
79
- 1. Provide listId + array of tasks (preferred)
80
- 2. Provide listName + array of tasks
81
-
82
- Requirements:
83
- - tasks: REQUIRED (array of tasks, each with at least a name)
84
- - List identification: EITHER listId OR listName REQUIRED
85
-
86
- Notes:
87
- - Configure batch processing via options parameter
88
- - Custom fields supported for each task`,
76
+ description: `Creates multiple tasks in one list. Use listId (preferred) or listName + array of tasks (each needs name). Configure batch size/concurrency via options. Tasks can have custom fields as {id, value} array.`,
89
77
  inputSchema: {
90
78
  type: "object",
91
79
  properties: {
@@ -161,23 +149,11 @@ Notes:
161
149
  }
162
150
  };
163
151
  /**
164
- * Tool definition for updating multiple tasks efficiently
152
+ * Tool definition for updating multiple tasks
165
153
  */
166
154
  export const updateBulkTasksTool = {
167
155
  name: "update_bulk_tasks",
168
- description: `Purpose: Update multiple tasks efficiently in a single operation.
169
-
170
- Valid Usage:
171
- 1. Provide array of tasks with taskId (preferred)
172
- 2. Provide array of tasks with taskName + listName
173
-
174
- Requirements:
175
- - tasks: REQUIRED (array of tasks to update)
176
- - Each task needs identification and update fields
177
-
178
- Notes:
179
- - Only specified fields will be updated for each task
180
- - Configure batch processing via options parameter`,
156
+ description: `Updates multiple tasks efficiently. For each task: use taskId (preferred) or taskName + listName. At least one update field per task. Configure batch size/concurrency via options. WARNING: taskName without listName will fail.`,
181
157
  inputSchema: {
182
158
  type: "object",
183
159
  properties: {
@@ -254,21 +230,11 @@ Notes:
254
230
  }
255
231
  };
256
232
  /**
257
- * Tool definition for moving multiple tasks at once
233
+ * Tool definition for moving multiple tasks
258
234
  */
259
235
  export const moveBulkTasksTool = {
260
236
  name: "move_bulk_tasks",
261
- description: `Purpose: Move multiple tasks to a different list efficiently.
262
-
263
- Valid Usage:
264
- 1. Provide tasks array + target list
265
-
266
- Requirements:
267
- - tasks: REQUIRED (array of task identifiers)
268
- - Target list: EITHER targetListId OR targetListName REQUIRED
269
-
270
- Warning:
271
- - Task statuses may reset if destination list has different status options`,
237
+ description: `Moves multiple tasks to one list. For each task: use taskId (preferred) or taskName + listName. Target list: use targetListId/Name. Configure batch size/concurrency via options. WARNING: Task statuses may reset, taskName needs listName.`,
272
238
  inputSchema: {
273
239
  type: "object",
274
240
  properties: {
@@ -311,22 +277,11 @@ Warning:
311
277
  }
312
278
  };
313
279
  /**
314
- * Tool definition for deleting multiple tasks at once
280
+ * Tool definition for deleting multiple tasks
315
281
  */
316
282
  export const deleteBulkTasksTool = {
317
283
  name: "delete_bulk_tasks",
318
- description: `Purpose: PERMANENTLY DELETE multiple tasks at once.
319
-
320
- Valid Usage:
321
- 1. Provide array of tasks with taskId (preferred)
322
- 2. Provide array of tasks with taskName + listName
323
-
324
- Requirements:
325
- - tasks: REQUIRED (array of task identifiers)
326
-
327
- Warning:
328
- - This action CANNOT be undone
329
- - Always provide listName when using taskName`,
284
+ description: `PERMANENTLY deletes multiple tasks. For each task: use taskId (preferred/safest) or taskName + listName. Configure batch size/concurrency via options. WARNING: Cannot be undone, taskName without listName is dangerous.`,
330
285
  inputSchema: {
331
286
  type: "object",
332
287
  properties: {