@taazkareem/clickup-mcp-server 0.6.9 → 0.6.10

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.
@@ -0,0 +1,501 @@
1
+ /**
2
+ * SPDX-FileCopyrightText: © 2025 João Santana <joaosantana@gmail.com>
3
+ * SPDX-License-Identifier: MIT
4
+ *
5
+ * ClickUp MCP Document Tools
6
+ *
7
+ * This module defines document-related tools including creating,
8
+ * retrieving, updating, and deleting documents.
9
+ */
10
+ import { workspaceService } from '../services/shared.js';
11
+ import config from '../config.js';
12
+ import { sponsorService } from '../utils/sponsor-service.js';
13
+ import { Logger } from "../logger.js";
14
+ import { clickUpServices } from "../services/shared.js";
15
+ const logger = new Logger('DocumentTools');
16
+ const { document: documentService } = clickUpServices;
17
+ /**
18
+ * Tool definition for creating a document
19
+ */
20
+ export const createDocumentTool = {
21
+ name: "create_document",
22
+ description: `Creates a document in a ClickUp space, folder, or list. Requires name, parent info, visibility and create_page flag.`,
23
+ inputSchema: {
24
+ type: "object",
25
+ properties: {
26
+ name: {
27
+ type: "string",
28
+ description: "Name and Title of the document"
29
+ },
30
+ parent: {
31
+ type: "object",
32
+ properties: {
33
+ id: {
34
+ type: "string",
35
+ description: "ID of the parent container (space, folder, or list)"
36
+ },
37
+ type: {
38
+ type: "number",
39
+ enum: [4, 5, 6, 7, 12],
40
+ description: "Type of the parent container (4=space, 5=folder, 6=list, 7=everything, 12=workspace)"
41
+ }
42
+ },
43
+ required: ["id", "type"],
44
+ description: "Parent container information"
45
+ },
46
+ visibility: {
47
+ type: "string",
48
+ enum: ["PUBLIC", "PRIVATE"],
49
+ description: "Document visibility setting"
50
+ },
51
+ create_page: {
52
+ type: "boolean",
53
+ description: "Whether to create an initial blank page"
54
+ }
55
+ },
56
+ required: ["name", "parent", "visibility", "create_page"]
57
+ }
58
+ };
59
+ /**
60
+ * Tool definition for getting a document
61
+ */
62
+ export const getDocumentTool = {
63
+ name: "get_document",
64
+ description: `Gets details of a ClickUp document. Use documentId (preferred) or search by title in a container.`,
65
+ inputSchema: {
66
+ type: "object",
67
+ properties: {
68
+ documentId: {
69
+ type: "string",
70
+ description: "ID of the document to retrieve"
71
+ },
72
+ },
73
+ required: ["documentId"]
74
+ }
75
+ };
76
+ /**
77
+ * Tool definition for listing documents
78
+ */
79
+ export const listDocumentsTool = {
80
+ name: "list_documents",
81
+ description: `Lists all documents in a ClickUp space, folder, or list.`,
82
+ inputSchema: {
83
+ type: "object",
84
+ properties: {
85
+ id: {
86
+ type: "string",
87
+ description: "Optional document ID to filter by"
88
+ },
89
+ creator: {
90
+ type: "number",
91
+ description: "Optional creator ID to filter by"
92
+ },
93
+ deleted: {
94
+ type: "boolean",
95
+ description: "Whether to include deleted documents"
96
+ },
97
+ archived: {
98
+ type: "boolean",
99
+ description: "Whether to include archived documents"
100
+ },
101
+ parent_id: {
102
+ type: "string",
103
+ description: "ID of the parent container to list documents from"
104
+ },
105
+ parent_type: {
106
+ type: "string",
107
+ enum: ["TASK", "SPACE", "FOLDER", "LIST", "EVERYTHING", "WORKSPACE"],
108
+ description: "Type of the parent container"
109
+ },
110
+ limit: {
111
+ type: "number",
112
+ description: "Maximum number of documents to return"
113
+ },
114
+ next_cursor: {
115
+ type: "string",
116
+ description: "Cursor for pagination"
117
+ }
118
+ },
119
+ required: []
120
+ }
121
+ };
122
+ /**
123
+ * Tool definition for listing document pages
124
+ */
125
+ export const listDocumentPagesTool = {
126
+ name: "list_document_pages",
127
+ description: "Lists all pages in a document with optional depth control",
128
+ inputSchema: {
129
+ type: "object",
130
+ properties: {
131
+ documentId: {
132
+ type: "string",
133
+ description: "ID of the document to list pages from"
134
+ },
135
+ max_page_depth: {
136
+ type: "number",
137
+ description: "Maximum depth of pages to retrieve (-1 for unlimited)",
138
+ optional: true
139
+ }
140
+ },
141
+ required: ["documentId"]
142
+ }
143
+ };
144
+ /**
145
+ * Tool definition for getting document pages
146
+ */
147
+ export const getDocumentPagesTool = {
148
+ name: "get_document_pages",
149
+ description: "Gets the content of specific pages from a document",
150
+ inputSchema: {
151
+ type: "object",
152
+ properties: {
153
+ documentId: {
154
+ type: "string",
155
+ description: "ID of the document to get pages from"
156
+ },
157
+ pageIds: {
158
+ type: "array",
159
+ items: {
160
+ type: "string"
161
+ },
162
+ description: "Array of page IDs to retrieve"
163
+ },
164
+ content_format: {
165
+ type: "string",
166
+ enum: ["text/md", "text/html"],
167
+ description: "Format of the content to retrieve",
168
+ optional: true
169
+ }
170
+ },
171
+ required: ["documentId", "pageIds"]
172
+ }
173
+ };
174
+ /**
175
+ * Tool definition for creating a document page
176
+ */
177
+ export const createDocumentPageTool = {
178
+ name: "create_document_page",
179
+ description: "Creates a new page in a ClickUp document",
180
+ inputSchema: {
181
+ type: "object",
182
+ properties: {
183
+ documentId: {
184
+ type: "string",
185
+ description: "ID of the document to create the page in"
186
+ },
187
+ content: {
188
+ type: "string",
189
+ description: "Content of the page",
190
+ optional: true
191
+ },
192
+ name: {
193
+ type: "string",
194
+ description: "Name and title of the page",
195
+ },
196
+ sub_title: {
197
+ type: "string",
198
+ description: "Subtitle of the page",
199
+ optional: true
200
+ },
201
+ parent_page_id: {
202
+ type: "string",
203
+ description: "ID of the parent page (if this is a sub-page)",
204
+ optional: true
205
+ }
206
+ },
207
+ required: ["documentId", "name"]
208
+ }
209
+ };
210
+ /**
211
+ * Tool definition for updating a document page
212
+ */
213
+ export const updateDocumentPageTool = {
214
+ name: "update_document_page",
215
+ description: "Updates an existing page in a ClickUp document. Supports updating name, subtitle, and content with different edit modes (replace/append/prepend).",
216
+ inputSchema: {
217
+ type: "object",
218
+ properties: {
219
+ documentId: {
220
+ type: "string",
221
+ description: "ID of the document containing the page"
222
+ },
223
+ pageId: {
224
+ type: "string",
225
+ description: "ID of the page to update"
226
+ },
227
+ name: {
228
+ type: "string",
229
+ description: "New name for the page",
230
+ optional: true
231
+ },
232
+ sub_title: {
233
+ type: "string",
234
+ description: "New subtitle for the page",
235
+ optional: true
236
+ },
237
+ content: {
238
+ type: "string",
239
+ description: "New content for the page",
240
+ optional: true
241
+ },
242
+ content_edit_mode: {
243
+ type: "string",
244
+ enum: ["replace", "append", "prepend"],
245
+ description: "How to update the content. Defaults to replace",
246
+ optional: true
247
+ },
248
+ content_format: {
249
+ type: "string",
250
+ enum: ["text/md", "text/plain"],
251
+ description: "Format of the content. Defaults to text/md",
252
+ optional: true
253
+ },
254
+ },
255
+ required: ["documentId", "pageId"]
256
+ }
257
+ };
258
+ /**
259
+ * Helper function to find a document by title in a container
260
+ */
261
+ async function findDocumentByTitle(parentId, title) {
262
+ const response = await documentService.listDocuments({
263
+ parent_id: parentId
264
+ });
265
+ const document = response.docs.find(doc => doc.name === title);
266
+ return document ? document.id : null;
267
+ }
268
+ /**
269
+ * Helper function to find parent container ID by name and type
270
+ */
271
+ async function findParentIdByName(name, type) {
272
+ const hierarchy = await workspaceService.getWorkspaceHierarchy();
273
+ const container = workspaceService.findIDByNameInHierarchy(hierarchy, name, type);
274
+ return container ? container.id : null;
275
+ }
276
+ /**
277
+ * Handler for the create_document tool
278
+ */
279
+ export async function handleCreateDocument(parameters) {
280
+ const { name, parent, visibility, create_page } = parameters;
281
+ if (!parent || !visibility || !create_page) {
282
+ return sponsorService.createErrorResponse('Parent, visibility, and create_page are required');
283
+ }
284
+ // Prepare document data
285
+ const documentData = {
286
+ name,
287
+ parent,
288
+ visibility,
289
+ create_page
290
+ };
291
+ try {
292
+ // Create the document
293
+ const newDocument = await clickUpServices.document.createDocument(documentData);
294
+ return sponsorService.createResponse({
295
+ id: newDocument.id,
296
+ name: newDocument.name,
297
+ parent: newDocument.parent,
298
+ url: `https://app.clickup.com/${config.clickupTeamId}/v/d/${newDocument.id}`,
299
+ message: `Document "${name}" created successfully`
300
+ }, true);
301
+ }
302
+ catch (error) {
303
+ return sponsorService.createErrorResponse(`Failed to create document: ${error.message}`);
304
+ }
305
+ }
306
+ /**
307
+ * Handler for the get_document tool
308
+ */
309
+ export async function handleGetDocument(parameters) {
310
+ const { documentId, title, parentId } = parameters;
311
+ let targetDocumentId = documentId;
312
+ // If no documentId but title and parentId are provided, look up the document ID
313
+ if (!targetDocumentId && title && parentId) {
314
+ targetDocumentId = await findDocumentByTitle(parentId, title);
315
+ if (!targetDocumentId) {
316
+ throw new Error(`Document "${title}" not found`);
317
+ }
318
+ }
319
+ if (!targetDocumentId) {
320
+ throw new Error("Either documentId or (title + parentId) must be provided");
321
+ }
322
+ try {
323
+ // Get the document
324
+ const document = await documentService.getDocument(targetDocumentId);
325
+ return sponsorService.createResponse({
326
+ id: document.id,
327
+ name: document.name,
328
+ parent: document.parent,
329
+ created: new Date(document.date_created).toISOString(),
330
+ updated: new Date(document.date_updated).toISOString(),
331
+ creator: document.creator,
332
+ public: document.public,
333
+ type: document.type,
334
+ url: `https://app.clickup.com/${config.clickupTeamId}/v/d/${document.id}`
335
+ }, true);
336
+ }
337
+ catch (error) {
338
+ return sponsorService.createErrorResponse(`Failed to retrieve document: ${error.message}`);
339
+ }
340
+ }
341
+ /**
342
+ * Handler for the list_documents tool
343
+ */
344
+ export async function handleListDocuments(parameters) {
345
+ const { id, creator, deleted, archived, parent_id, parent_type, limit, next_cursor } = parameters;
346
+ try {
347
+ // Prepare options object with all possible parameters
348
+ const options = {};
349
+ // Add each parameter to options only if it's defined
350
+ if (id !== undefined)
351
+ options.id = id;
352
+ if (creator !== undefined)
353
+ options.creator = creator;
354
+ if (deleted !== undefined)
355
+ options.deleted = deleted;
356
+ if (archived !== undefined)
357
+ options.archived = archived;
358
+ if (parent_id !== undefined)
359
+ options.parent_id = parent_id;
360
+ if (parent_type !== undefined)
361
+ options.parent_type = parent_type;
362
+ if (limit !== undefined)
363
+ options.limit = limit;
364
+ if (next_cursor !== undefined)
365
+ options.next_cursor = next_cursor;
366
+ const response = await documentService.listDocuments(options);
367
+ // Ensure we have a valid response
368
+ if (!response || !response.docs) {
369
+ return sponsorService.createResponse({
370
+ documents: [],
371
+ message: "No documents found"
372
+ }, true);
373
+ }
374
+ // Map the documents to a simpler format
375
+ const documents = response.docs.map(doc => ({
376
+ id: doc.id,
377
+ name: doc.name,
378
+ url: `https://app.clickup.com/${config.clickupTeamId}/v/d/${doc.id}`,
379
+ parent: doc.parent,
380
+ created: new Date(doc.date_created).toISOString(),
381
+ updated: new Date(doc.date_updated).toISOString(),
382
+ creator: doc.creator,
383
+ public: doc.public,
384
+ type: doc.type
385
+ }));
386
+ return sponsorService.createResponse({
387
+ documents,
388
+ count: documents.length,
389
+ next_cursor: response.next_cursor,
390
+ message: `Found ${documents.length} document(s)`
391
+ }, true);
392
+ }
393
+ catch (error) {
394
+ return sponsorService.createErrorResponse(`Failed to list documents: ${error.message}`);
395
+ }
396
+ }
397
+ /**
398
+ * Handler for listing document pages
399
+ */
400
+ export async function handleListDocumentPages(params) {
401
+ logger.info('Listing document pages', { params });
402
+ try {
403
+ const { documentId, max_page_depth = -1 } = params;
404
+ const pages = await documentService.listDocumentPages(documentId, { max_page_depth });
405
+ return sponsorService.createResponse(pages);
406
+ }
407
+ catch (error) {
408
+ logger.error('Error listing document pages', error);
409
+ return sponsorService.createErrorResponse(error);
410
+ }
411
+ }
412
+ /**
413
+ * Handler for getting document pages
414
+ */
415
+ export async function handleGetDocumentPages(params) {
416
+ const { documentId, pageIds, content_format } = params;
417
+ if (!documentId) {
418
+ return sponsorService.createErrorResponse('Document ID is required');
419
+ }
420
+ if (!pageIds || !Array.isArray(pageIds) || pageIds.length === 0) {
421
+ return sponsorService.createErrorResponse('Page IDs array is required');
422
+ }
423
+ try {
424
+ const options = {};
425
+ // Adiciona content_format nas options se fornecido
426
+ if (content_format) {
427
+ options.content_format = content_format;
428
+ }
429
+ const pages = await clickUpServices.document.getDocumentPages(documentId, pageIds, options);
430
+ return sponsorService.createResponse(pages);
431
+ }
432
+ catch (error) {
433
+ return sponsorService.createErrorResponse(`Failed to get document pages: ${error.message}`);
434
+ }
435
+ }
436
+ /**
437
+ * Handler for creating a new page in a document
438
+ */
439
+ export async function handleCreateDocumentPage(parameters) {
440
+ const { documentId, content, sub_title, name, parent_page_id } = parameters;
441
+ if (!documentId) {
442
+ return sponsorService.createErrorResponse('Document ID is required');
443
+ }
444
+ if (!name) {
445
+ return sponsorService.createErrorResponse('Title/Name is required');
446
+ }
447
+ try {
448
+ const page = await clickUpServices.document.createPage(documentId, {
449
+ content,
450
+ sub_title,
451
+ name,
452
+ parent_page_id,
453
+ });
454
+ return sponsorService.createResponse(page);
455
+ }
456
+ catch (error) {
457
+ return sponsorService.createErrorResponse(`Failed to create document page: ${error.message}`);
458
+ }
459
+ }
460
+ /**
461
+ * Handler for updating a document page
462
+ */
463
+ export async function handleUpdateDocumentPage(parameters) {
464
+ const { documentId, pageId, name, sub_title, content, content_format, content_edit_mode } = parameters;
465
+ if (!documentId) {
466
+ return sponsorService.createErrorResponse('Document ID is required');
467
+ }
468
+ if (!pageId) {
469
+ return sponsorService.createErrorResponse('Page ID is required');
470
+ }
471
+ // Prepare update data
472
+ const updateData = {};
473
+ if (name)
474
+ updateData.name = name;
475
+ if (sub_title)
476
+ updateData.sub_title = sub_title;
477
+ if (content)
478
+ updateData.content = content;
479
+ if (content_format)
480
+ updateData.content_format = content_format;
481
+ if (content_edit_mode)
482
+ updateData.content_edit_mode = content_edit_mode;
483
+ try {
484
+ const page = await clickUpServices.document.updatePage(documentId, pageId, updateData);
485
+ return sponsorService.createResponse({
486
+ message: `Page updated successfully`
487
+ }, true);
488
+ }
489
+ catch (error) {
490
+ return sponsorService.createErrorResponse(`Failed to update document page: ${error.message}`);
491
+ }
492
+ }
493
+ export const documentTools = [
494
+ createDocumentTool,
495
+ getDocumentTool,
496
+ listDocumentsTool,
497
+ listDocumentPagesTool,
498
+ getDocumentPagesTool,
499
+ createDocumentPageTool,
500
+ updateDocumentPageTool
501
+ ];
@@ -196,7 +196,8 @@ export const updateBulkTasksTool = {
196
196
  description: "New status"
197
197
  },
