@taazkareem/clickup-mcp-server 0.4.70 → 0.4.71
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 +33 -16
- package/build/config.js +7 -4
- package/build/index.js +1 -1
- package/build/mcp-tools.js +64 -0
- package/build/server.js +4 -4
- package/build/server.log +374 -134
- package/build/services/clickup/bulk.js +132 -101
- package/build/services/clickup/task.js +40 -239
- package/build/tools/bulk-tasks.js +36 -0
- package/build/tools/task.js +614 -537
- package/build/tools/utils.js +8 -147
- package/build/utils/concurrency-utils.js +245 -0
- package/build/utils/date-utils.js +152 -0
- package/build/utils/params-utils.js +39 -0
- package/build/utils/resolver-utils.js +66 -0
- package/build/utils/sponsor-utils.js +49 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,29 +9,43 @@ A Model Context Protocol (MCP) server for integrating ClickUp tasks with AI appl
|
|
|
9
9
|
<img width="380" height="200" src="https://glama.ai/mcp/servers/iwjvs2zy63/badge" alt="ClickUp Server MCP server" />
|
|
10
10
|
</a>
|
|
11
11
|
|
|
12
|
-
##
|
|
13
|
-
|
|
14
|
-
Directions for use with Cursor Composer Agent:
|
|
12
|
+
## Setup
|
|
15
13
|
|
|
16
14
|
1. Get your credentials:
|
|
17
15
|
- ClickUp API key from [ClickUp Settings](https://app.clickup.com/settings/apps)
|
|
18
16
|
- Team ID from your ClickUp workspace URL
|
|
19
|
-
2.
|
|
20
|
-
3. Add under MCP Servers:
|
|
21
|
-
```bash
|
|
22
|
-
npx -y @taazkareem/clickup-mcp-server@latest \
|
|
23
|
-
--env CLICKUP_API_KEY=your_api_key_here \
|
|
24
|
-
--env CLICKUP_TEAM_ID=your_team_id_here
|
|
25
|
-
```
|
|
26
|
-
4. Replace the credentials and click Save
|
|
27
|
-
5. Use Natural Language to interact with your ClickUp Workspace!
|
|
28
|
-
|
|
17
|
+
2. Choose either hosted installation (sends webhooks) or NPX installation (downloads to local path and installs dependencies)
|
|
29
18
|
|
|
30
|
-
## Smithery Installation
|
|
19
|
+
## Smithery Installation (Quick Start)
|
|
31
20
|
|
|
32
21
|
[](https://smithery.ai/server/@TaazKareem/clickup-mcp-server)
|
|
33
22
|
|
|
34
|
-
The server is
|
|
23
|
+
The server is hosted on Smithery. There, you can preview the available tools or copy the commands to run on your specific client app.
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
## NPX Installation
|
|
27
|
+
|
|
28
|
+
Add this entry to your client's MCP settings JSON file:
|
|
29
|
+
|
|
30
|
+
{
|
|
31
|
+
"mcpServers": {
|
|
32
|
+
"ClickUp": {
|
|
33
|
+
"command": "npx",
|
|
34
|
+
"args": [
|
|
35
|
+
"-y",
|
|
36
|
+
"@taazkareem/clickup-mcp-server@latest"
|
|
37
|
+
],
|
|
38
|
+
"env": {
|
|
39
|
+
"CLICKUP_API_KEY": "your-api-key",
|
|
40
|
+
"CLICKUP_TEAM_ID": "your-team-id"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
-OR- Use this npx command:
|
|
47
|
+
|
|
48
|
+
`npx -y @taazkareem/clickup-mcp-server@latest`
|
|
35
49
|
|
|
36
50
|
## Features
|
|
37
51
|
|
|
@@ -102,6 +116,10 @@ The server provides clear error messages for:
|
|
|
102
116
|
- API errors
|
|
103
117
|
- Rate limiting
|
|
104
118
|
|
|
119
|
+
## Sponsor Message
|
|
120
|
+
|
|
121
|
+
When using this server, you may occasionally see a small sponsor message with a link to this repository included in tool responses. I hope you can support the project!
|
|
122
|
+
|
|
105
123
|
## Support the Developer
|
|
106
124
|
|
|
107
125
|
If you find this project useful, please consider supporting
|
|
@@ -123,4 +141,3 @@ or brands owned by third parties. The use of such APIs or references does not im
|
|
|
123
141
|
any affiliation with or endorsement by the respective companies. All trademarks and
|
|
124
142
|
brand names are the property of their respective owners. This project is an independent
|
|
125
143
|
work and is not officially associated with or sponsored by any third-party company mentioned.
|
|
126
|
-
|
package/build/config.js
CHANGED
|
@@ -22,11 +22,14 @@ for (let i = 0; i < args.length; i++) {
|
|
|
22
22
|
const configuration = {
|
|
23
23
|
clickupApiKey: envArgs.clickupApiKey || process.env.CLICKUP_API_KEY || '',
|
|
24
24
|
clickupTeamId: envArgs.clickupTeamId || process.env.CLICKUP_TEAM_ID || '',
|
|
25
|
+
enableSponsorMessage: process.env.ENABLE_SPONSOR_MESSAGE === 'true' || false,
|
|
26
|
+
sponsorUrl: process.env.SPONSOR_URL || 'https://github.com/sponsors/taazkareem'
|
|
25
27
|
};
|
|
26
|
-
// Validate
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
.
|
|
28
|
+
// Validate only the required variables are present
|
|
29
|
+
const requiredVars = ['clickupApiKey', 'clickupTeamId'];
|
|
30
|
+
const missingEnvVars = requiredVars
|
|
31
|
+
.filter(key => !configuration[key])
|
|
32
|
+
.map(key => key);
|
|
30
33
|
if (missingEnvVars.length > 0) {
|
|
31
34
|
throw new Error(`Missing required environment variables: ${missingEnvVars.join(', ')}`);
|
|
32
35
|
}
|
package/build/index.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* Task Management:
|
|
11
11
|
* - Create, update, move and duplicate tasks with rich description support
|
|
12
12
|
* - Find tasks by name with smart disambiguation
|
|
13
|
-
* -
|
|
13
|
+
* - Optimized bulk task operations with concurrent processing
|
|
14
14
|
* - Comprehensive filtering and sorting options
|
|
15
15
|
*
|
|
16
16
|
* Workspace Organization:
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Logger } from "./logger.js";
|
|
2
|
+
// Create a logger instance
|
|
3
|
+
const logger = new Logger('MCPTools');
|
|
4
|
+
/**
|
|
5
|
+
* Register a handler for a tool that may receive JSON string parameters
|
|
6
|
+
* This wrapper ensures that array and object parameters are properly parsed
|
|
7
|
+
*
|
|
8
|
+
* @param server MCP Server instance
|
|
9
|
+
* @param name Tool name
|
|
10
|
+
* @param handler Handler function
|
|
11
|
+
*/
|
|
12
|
+
export function registerToolHandler(server, name, handler) {
|
|
13
|
+
// Create a wrapper handler that pre-processes parameters
|
|
14
|
+
const wrappedHandler = async (params) => {
|
|
15
|
+
logger.debug(`Processing parameters for tool ${name}`, { params });
|
|
16
|
+
try {
|
|
17
|
+
// Process the parameters before passing them to the actual handler
|
|
18
|
+
const processedParams = {};
|
|
19
|
+
// Process each parameter - try to parse strings that might be JSON
|
|
20
|
+
for (const [key, value] of Object.entries(params)) {
|
|
21
|
+
if (typeof value === 'string') {
|
|
22
|
+
try {
|
|
23
|
+
// Check if this might be a JSON array or object
|
|
24
|
+
if ((value.startsWith('[') && value.endsWith(']')) ||
|
|
25
|
+
(value.startsWith('{') && value.endsWith('}'))) {
|
|
26
|
+
try {
|
|
27
|
+
processedParams[key] = JSON.parse(value);
|
|
28
|
+
logger.debug(`Parsed JSON parameter: ${key}`, { original: value, parsed: processedParams[key] });
|
|
29
|
+
}
|
|
30
|
+
catch (parseError) {
|
|
31
|
+
// If parsing fails, use the original string
|
|
32
|
+
processedParams[key] = value;
|
|
33
|
+
logger.debug(`Failed to parse JSON for parameter: ${key}, using original`, { error: parseError.message });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
processedParams[key] = value;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
// If there's any error, use the original value
|
|
42
|
+
processedParams[key] = value;
|
|
43
|
+
logger.debug(`Error processing parameter: ${key}`, { error: error.message });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
// Non-string values are used as-is
|
|
48
|
+
processedParams[key] = value;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
logger.debug(`Processed parameters for tool ${name}`, { processedParams });
|
|
52
|
+
// Call the original handler with processed parameters
|
|
53
|
+
return handler(processedParams);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
logger.error(`Error in wrapped handler for tool ${name}:`, { error: error.stack || error.message });
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
// Use setRequestHandler to register the wrapped handler
|
|
61
|
+
logger.info(`Registering wrapped handler for tool: ${name}`);
|
|
62
|
+
// Override the tool's handler in the CallTool switch statement
|
|
63
|
+
// The server.ts file will use the switch case to call this handler
|
|
64
|
+
}
|
package/build/server.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
2
|
import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
3
3
|
import { workspaceHierarchyTool, handleGetWorkspaceHierarchy } from "./tools/workspace.js";
|
|
4
|
-
import { createTaskTool, handleCreateTask, updateTaskTool, handleUpdateTask, moveTaskTool, handleMoveTask, duplicateTaskTool, handleDuplicateTask, getTaskTool, getTasksTool, handleGetTasks, deleteTaskTool, handleDeleteTask, createBulkTasksTool, handleCreateBulkTasks, updateBulkTasksTool, handleUpdateBulkTasks, moveBulkTasksTool, handleMoveBulkTasks, deleteBulkTasksTool, handleDeleteBulkTasks
|
|
4
|
+
import { createTaskTool, handleCreateTask, updateTaskTool, handleUpdateTask, moveTaskTool, handleMoveTask, duplicateTaskTool, handleDuplicateTask, getTaskTool, getTasksTool, handleGetTasks, deleteTaskTool, handleDeleteTask, getTaskCommentsTool, handleGetTaskComments, createBulkTasksTool, handleCreateBulkTasks, updateBulkTasksTool, handleUpdateBulkTasks, moveBulkTasksTool, handleMoveBulkTasks, deleteBulkTasksTool, handleDeleteBulkTasks } from "./tools/task.js";
|
|
5
5
|
import { createListTool, handleCreateList, createListInFolderTool, handleCreateListInFolder, getListTool, handleGetList, updateListTool, handleUpdateList, deleteListTool, handleDeleteList } from "./tools/list.js";
|
|
6
6
|
import { createFolderTool, handleCreateFolder, getFolderTool, handleGetFolder, updateFolderTool, handleUpdateFolder, deleteFolderTool, handleDeleteFolder } from "./tools/folder.js";
|
|
7
7
|
import { Logger } from "./logger.js";
|
|
@@ -40,11 +40,11 @@ export function configureServer() {
|
|
|
40
40
|
moveTaskTool,
|
|
41
41
|
duplicateTaskTool,
|
|
42
42
|
deleteTaskTool,
|
|
43
|
+
getTaskCommentsTool,
|
|
43
44
|
createBulkTasksTool,
|
|
44
45
|
updateBulkTasksTool,
|
|
45
46
|
moveBulkTasksTool,
|
|
46
47
|
deleteBulkTasksTool,
|
|
47
|
-
getTaskCommentsTool,
|
|
48
48
|
createListTool,
|
|
49
49
|
createListInFolderTool,
|
|
50
50
|
getListTool,
|
|
@@ -87,6 +87,8 @@ export function configureServer() {
|
|
|
87
87
|
return handleGetTasks(params);
|
|
88
88
|
case "delete_task":
|
|
89
89
|
return handleDeleteTask(params);
|
|
90
|
+
case "get_task_comments":
|
|
91
|
+
return handleGetTaskComments(params);
|
|
90
92
|
case "create_bulk_tasks":
|
|
91
93
|
return handleCreateBulkTasks(params);
|
|
92
94
|
case "update_bulk_tasks":
|
|
@@ -95,8 +97,6 @@ export function configureServer() {
|
|
|
95
97
|
return handleMoveBulkTasks(params);
|
|
96
98
|
case "delete_bulk_tasks":
|
|
97
99
|
return handleDeleteBulkTasks(params);
|
|
98
|
-
case "get_task_comments":
|
|
99
|
-
return handleGetTaskComments(params);
|
|
100
100
|
case "create_list":
|
|
101
101
|
return handleCreateList(params);
|
|
102
102
|
case "create_list_in_folder":
|