@taazkareem/clickup-mcp-server 0.6.9 → 0.7.0

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
@@ -1,12 +1,12 @@
1
1
  <img src="assets/images/clickup_mcp_server_social_image.png" alt="ClickUp MCP Server" width="100%">
2
2
 
3
- ![Total Supporters](https://img.shields.io/badge/🏆%20Total%20Supporters-3-gold)
3
+ ![Total Supporters](https://img.shields.io/badge/🏆%20Total%20Supporters-4-gold)
4
4
  [![GitHub Stars](https://img.shields.io/github/stars/TaazKareem/clickup-mcp-server?style=flat&logo=github)](https://github.com/TaazKareem/clickup-mcp-server/stargazers)
5
5
  [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-brightgreen.svg)](https://github.com/TaazKareem/clickup-mcp-server/graphs/commit-activity)
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.9 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:** v0.7.0 now available with complete Time Tracking support and Document Management features.
10
10
 
11
11
  ## Setup
12
12
 
@@ -20,7 +20,7 @@ A Model Context Protocol (MCP) server for integrating ClickUp tasks with AI appl
20
20
 
21
21
  [![smithery badge](https://smithery.ai/badge/@taazkareem/clickup-mcp-server)](https://smithery.ai/server/@TaazKareem/clickup-mcp-server)
22
22
 
23
- The server is hosted on [Smithery](https://smithery.ai/server/@taazkareem/clickup-mcp-server). There, you can preview the available tools or copy the commands to run on your specific client app.
23
+ The server is hosted on [Smithery](https://smithery.ai/server/@taazkareem/clickup-mcp-server). There, you can preview the available tools or copy the commands to run on your specific client app.
24
24
 
25
25
  ## NPX Installation
26
26
 
@@ -41,7 +41,8 @@ Add this entry to your client's MCP settings JSON file:
41
41
  ],
42
42
  "env": {
43
43
  "CLICKUP_API_KEY": "your-api-key",
44
- "CLICKUP_TEAM_ID": "your-team-id"
44
+ "CLICKUP_TEAM_ID": "your-team-id",
45
+ "DOCUMENT_SUPPORT": "true"
45
46
  }
46
47
  }
47
48
  }
@@ -52,64 +53,87 @@ Or use this npx command:
52
53
 
53
54
  `npx -y @taazkareem/clickup-mcp-server@latest --env CLICKUP_API_KEY=your-api-key --env CLICKUP_TEAM_ID=your-team-id`
54
55
 
56
+ **Obs: if you don't pass "DOCUMENT_SUPPORT": "true", the default is false and document support will not be active.**
57
+
58
+ Additionally, you can use the `DISABLED_TOOLS` environment variable or `--env DISABLED_TOOLS` argument to disable specific tools. Provide a comma-separated list of tool names to disable (e.g., `create_task,delete_task`).
59
+
60
+ Please disable tools you don't need if you are having issues with the number of tools or any context limitations
61
+
55
62
  ## Features
56
63
 
57
- | 📝 Task Management | 🏷️ Tag Management |
58
- |----------------------------|----------------------------|
59
- | • Create, update, and delete tasks<br>• Move and duplicate tasks anywhere<br>• Support for single and bulk operations<br>• Set start/due dates with natural language<br>• Create and manage subtasks<br>• Add comments and attachments | • Create, update, and delete space tags<br>• Add and remove tags from tasks<br>• Use natural language color commands<br>• Automatic contrasting foreground colors<br>• View all space tags<br>• Tag-based task organization across workspace |
60
- | 🌳 **Workspace Organization** | ⚡ **Integration Features** |
61
- | • Navigate spaces, folders, and lists<br>• Create and manage folders<br>• Organize lists within spaces<br>• Create lists in folders<br>• View workspace hierarchy<br>• Efficient path navigation | • Global name or ID-based lookups<br>• Case-insensitive matching<br>• Markdown formatting support<br>• Built-in rate limiting<br>• Error handling and validation<br>• Comprehensive API coverage |
64
+ | 📝 Task Management | 🏷️ Tag Management |
65
+ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
66
+ | • Create, update, and delete tasks`<br>`• Move and duplicate tasks anywhere`<br>`• Support for single and bulk operations`<br>`• Set start/due dates with natural language`<br>`• Create and manage subtasks`<br>`• Add comments and attachments | • Create, update, and delete space tags`<br>`• Add and remove tags from tasks`<br>`• Use natural language color commands`<br>`• Automatic contrasting foreground colors`<br>`• View all space tags`<br>`• Tag-based task organization across workspace |
67
+ | ⏱️**Time Tracking** | 🌳**Workspace Organization** |
68
+ | • View time entries for tasks`<br>`• Start/stop time tracking on tasks`<br>`• Add manual time entries`<br>`• Delete time entries`<br>`• View currently running timer`<br>`• Track billable and non-billable time | • Navigate spaces, folders, and lists`<br>`• Create and manage folders`<br>`• Organize lists within spaces`<br>`• Create lists in folders`<br>`• View workspace hierarchy`<br>`• Efficient path navigation |
69
+ | ⚡**Integration Features** | **Document Listing, Creation and Updating!** |
70
+ | • Global name or ID-based lookups`<br>`• Case-insensitive matching`<br>`• Markdown formatting support`<br>`• Built-in rate limiting`<br>`• Error handling and validation`<br>`• Comprehensive API coverage | • Document Listing through all workspace`<br>` • Document Page listing `<br>` • Document Page Details `<br>` • Document Creation `<br>` • Document page update, modification (append and prepend) `<br>` |
62
71
 
63
72
  ## Available Tools
64
73
 
65
- | Tool | Description | Required Parameters |
66
- |------|-------------|-------------------|
67
- | [get_workspace_hierarchy](docs/api-reference.md#workspace-navigation) | Get workspace structure | None |
68
- | [create_task](docs/api-reference.md#task-management) | Create a task | `name`, (`listId`/`listName`) |
69
- | [create_bulk_tasks](docs/api-reference.md#task-management) | Create multiple tasks | `tasks[]` |
70
- | [update_task](docs/api-reference.md#task-management) | Modify task | `taskId`/`taskName` |
71
- | [update_bulk_tasks](docs/api-reference.md#task-management) | Update multiple tasks | `tasks[]` with IDs or names |
72
- | [get_tasks](docs/api-reference.md#task-management) | Get tasks from list | `listId`/`listName` |
73
- | [get_task](docs/api-reference.md#task-management) | Get single task details | `taskId`/`taskName` (with smart disambiguation) |
74
- | [get_workspace_tasks](docs/api-reference.md#task-management) | Get tasks with filtering | At least one filter (tags, list_ids, space_ids, etc.) |
75
- | [get_task_comments](docs/api-reference.md#task-management) | Get comments on a task | `taskId`/`taskName` |
76
- | [create_task_comment](docs/api-reference.md#task-management) | Add a comment to a task | `commentText`, (`taskId`/(`taskName`+`listName`)) |
77
- | [attach_task_file](docs/api-reference.md#task-management) | Attach file to a task | `taskId`/`taskName`, (`file_data` or `file_url`) |
78
- | [delete_task](docs/api-reference.md#task-management) | Remove task | `taskId`/`taskName` |
79
- | [delete_bulk_tasks](docs/api-reference.md#task-management) | Remove multiple tasks | `tasks[]` with IDs or names |
80
- | [move_task](docs/api-reference.md#task-management) | Move task | `taskId`/`taskName`, `listId`/`listName` |
81
- | [move_bulk_tasks](docs/api-reference.md#task-management) | Move multiple tasks | `tasks[]` with IDs or names, target list |
82
- | [duplicate_task](docs/api-reference.md#task-management) | Copy task | `taskId`/`taskName`, `listId`/`listName` |
83
- | [create_list](docs/api-reference.md#list-management) | Create list in space | `name`, `spaceId`/`spaceName` |
84
- | [create_folder](docs/api-reference.md#folder-management) | Create folder | `name`, `spaceId`/`spaceName` |
85
- | [create_list_in_folder](docs/api-reference.md#list-management) | Create list in folder | `name`, `folderId`/`folderName` |
86
- | [get_folder](docs/api-reference.md#folder-management) | Get folder details | `folderId`/`folderName` |
87
- | [update_folder](docs/api-reference.md#folder-management) | Update folder properties | `folderId`/`folderName` |
88
- | [delete_folder](docs/api-reference.md#folder-management) | Delete folder | `folderId`/`folderName` |
89
- | [get_list](docs/api-reference.md#list-management) | Get list details | `listId`/`listName` |
90
- | [update_list](docs/api-reference.md#list-management) | Update list properties | `listId`/`listName` |
91
- | [delete_list](docs/api-reference.md#list-management) | Delete list | `listId`/`listName` |
92
- | [get_space_tags](docs/api-reference.md#tag-management) | Get space tags | `spaceId`/`spaceName` |
93
- | [create_space_tag](docs/api-reference.md#tag-management) | Create tag | `tagName`, `spaceId`/`spaceName` |
94
- | [update_space_tag](docs/api-reference.md#tag-management) | Update tag | `tagName`, `spaceId`/`spaceName` |
95
- | [delete_space_tag](docs/api-reference.md#tag-management) | Delete tag | `tagName`, `spaceId`/`spaceName` |
96
- | [add_tag_to_task](docs/api-reference.md#tag-management) | Add tag to task | `tagName`, `taskId`/(`taskName`+`listName`) |
97
- | [remove_tag_from_task](docs/api-reference.md#tag-management) | Remove tag from task | `tagName`, `taskId`/(`taskName`+`listName`) |
74
+ | Tool | Description | Required Parameters |
75
+ | ------------------------------------------------------------------ | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
76
+ | [get_workspace_hierarchy](docs/api-reference.md#workspace-navigation) | Get workspace structure | None |
77
+ | [create_task](docs/api-reference.md#task-management) | Create a task | `name`, (`listId`/`listName`) |
78
+ | [create_bulk_tasks](docs/api-reference.md#task-management) | Create multiple tasks | `tasks[]` |
79
+ | [update_task](docs/api-reference.md#task-management) | Modify task | `taskId`/`taskName` |
80
+ | [update_bulk_tasks](docs/api-reference.md#task-management) | Update multiple tasks | `tasks[]` with IDs or names |
81
+ | [get_tasks](docs/api-reference.md#task-management) | Get tasks from list | `listId`/`listName` |
82
+ | [get_task](docs/api-reference.md#task-management) | Get single task details | `taskId`/`taskName` (with smart disambiguation) |
83
+ | [get_workspace_tasks](docs/api-reference.md#task-management) | Get tasks with filtering | At least one filter (tags, list_ids, space_ids, etc.) |
84
+ | [get_task_comments](docs/api-reference.md#task-management) | Get comments on a task | `taskId`/`taskName` |
85
+ | [create_task_comment](docs/api-reference.md#task-management) | Add a comment to a task | `commentText`, (`taskId`/(`taskName`+`listName`)) |
86
+ | [attach_task_file](docs/api-reference.md#task-management) | Attach file to a task | `taskId`/`taskName`, (`file_data` or `file_url`) |
87
+ | [delete_task](docs/api-reference.md#task-management) | Remove task | `taskId`/`taskName` |
88
+ | [delete_bulk_tasks](docs/api-reference.md#task-management) | Remove multiple tasks | `tasks[]` with IDs or names |
89
+ | [move_task](docs/api-reference.md#task-management) | Move task | `taskId`/`taskName`, `listId`/`listName` |
90
+ | [move_bulk_tasks](docs/api-reference.md#task-management) | Move multiple tasks | `tasks[]` with IDs or names, target list |
91
+ | [duplicate_task](docs/api-reference.md#task-management) | Copy task | `taskId`/`taskName`, `listId`/`listName` |
92
+ | [create_list](docs/api-reference.md#list-management) | Create list in space | `name`, `spaceId`/`spaceName` |
93
+ | [create_folder](docs/api-reference.md#folder-management) | Create folder | `name`, `spaceId`/`spaceName` |
94
+ | [create_list_in_folder](docs/api-reference.md#list-management) | Create list in folder | `name`, `folderId`/`folderName` |
95
+ | [get_folder](docs/api-reference.md#folder-management) | Get folder details | `folderId`/`folderName` |
96
+ | [update_folder](docs/api-reference.md#folder-management) | Update folder properties | `folderId`/`folderName` |
97
+ | [delete_folder](docs/api-reference.md#folder-management) | Delete folder | `folderId`/`folderName` |
98
+ | [get_list](docs/api-reference.md#list-management) | Get list details | `listId`/`listName` |
99
+ | [update_list](docs/api-reference.md#list-management) | Update list properties | `listId`/`listName` |
100
+ | [delete_list](docs/api-reference.md#list-management) | Delete list | `listId`/`listName` |
101
+ | [get_space_tags](docs/api-reference.md#tag-management) | Get space tags | `spaceId`/`spaceName` |
102
+ | [create_space_tag](docs/api-reference.md#tag-management) | Create tag | `tagName`, `spaceId`/`spaceName` |
103
+ | [update_space_tag](docs/api-reference.md#tag-management) | Update tag | `tagName`, `spaceId`/`spaceName` |
104
+ | [delete_space_tag](docs/api-reference.md#tag-management) | Delete tag | `tagName`, `spaceId`/`spaceName` |
105
+ | [add_tag_to_task](docs/api-reference.md#tag-management) | Add tag to task | `tagName`, `taskId`/(`taskName`+`listName`) |
106
+ | [remove_tag_from_task](docs/api-reference.md#tag-management) | Remove tag from task | `tagName`, `taskId`/(`taskName`+`listName`) |
107
+ | [get_task_time_entries](docs/api-reference.md#time-tracking) | Get time entries for a task | `taskId`/`taskName` |
108
+ | [start_time_tracking](docs/api-reference.md#time-tracking) | Start time tracking on a task | `taskId`/`taskName` |
109
+ | [stop_time_tracking](docs/api-reference.md#time-tracking) | Stop current time tracking | None |
110
+ | [add_time_entry](docs/api-reference.md#time-tracking) | Add manual time entry to a task | `taskId`/`taskName`, `start`, `duration` |
111
+ | [delete_time_entry](docs/api-reference.md#time-tracking) | Delete a time entry | `timeEntryId` |
112
+ | [get_current_time_entry](docs/api-reference.md#time-tracking) | Get currently running timer | None |
113
+ | [create_document](docs/api-reference.md#document-management) | Create a document | `workspaceId`, `name`, `parentId`/`parentType`, `visibility`, `create_pages` |
114
+ | [get_document](docs/api-reference.md#document-management) | Get a document | `workspaceId`/`documentId` |
115
+ | [list_documents](docs/api-reference.md#document-management) | List documents | `workspaceId`, `documentId`/`creator`/`deleted`/`archived`/`parent_id`/`parent_type`/`limit`/`next_cursor` |
116
+ | [list_document_pages](docs/api-reference.md#document-management) | List document pages | `documentId`/`documentName` |
117
+ | [get_document_pages](docs/api-reference.md#document-management) | Get document pages | `documentId`/`documentName`, `pageIds` |
118
+ | [create_document_pages](docs/api-reference.md#document-management) | Create a document page | `workspaceId`/`documentId`, `parent_page_id`/`name`/`sub_title`,`content`/`content_format` |
119
+ | [update_document_page](docs/api-reference.md#document-management) | Update a document page | `workspaceId`/`documentId`, `name`/`sub_title`,`content`/`content_edit_mode`/`content_format` |
98
120
 
99
121
  See [full documentation](docs/api-reference.md) for optional parameters and advanced usage.
100
122
 
101
123
  ## Prompts
124
+
102
125
  Not yet implemented and not supported by all client apps. Request a feature for a Prompt implementation that would be most beneficial for your workflow (without it being too specific). Examples:
103
126
 
104
- | Prompt | Purpose | Features |
105
- |--------|---------|----------|
106
- | [summarize_tasks](docs/api-reference.md#prompts) | Task overview | Status summary, priorities, relationships |
107
- | [analyze_priorities](docs/api-reference.md#prompts) | Priority optimization | Distribution analysis, sequencing |
108
- | [generate_description](docs/api-reference.md#prompts) | Task description creation | Objectives, criteria, dependencies |
127
+ | Prompt | Purpose | Features |
128
+ | -------------------------------------------------- | ------------------------- | ----------------------------------------- |
129
+ | [summarize_tasks](docs/api-reference.md#prompts) | Task overview | Status summary, priorities, relationships |
130
+ | [analyze_priorities](docs/api-reference.md#prompts) | Priority optimization | Distribution analysis, sequencing |
131
+ | [generate_description](docs/api-reference.md#prompts) | Task description creation | Objectives, criteria, dependencies |
109
132
 
110
133
  ## Error Handling
111
134
 
112
135
  The server provides clear error messages for:
136
+
113
137
  - Missing required parameters
114
138
  - Invalid IDs or names
115
139
  - Items not found
@@ -127,12 +151,10 @@ If you find this project useful, please consider supporting:
127
151
 
128
152
  [![Sponsor TaazKareem](https://img.shields.io/badge/Sponsor-TaazKareem-orange?logo=github)](https://github.com/sponsors/TaazKareem)
129
153
 
130
-
131
154
  <a href="https://buymeacoffee.com/taazkareem">
132
155
  <img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" width="200" alt="Buy Me A Coffee">
133
156
  </a>
134
157
 
135
-
136
158
  ## Acknowledgements
137
159
 
138
160
  Special thanks to [ClickUp](https://clickup.com) for their excellent API and services that make this integration possible.
@@ -150,7 +172,7 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
150
172
  ## Disclaimer
151
173
 
152
174
  This software makes use of third-party APIs and may reference trademarks
153
- or brands owned by third parties. The use of such APIs or references does not imply
154
- any affiliation with or endorsement by the respective companies. All trademarks and
175
+ or brands owned by third parties. The use of such APIs or references does not imply
176
+ any affiliation with or endorsement by the respective companies. All trademarks and
155
177
  brand names are the property of their respective owners. This project is an independent
156
178
  work and is not officially associated with or sponsored by any third-party company mentioned.
package/build/config.js CHANGED
@@ -7,6 +7,10 @@
7
7
  * The required environment variables (CLICKUP_API_KEY and CLICKUP_TEAM_ID) are passed
8
8
  * securely to this file when running the hosted server at smithery.ai. Optionally,
9
9
  * they can be parsed via command line arguments when running the server locally.
10
+ *
11
+ * The document support is optional and can be passed via command line arguments.
12
+ * The default value is 'false' (string), which means document support will be disabled if
13
+ * no parameter is passed. Pass it as 'true' (string) to enable it.
10
14
  */
11
15
  // Parse any command line environment arguments
12
16
  const args = process.argv.slice(2);
@@ -18,8 +22,18 @@ for (let i = 0; i < args.length; i++) {
18
22
  envArgs.clickupApiKey = value;
19
23
  if (key === 'CLICKUP_TEAM_ID')
20
24
  envArgs.clickupTeamId = value;
25
+ if (key === 'DOCUMENT_SUPPORT')
26
+ envArgs.documentSupport = value;
27
+ if (key === 'DOCUMENT_MODEL')
28
+ envArgs.documentSupport = value; // Backward compatibility
29
+ if (key === 'DOCUMENT_MODULE')
30
+ envArgs.documentSupport = value; // Backward compatibility
21
31
  if (key === 'LOG_LEVEL')
22
32
  envArgs.logLevel = value;
33
+ if (key === 'DISABLED_TOOLS')
34
+ envArgs.disabledTools = value;
35
+ if (key === 'DISABLED_COMMANDS')
36
+ envArgs.disabledTools = value; // Backward compatibility
23
37
  i++;
24
38
  }
25
39
  }
@@ -52,7 +66,9 @@ const configuration = {
52
66
  clickupApiKey: envArgs.clickupApiKey || process.env.CLICKUP_API_KEY || '',
53
67
  clickupTeamId: envArgs.clickupTeamId || process.env.CLICKUP_TEAM_ID || '',
54
68
  enableSponsorMessage: process.env.ENABLE_SPONSOR_MESSAGE !== 'false',
55
- logLevel: parseLogLevel(envArgs.logLevel || process.env.LOG_LEVEL)
69
+ documentSupport: envArgs.documentSupport || process.env.DOCUMENT_SUPPORT || process.env.DOCUMENT_MODULE || process.env.DOCUMENT_MODEL || 'false',
70
+ logLevel: parseLogLevel(envArgs.logLevel || process.env.LOG_LEVEL),
71
+ disabledTools: ((envArgs.disabledTools || process.env.DISABLED_TOOLS || process.env.DISABLED_COMMANDS)?.split(',').map(cmd => cmd.trim()).filter(cmd => cmd !== '') || []),
56
72
  };
57
73
  // Don't log to console as it interferes with JSON-RPC communication
58
74
  // Validate only the required variables are present
package/build/server.js CHANGED
@@ -6,11 +6,13 @@
6
6
  */
7
7
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
8
8
  import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, ListResourcesRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
9
+ import config from "./config.js";
9
10
  import { workspaceHierarchyTool, handleGetWorkspaceHierarchy } from "./tools/workspace.js";
10
- import { createTaskTool, updateTaskTool, moveTaskTool, duplicateTaskTool, getTaskTool, deleteTaskTool, getTaskCommentsTool, createTaskCommentTool, createBulkTasksTool, updateBulkTasksTool, moveBulkTasksTool, deleteBulkTasksTool, attachTaskFileTool, getWorkspaceTasksTool, handleCreateTask, handleUpdateTask, handleMoveTask, handleDuplicateTask, handleDeleteTask, handleGetTaskComments, handleCreateTaskComment, handleCreateBulkTasks, handleUpdateBulkTasks, handleMoveBulkTasks, handleDeleteBulkTasks, handleGetTask, handleAttachTaskFile, handleGetWorkspaceTasks } from "./tools/task/index.js";
11
+ import { createTaskTool, updateTaskTool, moveTaskTool, duplicateTaskTool, getTaskTool, deleteTaskTool, getTaskCommentsTool, createTaskCommentTool, createBulkTasksTool, updateBulkTasksTool, moveBulkTasksTool, deleteBulkTasksTool, attachTaskFileTool, getWorkspaceTasksTool, getTaskTimeEntriesTool, startTimeTrackingTool, stopTimeTrackingTool, addTimeEntryTool, deleteTimeEntryTool, getCurrentTimeEntryTool, handleCreateTask, handleUpdateTask, handleMoveTask, handleDuplicateTask, handleDeleteTask, handleGetTaskComments, handleCreateTaskComment, handleCreateBulkTasks, handleUpdateBulkTasks, handleMoveBulkTasks, handleDeleteBulkTasks, handleGetTask, handleAttachTaskFile, handleGetWorkspaceTasks, handleGetTaskTimeEntries, handleStartTimeTracking, handleStopTimeTracking, handleAddTimeEntry, handleDeleteTimeEntry, handleGetCurrentTimeEntry } from "./tools/task/index.js";
11
12
  import { createListTool, handleCreateList, createListInFolderTool, handleCreateListInFolder, getListTool, handleGetList, updateListTool, handleUpdateList, deleteListTool, handleDeleteList } from "./tools/list.js";
12
13
  import { createFolderTool, handleCreateFolder, getFolderTool, handleGetFolder, updateFolderTool, handleUpdateFolder, deleteFolderTool, handleDeleteFolder } from "./tools/folder.js";
13
14
  import { getSpaceTagsTool, handleGetSpaceTags, addTagToTaskTool, handleAddTagToTask, removeTagFromTaskTool, handleRemoveTagFromTask } from "./tools/tag.js";
15
+ import { createDocumentTool, handleCreateDocument, getDocumentTool, handleGetDocument, listDocumentsTool, handleListDocuments, listDocumentPagesTool, handleListDocumentPages, getDocumentPagesTool, handleGetDocumentPages, createDocumentPageTool, handleCreateDocumentPage, updateDocumentPageTool, handleUpdateDocumentPage } from "./tools/documents.js";
14
16
  import { Logger } from "./logger.js";
15
17
  import { clickUpServices } from "./services/shared.js";
16
18
  // Create a logger instance for server
@@ -19,7 +21,7 @@ const logger = new Logger('Server');
19
21
  const { workspace } = clickUpServices;
20
22
  export const server = new Server({
21
23
  name: "clickup-mcp-server",
22
- version: "0.6.9",
24
+ version: "0.7.0",
23
25
  }, {
24
26
  capabilities: {
25
27
  tools: {},
@@ -27,6 +29,22 @@ export const server = new Server({
27
29
  resources: {},
28
30
  },
29
31
  });
32
+ const documentModule = () => {
33
+ if (config.documentSupport === 'true') {
34
+ return [
35
+ createDocumentTool,
36
+ getDocumentTool,
37
+ listDocumentsTool,
38
+ listDocumentPagesTool,
39
+ getDocumentPagesTool,
40
+ createDocumentPageTool,
41
+ updateDocumentPageTool,
42
+ ];
43
+ }
44
+ else {
45
+ return [];
46
+ }
47
+ };
30
48
  /**
31
49
  * Configure the server routes and handlers
32
50
  */
@@ -52,6 +70,12 @@ export function configureServer() {
52
70
  moveBulkTasksTool,
53
71
  deleteBulkTasksTool,
54
72
  getWorkspaceTasksTool,
73
+ getTaskTimeEntriesTool,
74
+ startTimeTrackingTool,
75
+ stopTimeTrackingTool,
76
+ addTimeEntryTool,
77
+ deleteTimeEntryTool,
78
+ getCurrentTimeEntryTool,
55
79
  createListTool,
56
80
  createListInFolderTool,
57
81
  getListTool,
@@ -63,8 +87,9 @@ export function configureServer() {
63
87
  deleteFolderTool,
64
88
  getSpaceTagsTool,
65
89
  addTagToTaskTool,
66
- removeTagFromTaskTool
67
- ]
90
+ removeTagFromTaskTool,
91
+ ...documentModule()
92
+ ].filter(tool => !config.disabledTools.includes(tool.name))
68
93
  };
69
94
  });
70
95
  // Add handler for resources/list
@@ -74,8 +99,8 @@ export function configureServer() {
74
99
  });
75
100
  // Register CallTool handler with proper logging
76
101
  logger.info("Registering tool handlers", {
77
- toolCount: 31,
78
- categories: ["workspace", "task", "list", "folder", "tag"]
102
+ toolCount: 40,
103
+ categories: ["workspace", "task", "time-tracking", "list", "folder", "tag", "document"]
79
104
  });
80
105
  server.setRequestHandler(CallToolRequestSchema, async (req) => {
81
106
  const { name, arguments: params } = req.params;
@@ -83,6 +108,14 @@ export function configureServer() {
83
108
  logger.info(`Received CallTool request for tool: ${name}`, {
84
109
  params
85
110
  });
111
+ // Check if the tool is disabled
112
+ if (config.disabledTools.includes(name)) {
113
+ logger.warn(`Tool execution blocked: Tool '${name}' is disabled.`);
114
+ throw {
115
+ code: -32601,
116
+ message: `Tool '${name}' is disabled.`
117
+ };
118
+ }
86
119
  try {
87
120
  // Handle tool calls by routing to the appropriate handler
88
121
  switch (name) {
@@ -140,6 +173,32 @@ export function configureServer() {
140
173
  return handleAddTagToTask(params);
141
174
  case "remove_tag_from_task":
142
175
  return handleRemoveTagFromTask(params);
176
+ case "get_task_time_entries":
177
+ return handleGetTaskTimeEntries(params);
178
+ case "start_time_tracking":
179
+ return handleStartTimeTracking(params);
180
+ case "stop_time_tracking":
181
+ return handleStopTimeTracking(params);
182
+ case "add_time_entry":
183
+ return handleAddTimeEntry(params);
184
+ case "delete_time_entry":
185
+ return handleDeleteTimeEntry(params);
186
+ case "get_current_time_entry":
187
+ return handleGetCurrentTimeEntry(params);
188
+ case "create_document":
189
+ return handleCreateDocument(params);
190
+ case "get_document":
191
+ return handleGetDocument(params);
192
+ case "list_documents":
193
+ return handleListDocuments(params);
194
+ case "list_document_pages":
195
+ return handleListDocumentPages(params);
196
+ case "get_document_pages":
197
+ return handleGetDocumentPages(params);
198
+ case "create_document_page":
199
+ return handleCreateDocumentPage(params);
200
+ case "update_document_page":
201
+ return handleUpdateDocumentPage(params);
143
202
  default:
144
203
  logger.error(`Unknown tool requested: ${name}`);
145
204
  const error = new Error(`Unknown tool: ${name}`);
@@ -0,0 +1,159 @@
1
+ /**
2
+ * SPDX-FileCopyrightText: © 2025 João Santana <joaosantana@gmail.com>
3
+ * SPDX-License-Identifier: MIT
4
+ *
5
+ * Document service for ClickUp
6
+ *
7
+ * This service provides methods to manage ClickUp documents:
8
+ * - Create documents
9
+ * - Get document details
10
+ * - List documents in a container
11
+ * - List document pages
12
+ * - Get document pages content
13
+ * - Update document pages
14
+ */
15
+ import { BaseClickUpService, ClickUpServiceError, ErrorCode } from './base.js';
16
+ export class DocumentService extends BaseClickUpService {
17
+ constructor(apiKey, teamId, baseUrl) {
18
+ // Override baseUrl to use v3 API, since Docs are only available in v3
19
+ super(apiKey, teamId, baseUrl || 'https://api.clickup.com/api/v3');
20
+ }
21
+ /**
22
+ * Helper method to handle errors consistently
23
+ * @param error The error that occurred
24
+ * @param message Optional custom error message
25
+ * @returns A ClickUpServiceError
26
+ */
27
+ handleError(error, message) {
28
+ if (error instanceof ClickUpServiceError) {
29
+ return error;
30
+ }
31
+ return new ClickUpServiceError(message || `Document service error: ${error.message}`, ErrorCode.UNKNOWN, error);
32
+ }
33
+ /**
34
+ * Creates a new document in a space, folder, or list
35
+ * @param data - Document data with parent object structured as {id: string, type: number}
36
+ * @returns Created document
37
+ */
38
+ async createDocument(data) {
39
+ try {
40
+ // Log the request data for debugging
41
+ this.logOperation('Creating document with data:', { data });
42
+ const response = await this.client.post(`/workspaces/${this.teamId}/docs`, {
43
+ name: data.name,
44
+ parent: data.parent,
45
+ visibility: data.visibility || 'PRIVATE',
46
+ create_page: data.create_page !== undefined ? data.create_page : true
47
+ });
48
+ return response.data;
49
+ }
50
+ catch (error) {
51
+ throw this.handleError(error, 'Failed to create document');
52
+ }
53
+ }
54
+ /**
55
+ * Creates a new page in a document
56
+ * @param documentId - ID of the document to create the page in
57
+ * @param data - Page data
58
+ * @returns Created page
59
+ */
60
+ async createPage(documentId, data) {
61
+ try {
62
+ this.logOperation('Creating page in document with data:', { documentId, data });
63
+ const response = await this.client.post(`/workspaces/${this.teamId}/docs/${documentId}/pages`, data);
64
+ return response.data;
65
+ }
66
+ catch (error) {
67
+ throw this.handleError(error, `Failed to create page in document ${documentId}`);
68
+ }
69
+ }
70
+ /**
71
+ * Gets a document by ID
72
+ * @param documentId - ID of the document to retrieve
73
+ * @returns Document details
74
+ */
75
+ async getDocument(documentId) {
76
+ try {
77
+ this.logOperation('Getting document with ID:', { documentId });
78
+ const response = await this.client.get(`/workspaces/${this.teamId}/docs/${documentId}`);
79
+ return response.data;
80
+ }
81
+ catch (error) {
82
+ throw this.handleError(error, `Failed to get document ${documentId}`);
83
+ }
84
+ }
85
+ /**
86
+ * Lists documents in the workspace with optional filters
87
+ * @param options - Search and filter options
88
+ * @returns List of documents
89
+ */
90
+ async listDocuments(options = {}) {
91
+ try {
92
+ this.logOperation('Listing documents with options:', { options });
93
+ const response = await this.client.get(`/workspaces/${this.teamId}/docs`, {
94
+ params: options
95
+ });
96
+ return response.data;
97
+ }
98
+ catch (error) {
99
+ throw this.handleError(error, 'Failed to list documents');
100
+ }
101
+ }
102
+ /**
103
+ * Lists all pages in a document with optional depth control
104
+ * @param documentId - ID of the document
105
+ * @param options - Options for page listing
106
+ * @returns List of document pages
107
+ */
108
+ async listDocumentPages(documentId, options = {}) {
109
+ try {
110
+ this.logOperation('Listing pages for document with ID:', { documentId, options });
111
+ const response = await this.client.get(`/workspaces/${this.teamId}/docs/${documentId}/pageListing`, { params: options });
112
+ return response.data;
113
+ }
114
+ catch (error) {
115
+ throw this.handleError(error, `Failed to list pages for document ${documentId}`);
116
+ }
117
+ }
118
+ /**
119
+ * Gets the content of specific pages in a document
120
+ * @param documentId - ID of the document
121
+ * @param pageIds - Array of page IDs to retrieve
122
+ * @param options - Options for retrieving pages content
123
+ * @returns Document pages with content
124
+ */
125
+ async getDocumentPages(documentId, pageIds, options = {}) {
126
+ try {
127
+ // Get pages in parallel
128
+ this.logOperation('Getting pages for document with ID:', { documentId, pageIds, options });
129
+ const pagePromises = pageIds.map(pageId => this.client.get(`/workspaces/${this.teamId}/docs/${documentId}/pages/${pageId}`, { params: { ...options, pageIds } }));
130
+ const responses = await Promise.all(pagePromises);
131
+ const pages = responses.map(response => response.data);
132
+ return { pages };
133
+ }
134
+ catch (error) {
135
+ throw this.handleError(error, `Failed to get pages for document ${documentId}`);
136
+ }
137
+ }
138
+ /**
139
+ * Updates an existing page in a document
140
+ * @param documentId - ID of the document containing the page
141
+ * @param pageId - ID of the page to update
142
+ * @param data - Updated page data
143
+ * @returns Updated page
144
+ */
145
+ async updatePage(documentId, pageId, data) {
146
+ try {
147
+ this.logOperation('Updating page in document with ID:', { documentId, pageId, data });
148
+ const response = await this.client.put(`/workspaces/${this.teamId}/docs/${documentId}/pages/${pageId}`, {
149
+ ...data,
150
+ content_format: data.content_format || 'text/md',
151
+ content_edit_mode: data.content_edit_mode || 'append'
152
+ });
153
+ return response.data;
154
+ }
155
+ catch (error) {
156
+ throw this.handleError(error, `Failed to update page ${pageId} in document ${documentId}`);
157
+ }
158
+ }
159
+ }
@@ -17,13 +17,17 @@ export { TaskService } from './task/index.js';
17
17
  export { ListService } from './list.js';
18
18
  export { FolderService } from './folder.js';
19
19
  export { ClickUpTagService } from './tag.js';
20
+ export { TimeTrackingService } from './time.js';
21
+ export { DocumentService } from './document.js';
20
22
  // Import service classes for the factory function
21
23
  import { WorkspaceService } from './workspace.js';
22
24
  import { TaskService } from './task/index.js';
23
25
  import { ListService } from './list.js';
24
26
  import { FolderService } from './folder.js';
25
27
  import { ClickUpTagService } from './tag.js';
28
+ import { TimeTrackingService } from './time.js';
26
29
  import { Logger } from '../../logger.js';
30
+ import { DocumentService } from './document.js';
27
31
  // Singleton logger for ClickUp services
28
32
  const logger = new Logger('ClickUpServices');
29
33
  /**
@@ -50,12 +54,18 @@ export function createClickUpServices(config) {
50
54
  const folderService = new FolderService(apiKey, teamId, baseUrl, workspaceService);
51
55
  logger.info('Initializing ClickUp Tag service');
52
56
  const tagService = new ClickUpTagService(apiKey, teamId, baseUrl);
57
+ logger.info('Initializing ClickUp Time Tracking service');
58
+ const timeTrackingService = new TimeTrackingService(apiKey, teamId, baseUrl);
59
+ logger.info('Initializing ClickUp Document service');
60
+ const documentService = new DocumentService(apiKey, teamId, baseUrl);
53
61
  const services = {
54
62
  workspace: workspaceService,
55
63
  task: taskService,
56
64
  list: listService,
57
65
  folder: folderService,
58
- tag: tagService
66
+ tag: tagService,
67
+ timeTracking: timeTrackingService,
68
+ document: documentService
59
69
  };
60
70
  // Log successful completion
61
71
  logger.info('All ClickUp services initialized successfully', {
@@ -268,8 +268,11 @@ export class TaskServiceCore extends BaseClickUpService {
268
268
  async updateTask(taskId, updateData) {
269
269
  this.logOperation('updateTask', { taskId, ...updateData });
270
270
  try {
271
- return await this.makeRequest(async () => {
272
- const response = await this.client.put(`/task/${taskId}`, updateData);
271
+ // Extract custom fields from updateData
272
+ const { custom_fields, ...standardFields } = updateData;
273
+ // First update the standard fields
274
+ const updatedTask = await this.makeRequest(async () => {
275
+ const response = await this.client.put(`/task/${taskId}`, standardFields);
273
276
  // Handle both JSON and text responses
274
277
  const data = response.data;
275
278
  if (typeof data === 'string') {
@@ -283,6 +286,15 @@ export class TaskServiceCore extends BaseClickUpService {
283
286
  }
284
287
  return data;
285
288
  });
289
+ // Then update custom fields if provided
290
+ if (custom_fields && Array.isArray(custom_fields) && custom_fields.length > 0) {
291
+ // Use the setCustomFieldValues method from the inherited class
292
+ // This will be available in TaskServiceCustomFields which extends this class
293
+ await this.setCustomFieldValues(taskId, custom_fields);
294
+ // Fetch the task again to get the updated version with custom fields
295
+ return await this.getTask(taskId);
296
+ }
297
+ return updatedTask;
286
298
  }
287
299
  catch (error) {
288
300
  throw this.handleError(error, `Failed to update task ${taskId}`);