198
198
  priority: {
199
- type: ["number", "null"],
199
+ type: "number",
200
+ nullable: true,
200
201
  enum: [1, 2, 3, 4, null],
201
202
  description: "New priority (1-4 or null)"
202
203
  },
@@ -14,6 +14,8 @@ export { createTaskTool, getTaskTool, getTasksTool, updateTaskTool, moveTaskTool
14
14
  export { createBulkTasksTool, updateBulkTasksTool, moveBulkTasksTool, deleteBulkTasksTool } from './bulk-operations.js';
15
15
  // Re-export workspace task operation tools
16
16
  export { getWorkspaceTasksTool } from './workspace-operations.js';
17
+ // Re-export time tracking tools and handlers
18
+ export { getTaskTimeEntriesTool, startTimeTrackingTool, stopTimeTrackingTool, addTimeEntryTool, deleteTimeEntryTool, getCurrentTimeEntryTool, handleGetTaskTimeEntries, handleStartTimeTracking, handleStopTimeTracking, handleAddTimeEntry, handleDeleteTimeEntry, handleGetCurrentTimeEntry, timeTrackingTools, timeTrackingHandlers } from './time-tracking.js';
17
19
  // Re-export attachment tool
18
20
  export { attachTaskFileTool, handleAttachTaskFile } from './attachments.js';
19
21
  // Re-export handlers
@@ -161,7 +161,8 @@ export const updateTaskTool = {
161
161
  description: "New status. Must be valid for the task's current list."
162
162
  },
163
163
  priority: {
164
- type: ["number", "null"],
164
+ type: "number",
165
+ nullable: true,
165
166
  enum: [1, 2, 3, 4, null],
166
167
  description: "New priority: 1 (urgent) to 4 (low). Set null to clear priority."
167
168
  },