@taazkareem/clickup-mcp-server 0.5.1 ā 0.6.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 +18 -18
- package/build/config.js +1 -2
- package/build/index.js +14 -29
- package/build/logger.js +29 -2
- package/build/server.js +2 -2
- package/build/services/clickup/task.js +27 -2
- package/build/tools/task/handlers.js +17 -10
- package/build/tools/task/single-operations.js +54 -46
- package/build/tools/workspace.js +6 -46
- package/build/utils/sponsor-service.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,18 +1,12 @@
|
|
|
1
|
-
<img src="
|
|
2
|
-
|
|
3
|
-
# MCP Server
|
|
1
|
+
<img src="assets/images/clickup_mcp_server_social_image.png" alt="ClickUp MCP Server" width="100%">
|
|
4
2
|
|
|
3
|
+

|
|
5
4
|
[](https://github.com/TaazKareem/clickup-mcp-server/stargazers)
|
|
6
|
-
[](https://github.com/TaazKareem/clickup-mcp-server/graphs/commit-activity)
|
|
7
6
|
|
|
8
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.
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
> š§ **Status Update:** -v0.5.1 beta release with new Attach Task Files tool, Create Task Comments tool, Get Task Comments tool, and Custom ID support across all tools.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
> š§ **Status Update:** v0.5.2 release with new Attach Task Files tool, Create Task Comments tool, Get Task Comments tool, Custom ID support across all tools, and Subtasks support.
|
|
16
10
|
|
|
17
11
|
## Setup
|
|
18
12
|
|
|
@@ -26,13 +20,13 @@ A Model Context Protocol (MCP) server for integrating ClickUp tasks with AI appl
|
|
|
26
20
|
|
|
27
21
|
[](https://smithery.ai/server/@TaazKareem/clickup-mcp-server)
|
|
28
22
|
|
|
29
|
-
The server is hosted on Smithery. 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.
|
|
30
24
|
|
|
31
25
|
|
|
32
26
|
## NPX Installation
|
|
33
27
|
|
|
34
28
|
[](https://www.npmjs.com/package/@taazkareem/clickup-mcp-server)
|
|
35
|
-
[](https://github.com/TaazKareem/clickup-mcp-server/blob/main/package.json)
|
|
36
30
|
[](https://npmcharts.com/compare/@taazkareem/clickup-mcp-server?minimal=true)
|
|
37
31
|
|
|
38
32
|
Add this entry to your client's MCP settings JSON file:
|
|
@@ -69,6 +63,7 @@ Or use this npx command:
|
|
|
69
63
|
- Get task comments
|
|
70
64
|
- Set due dates using natural language and relative time expressions
|
|
71
65
|
- Attach files to tasks using local file paths, URL, base64, or chunked uploads
|
|
66
|
+
- Create and manage subtasks with support for multi-level nesting
|
|
72
67
|
|
|
73
68
|
- š **Workspace Organization**
|
|
74
69
|
- Complete workspace hierarchy (spaces, folders, lists)
|
|
@@ -86,12 +81,12 @@ Or use this npx command:
|
|
|
86
81
|
| Tool | Description | Required Parameters |
|
|
87
82
|
|------|-------------|-------------------|
|
|
88
83
|
| [get_workspace_hierarchy](docs/api-reference.md#workspace-navigation) | Get workspace structure | None |
|
|
89
|
-
| [create_task](docs/api-reference.md#task-management) | Create a task | `name`, (`listId`/`listName`) |
|
|
84
|
+
| [create_task](docs/api-reference.md#task-management) | Create a task | `name`, (`listId`/`listName`), optional `parent` |
|
|
90
85
|
| [create_bulk_tasks](docs/api-reference.md#task-management) | Create multiple tasks | `tasks[]` |
|
|
91
86
|
| [update_task](docs/api-reference.md#task-management) | Modify task | `taskId`/`taskName` |
|
|
92
87
|
| [update_bulk_tasks](docs/api-reference.md#task-management) | Update multiple tasks | `tasks[]` with IDs or names |
|
|
93
|
-
| [get_tasks](docs/api-reference.md#task-management) | Get tasks from list | `listId`/`listName` |
|
|
94
|
-
| [get_task](docs/api-reference.md#task-management) | Get task details | `taskId`/`taskName` |
|
|
88
|
+
| [get_tasks](docs/api-reference.md#task-management) | Get tasks from list | `listId`/`listName`, optional `subtasks` |
|
|
89
|
+
| [get_task](docs/api-reference.md#task-management) | Get task details | `taskId`/`taskName`, optional `subtasks` |
|
|
95
90
|
| [get_task_comments](docs/api-reference.md#task-management) | Get comments on a task | `taskId`/`taskName` |
|
|
96
91
|
| [create_task_comment](docs/api-reference.md#task-management) | Add a comment to a task | `commentText`, (`taskId`/(`taskName`+`listName`)) |
|
|
97
92
|
| [attach_task_file](docs/api-reference.md#task-management) | Attach file to a task | `taskId`/`taskName`, (`file_data` or `file_url`) |
|
|
@@ -112,8 +107,8 @@ Or use this npx command:
|
|
|
112
107
|
|
|
113
108
|
See [full documentation](docs/api-reference.md) for optional parameters and advanced usage.
|
|
114
109
|
|
|
115
|
-
##
|
|
116
|
-
Not yet implemented
|
|
110
|
+
## Prompts
|
|
111
|
+
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:
|
|
117
112
|
|
|
118
113
|
| Prompt | Purpose | Features |
|
|
119
114
|
|--------|---------|----------|
|
|
@@ -131,6 +126,9 @@ The server provides clear error messages for:
|
|
|
131
126
|
- API errors
|
|
132
127
|
- Rate limiting
|
|
133
128
|
|
|
129
|
+
The `LOG_LEVEL` environment variable can be specified to control the verbosity of server logs. Valid values are `trace`, `debug`, `info`, `warn`, and `error` (default).
|
|
130
|
+
This can be also be specified on the command line as, e.g. `--env LOG_LEVEL=info`.
|
|
131
|
+
|
|
134
132
|
## Support the Developer
|
|
135
133
|
|
|
136
134
|
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!
|
|
@@ -138,10 +136,12 @@ If you find this project useful, please consider supporting:
|
|
|
138
136
|
|
|
139
137
|
[](https://github.com/sponsors/TaazKareem)
|
|
140
138
|
|
|
139
|
+
|
|
141
140
|
<a href="https://buymeacoffee.com/taazkareem">
|
|
142
141
|
<img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" width="200" alt="Buy Me A Coffee">
|
|
143
142
|
</a>
|
|
144
143
|
|
|
144
|
+
|
|
145
145
|
## Acknowledgements
|
|
146
146
|
|
|
147
147
|
Special thanks to [ClickUp](https://clickup.com) for their excellent API and services that make this integration possible.
|
|
@@ -158,7 +158,7 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
|
|
|
158
158
|
|
|
159
159
|
## Disclaimer
|
|
160
160
|
|
|
161
|
-
|
|
161
|
+
This software makes use of third-party APIs and may reference trademarks
|
|
162
162
|
or brands owned by third parties. The use of such APIs or references does not imply
|
|
163
163
|
any affiliation with or endorsement by the respective companies. All trademarks and
|
|
164
164
|
brand names are the property of their respective owners. This project is an independent
|
package/build/config.js
CHANGED
|
@@ -22,8 +22,7 @@ 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 !== 'false'
|
|
26
|
-
sponsorUrl: process.env.SPONSOR_URL || 'https://github.com/sponsors/taazkareem'
|
|
25
|
+
enableSponsorMessage: process.env.ENABLE_SPONSOR_MESSAGE !== 'false'
|
|
27
26
|
};
|
|
28
27
|
// Validate only the required variables are present
|
|
29
28
|
const requiredVars = ['clickupApiKey', 'clickupTeamId'];
|
package/build/index.js
CHANGED
|
@@ -1,37 +1,25 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* ClickUp MCP Server
|
|
3
|
+
* ClickUp MCP Server
|
|
4
4
|
*
|
|
5
|
-
* This server
|
|
6
|
-
*
|
|
5
|
+
* This custom server implements the Model Context Protocol (MCP) specification to enable
|
|
6
|
+
* AI applications to interact with ClickUp workspaces. It provides a standardized
|
|
7
|
+
* interface for managing tasks, lists, folders and other ClickUp entities using Natural Language.
|
|
7
8
|
*
|
|
8
|
-
* Key
|
|
9
|
+
* Key Features:
|
|
10
|
+
* - Complete task management (CRUD operations, moving, duplicating)
|
|
11
|
+
* - Workspace organization (spaces, folders, lists)
|
|
12
|
+
* - Bulk operations with concurrent processing
|
|
13
|
+
* - Natural language date parsing
|
|
14
|
+
* - File attachments support
|
|
15
|
+
* - Name-based entity resolution
|
|
16
|
+
* - Markdown formatting
|
|
17
|
+
* - Built-in rate limiting
|
|
9
18
|
*
|
|
10
|
-
*
|
|
11
|
-
* - Create, update, move and duplicate tasks with rich description support
|
|
12
|
-
* - Find tasks by name with smart disambiguation
|
|
13
|
-
* - Optimized bulk task operations with concurrent processing
|
|
14
|
-
* - Comprehensive filtering and sorting options
|
|
15
|
-
*
|
|
16
|
-
* Workspace Organization:
|
|
17
|
-
* - Navigate and discover workspace structure with hierarchical views
|
|
18
|
-
* - Create and manage lists and folders with proper nesting
|
|
19
|
-
* - Smart name-based lookups that eliminate the need for IDs
|
|
20
|
-
* - Support for priorities, statuses, and due dates
|
|
21
|
-
*
|
|
22
|
-
* Technical Features:
|
|
23
|
-
* - Full markdown support for rich text content
|
|
24
|
-
* - Secure credential handling through configuration
|
|
25
|
-
* - Comprehensive error reporting and validation
|
|
26
|
-
* - Name-based entity resolution with fuzzy matching
|
|
27
|
-
*
|
|
28
|
-
* This implementation follows the Model Context Protocol specification and
|
|
29
|
-
* is designed to be used with AI assistants that support MCP.
|
|
19
|
+
* For full documentation and usage examples, please refer to the README.md file.
|
|
30
20
|
*/
|
|
31
21
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
32
22
|
import { configureServer, server } from "./server.js";
|
|
33
|
-
import { clickUpServices } from "./services/shared.js";
|
|
34
|
-
import { initializeWorkspaceTool } from "./tools/workspace.js";
|
|
35
23
|
import { info, error, warn } from "./logger.js";
|
|
36
24
|
import { exec } from 'child_process';
|
|
37
25
|
import { promisify } from 'util';
|
|
@@ -76,9 +64,6 @@ async function main() {
|
|
|
76
64
|
os: process.platform,
|
|
77
65
|
arch: process.arch
|
|
78
66
|
});
|
|
79
|
-
// Initialize tools with services
|
|
80
|
-
info("Initializing workspace tools");
|
|
81
|
-
initializeWorkspaceTool(clickUpServices);
|
|
82
67
|
// Configure the server with all handlers
|
|
83
68
|
info("Configuring server request handlers");
|
|
84
69
|
await configureServer();
|
package/build/logger.js
CHANGED
|
@@ -24,8 +24,35 @@ export var LogLevel;
|
|
|
24
24
|
LogLevel[LogLevel["WARN"] = 3] = "WARN";
|
|
25
25
|
LogLevel[LogLevel["ERROR"] = 4] = "ERROR";
|
|
26
26
|
})(LogLevel || (LogLevel = {}));
|
|
27
|
-
//
|
|
28
|
-
const
|
|
27
|
+
// Parse LOG_LEVEL environment variable or command line argument
|
|
28
|
+
const parseLogLevel = (levelStr) => {
|
|
29
|
+
if (!levelStr)
|
|
30
|
+
return LogLevel.ERROR; // Default to ERROR if not specified
|
|
31
|
+
switch (levelStr.toUpperCase()) {
|
|
32
|
+
case 'TRACE': return LogLevel.TRACE;
|
|
33
|
+
case 'DEBUG': return LogLevel.DEBUG;
|
|
34
|
+
case 'INFO': return LogLevel.INFO;
|
|
35
|
+
case 'WARN': return LogLevel.WARN;
|
|
36
|
+
case 'ERROR': return LogLevel.ERROR;
|
|
37
|
+
default:
|
|
38
|
+
console.error(`Invalid LOG_LEVEL: ${levelStr}, defaulting to ERROR`);
|
|
39
|
+
return LogLevel.ERROR;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
// Parse command line arguments for LOG_LEVEL
|
|
43
|
+
const args = process.argv.slice(2);
|
|
44
|
+
let argLogLevel;
|
|
45
|
+
for (let i = 0; i < args.length; i++) {
|
|
46
|
+
if (args[i] === '--env' && i + 1 < args.length) {
|
|
47
|
+
const [key, value] = args[i + 1].split('=');
|
|
48
|
+
if (key === 'LOG_LEVEL')
|
|
49
|
+
argLogLevel = value;
|
|
50
|
+
i++;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Get log level from environment variable or command line, default to ERROR
|
|
54
|
+
const configuredLevel = parseLogLevel(argLogLevel || process.env.LOG_LEVEL);
|
|
55
|
+
console.debug(`Log level set to: ${LogLevel[configuredLevel]}`);
|
|
29
56
|
/**
|
|
30
57
|
* Check if a log level is enabled based on the configured level
|
|
31
58
|
* @param level The log level to check
|
package/build/server.js
CHANGED
|
@@ -15,7 +15,7 @@ const { workspace } = clickUpServices;
|
|
|
15
15
|
*/
|
|
16
16
|
export const server = new Server({
|
|
17
17
|
name: "clickup-mcp-server",
|
|
18
|
-
version: "0.
|
|
18
|
+
version: "0.6.0",
|
|
19
19
|
}, {
|
|
20
20
|
capabilities: {
|
|
21
21
|
tools: {},
|
|
@@ -61,7 +61,7 @@ export function configureServer() {
|
|
|
61
61
|
});
|
|
62
62
|
// Register CallTool handler with proper logging
|
|
63
63
|
logger.info("Registering tool handlers", {
|
|
64
|
-
toolCount:
|
|
64
|
+
toolCount: 24,
|
|
65
65
|
categories: ["workspace", "task", "list", "folder"]
|
|
66
66
|
});
|
|
67
67
|
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
@@ -204,6 +204,28 @@ export class TaskService extends BaseClickUpService {
|
|
|
204
204
|
throw this.handleError(error, `Failed to get task ${taskId}`);
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
|
+
/**
|
|
208
|
+
* Get subtasks of a specific task
|
|
209
|
+
* @param taskId The ID of the parent task
|
|
210
|
+
* @returns Array of subtask details
|
|
211
|
+
*/
|
|
212
|
+
async getSubtasks(taskId) {
|
|
213
|
+
this.logOperation('getSubtasks', { taskId });
|
|
214
|
+
try {
|
|
215
|
+
return await this.makeRequest(async () => {
|
|
216
|
+
// First, get the task to get its list ID
|
|
217
|
+
const task = await this.getTask(taskId);
|
|
218
|
+
const listId = task.list.id;
|
|
219
|
+
// Then get all tasks from the list
|
|
220
|
+
const allTasks = await this.getTasks(listId, { subtasks: true });
|
|
221
|
+
// Filter tasks that have the specified task as parent
|
|
222
|
+
return allTasks.filter(t => t.parent === taskId || t.top_level_parent === taskId);
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
throw this.handleError(error, `Failed to get subtasks of task ${taskId}`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
207
229
|
/**
|
|
208
230
|
* Get a specific task by its custom ID
|
|
209
231
|
* @param customTaskId The custom ID of the task (e.g., "DEV-1234")
|
|
@@ -214,8 +236,11 @@ export class TaskService extends BaseClickUpService {
|
|
|
214
236
|
this.logOperation('getTaskByCustomId', { customTaskId, listId });
|
|
215
237
|
try {
|
|
216
238
|
return await this.makeRequest(async () => {
|
|
217
|
-
// Build query with custom_task_ids=true
|
|
218
|
-
const params = new URLSearchParams({
|
|
239
|
+
// Build query with custom_task_ids=true and team_id
|
|
240
|
+
const params = new URLSearchParams({
|
|
241
|
+
custom_task_ids: 'true',
|
|
242
|
+
team_id: this.teamId
|
|
243
|
+
});
|
|
219
244
|
// Use the ClickUp API endpoint for retrieving tasks by ID
|
|
220
245
|
// With custom_task_ids=true parameter, it will treat the ID as a custom ID
|
|
221
246
|
const response = await this.client.get(`/task/${customTaskId}?${params.toString()}`);
|
|
@@ -83,7 +83,7 @@ async function mapTaskIds(tasks) {
|
|
|
83
83
|
* Handler for creating a task
|
|
84
84
|
*/
|
|
85
85
|
export async function createTaskHandler(params) {
|
|
86
|
-
const { name, description, markdown_description, status, dueDate } = params;
|
|
86
|
+
const { name, description, markdown_description, status, dueDate, parent } = params;
|
|
87
87
|
if (!name)
|
|
88
88
|
throw new Error("Task name is required");
|
|
89
89
|
// Use our helper function to validate and convert priority
|
|
@@ -95,7 +95,8 @@ export async function createTaskHandler(params) {
|
|
|
95
95
|
markdown_description,
|
|
96
96
|
status,
|
|
97
97
|
priority,
|
|
98
|
-
due_date: dueDate ? parseDueDate(dueDate) : undefined
|
|
98
|
+
due_date: dueDate ? parseDueDate(dueDate) : undefined,
|
|
99
|
+
parent
|
|
99
100
|
});
|
|
100
101
|
}
|
|
101
102
|
/**
|
|
@@ -131,6 +132,12 @@ export async function duplicateTaskHandler(params) {
|
|
|
131
132
|
export async function getTaskHandler(params) {
|
|
132
133
|
// resolveTaskIdWithValidation now auto-detects whether taskId is a regular ID or custom ID
|
|
133
134
|
const taskId = await getTaskId(params.taskId, params.taskName, params.listName, params.customTaskId);
|
|
135
|
+
// If subtasks parameter is provided and true, use the getTaskWithSubtasks method
|
|
136
|
+
if (params.subtasks) {
|
|
137
|
+
const task = await taskService.getTask(taskId);
|
|
138
|
+
const subtasks = await taskService.getSubtasks(taskId);
|
|
139
|
+
return { ...task, subtasks };
|
|
140
|
+
}
|
|
134
141
|
return await taskService.getTask(taskId);
|
|
135
142
|
}
|
|
136
143
|
/**
|
|
@@ -140,14 +147,6 @@ export async function getTasksHandler(params) {
|
|
|
140
147
|
const listId = await getListId(params.listId, params.listName);
|
|
141
148
|
return await taskService.getTasks(listId, buildTaskFilters(params));
|
|
142
149
|
}
|
|
143
|
-
/**
|
|
144
|
-
* Handler for deleting a task
|
|
145
|
-
*/
|
|
146
|
-
export async function deleteTaskHandler(params) {
|
|
147
|
-
const taskId = await getTaskId(params.taskId, params.taskName, params.listName);
|
|
148
|
-
await taskService.deleteTask(taskId);
|
|
149
|
-
return true;
|
|
150
|
-
}
|
|
151
150
|
/**
|
|
152
151
|
* Handler for getting task comments
|
|
153
152
|
*/
|
|
@@ -242,3 +241,11 @@ export async function deleteBulkTasksHandler(params) {
|
|
|
242
241
|
await bulkService.deleteTasks(taskIds, parseBulkOptions(params.options));
|
|
243
242
|
return taskIds.map(() => true);
|
|
244
243
|
}
|
|
244
|
+
/**
|
|
245
|
+
* Handler for deleting a task
|
|
246
|
+
*/
|
|
247
|
+
export async function deleteTaskHandler(params) {
|
|
248
|
+
const taskId = await getTaskId(params.taskId, params.taskName, params.listName);
|
|
249
|
+
await taskService.deleteTask(taskId);
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
@@ -57,7 +57,8 @@ Requirements:
|
|
|
57
57
|
|
|
58
58
|
Notes:
|
|
59
59
|
- For multiple tasks, use create_bulk_tasks instead
|
|
60
|
-
- Reuse list IDs from previous responses when possible to avoid redundant lookups
|
|
60
|
+
- Reuse list IDs from previous responses when possible to avoid redundant lookups
|
|
61
|
+
- To create a subtask, set the parent parameter to the ID of the parent task`,
|
|
61
62
|
inputSchema: {
|
|
62
63
|
type: "object",
|
|
63
64
|
properties: {
|
|
@@ -92,6 +93,10 @@ Notes:
|
|
|
92
93
|
dueDate: {
|
|
93
94
|
type: "string",
|
|
94
95
|
description: "Optional due date. Supports Unix timestamps (ms) or natural language like '1 hour from now', 'tomorrow', 'next week', etc."
|
|
96
|
+
},
|
|
97
|
+
parent: {
|
|
98
|
+
type: "string",
|
|
99
|
+
description: "Optional ID of the parent task. When specified, this task will be created as a subtask of the specified parent task."
|
|
95
100
|
}
|
|
96
101
|
}
|
|
97
102
|
}
|
|
@@ -269,7 +274,8 @@ Requirements:
|
|
|
269
274
|
Note:
|
|
270
275
|
- Task names are only unique within a list, so the system needs to know which list to search in
|
|
271
276
|
- Regular task IDs are always 9 characters long (e.g., "86b394eqa")
|
|
272
|
-
- Custom IDs have an uppercase prefix followed by a hyphen and number (e.g., "DEV-1234")
|
|
277
|
+
- Custom IDs have an uppercase prefix followed by a hyphen and number (e.g., "DEV-1234")
|
|
278
|
+
- Set subtasks=true to include all subtasks in the response`,
|
|
273
279
|
inputSchema: {
|
|
274
280
|
type: "object",
|
|
275
281
|
properties: {
|
|
@@ -288,6 +294,10 @@ Note:
|
|
|
288
294
|
customTaskId: {
|
|
289
295
|
type: "string",
|
|
290
296
|
description: "Custom task ID (e.g., 'DEV-1234'). Only use this if you want to explicitly force custom ID lookup. In most cases, you can just use taskId which auto-detects ID format."
|
|
297
|
+
},
|
|
298
|
+
subtasks: {
|
|
299
|
+
type: "boolean",
|
|
300
|
+
description: "Whether to include subtasks in the response. Set to true to retrieve full details of all subtasks."
|
|
291
301
|
}
|
|
292
302
|
},
|
|
293
303
|
required: []
|
|
@@ -322,6 +332,15 @@ Notes:
|
|
|
322
332
|
type: "string",
|
|
323
333
|
description: "Name of list to get tasks from. Only use if you don't have listId."
|
|
324
334
|
},
|
|
335
|
+
subtasks: {
|
|
336
|
+
type: "boolean",
|
|
337
|
+
description: "Include subtasks"
|
|
338
|
+
},
|
|
339
|
+
statuses: {
|
|
340
|
+
type: "array",
|
|
341
|
+
items: { type: "string" },
|
|
342
|
+
description: "Filter by status names (e.g. ['To Do', 'In Progress'])"
|
|
343
|
+
},
|
|
325
344
|
archived: {
|
|
326
345
|
type: "boolean",
|
|
327
346
|
description: "Include archived tasks"
|
|
@@ -337,55 +356,11 @@ Notes:
|
|
|
337
356
|
reverse: {
|
|
338
357
|
type: "boolean",
|
|
339
358
|
description: "Reverse sort order (descending)"
|
|
340
|
-
},
|
|
341
|
-
subtasks: {
|
|
342
|
-
type: "boolean",
|
|
343
|
-
description: "Include subtasks"
|
|
344
|
-
},
|
|
345
|
-
statuses: {
|
|
346
|
-
type: "array",
|
|
347
|
-
items: {
|
|
348
|
-
type: "string"
|
|
349
|
-
},
|
|
350
|
-
description: "Filter by status names (e.g. ['To Do', 'In Progress'])"
|
|
351
359
|
}
|
|
352
360
|
},
|
|
353
361
|
required: []
|
|
354
362
|
}
|
|
355
363
|
};
|
|
356
|
-
/**
|
|
357
|
-
* Tool definition for deleting a task
|
|
358
|
-
*/
|
|
359
|
-
export const deleteTaskTool = {
|
|
360
|
-
name: "delete_task",
|
|
361
|
-
description: `Purpose: PERMANENTLY DELETE a task.
|
|
362
|
-
|
|
363
|
-
Valid Usage:
|
|
364
|
-
1. Use taskId alone (preferred and safest)
|
|
365
|
-
2. Use taskName + optional listName
|
|
366
|
-
|
|
367
|
-
Warning:
|
|
368
|
-
- This action CANNOT be undone
|
|
369
|
-
- Using taskName is risky as names may not be unique
|
|
370
|
-
- Provide listName when using taskName for more precise targeting`,
|
|
371
|
-
inputSchema: {
|
|
372
|
-
type: "object",
|
|
373
|
-
properties: {
|
|
374
|
-
taskId: {
|
|
375
|
-
type: "string",
|
|
376
|
-
description: "ID of task to delete (preferred). Works with both regular task IDs (9 characters) and custom IDs with uppercase prefixes (like 'DEV-1234')."
|
|
377
|
-
},
|
|
378
|
-
taskName: {
|
|
379
|
-
type: "string",
|
|
380
|
-
description: "Name of task to delete. Use with extreme caution as names may not be unique."
|
|
381
|
-
},
|
|
382
|
-
listName: {
|
|
383
|
-
type: "string",
|
|
384
|
-
description: "Name of list containing the task. Helps ensure correct task deletion when using taskName."
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
};
|
|
389
364
|
/**
|
|
390
365
|
* Tool definition for retrieving task comments
|
|
391
366
|
*/
|
|
@@ -477,3 +452,36 @@ Notes:
|
|
|
477
452
|
required: ["commentText"]
|
|
478
453
|
}
|
|
479
454
|
};
|
|
455
|
+
/**
|
|
456
|
+
* Tool definition for deleting a task
|
|
457
|
+
*/
|
|
458
|
+
export const deleteTaskTool = {
|
|
459
|
+
name: "delete_task",
|
|
460
|
+
description: `Purpose: PERMANENTLY DELETE a task.
|
|
461
|
+
|
|
462
|
+
Valid Usage:
|
|
463
|
+
1. Use taskId alone (preferred and safest)
|
|
464
|
+
2. Use taskName + optional listName
|
|
465
|
+
|
|
466
|
+
Warning:
|
|
467
|
+
- This action CANNOT be undone
|
|
468
|
+
- Using taskName is risky as names may not be unique
|
|
469
|
+
- Provide listName when using taskName for more precise targeting`,
|
|
470
|
+
inputSchema: {
|
|
471
|
+
type: "object",
|
|
472
|
+
properties: {
|
|
473
|
+
taskId: {
|
|
474
|
+
type: "string",
|
|
475
|
+
description: "ID of task to delete (preferred). Works with both regular task IDs (9 characters) and custom IDs with uppercase prefixes (like 'DEV-1234')."
|
|
476
|
+
},
|
|
477
|
+
taskName: {
|
|
478
|
+
type: "string",
|
|
479
|
+
description: "Name of task to delete. Use with extreme caution as names may not be unique."
|
|
480
|
+
},
|
|
481
|
+
listName: {
|
|
482
|
+
type: "string",
|
|
483
|
+
description: "Name of list containing the task. Helps ensure correct task deletion when using taskName."
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
};
|
package/build/tools/workspace.js
CHANGED
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { Logger } from '../logger.js';
|
|
8
8
|
import { sponsorService } from '../utils/sponsor-service.js';
|
|
9
|
+
import { clickUpServices } from '../services/shared.js';
|
|
9
10
|
// Create a logger for workspace tools
|
|
10
11
|
const logger = new Logger('WorkspaceTool');
|
|
11
|
-
// Use the workspace service
|
|
12
|
-
|
|
13
|
-
let workspaceService;
|
|
12
|
+
// Use the workspace service from the shared services
|
|
13
|
+
const { workspace: workspaceService } = clickUpServices;
|
|
14
14
|
/**
|
|
15
15
|
* Tool definition for retrieving the complete workspace hierarchy
|
|
16
16
|
*/
|
|
@@ -33,20 +33,6 @@ Notes:
|
|
|
33
33
|
properties: {}
|
|
34
34
|
}
|
|
35
35
|
};
|
|
36
|
-
/**
|
|
37
|
-
* Initialize the tool with services
|
|
38
|
-
*/
|
|
39
|
-
export function initializeWorkspaceTool(services) {
|
|
40
|
-
logger.info('Initializing workspace tool');
|
|
41
|
-
if (!services || !services.workspace) {
|
|
42
|
-
logger.error('Failed to initialize workspace tool: services not provided');
|
|
43
|
-
throw new Error('Workspace service not available');
|
|
44
|
-
}
|
|
45
|
-
workspaceService = services.workspace;
|
|
46
|
-
logger.info('Workspace tool initialized successfully', {
|
|
47
|
-
serviceType: workspaceService.constructor.name
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
36
|
/**
|
|
51
37
|
* Handler for the get_workspace_hierarchy tool
|
|
52
38
|
*/
|
|
@@ -56,40 +42,13 @@ export async function handleGetWorkspaceHierarchy() {
|
|
|
56
42
|
const hierarchy = await workspaceService.getWorkspaceHierarchy();
|
|
57
43
|
// Generate tree representation
|
|
58
44
|
const treeOutput = formatTreeOutput(hierarchy);
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}, true);
|
|
45
|
+
// Use sponsor service to create the response with optional sponsor message
|
|
46
|
+
return sponsorService.createResponse({ hierarchy: treeOutput }, true);
|
|
62
47
|
}
|
|
63
48
|
catch (error) {
|
|
64
49
|
return sponsorService.createErrorResponse(`Error getting workspace hierarchy: ${error.message}`);
|
|
65
50
|
}
|
|
66
51
|
}
|
|
67
|
-
/**
|
|
68
|
-
* Format the hierarchy for the response
|
|
69
|
-
*/
|
|
70
|
-
function formatHierarchyResponse(hierarchy) {
|
|
71
|
-
try {
|
|
72
|
-
const treeOutput = formatTreeOutput(hierarchy);
|
|
73
|
-
return {
|
|
74
|
-
content: [
|
|
75
|
-
{
|
|
76
|
-
type: "text",
|
|
77
|
-
text: treeOutput
|
|
78
|
-
}
|
|
79
|
-
]
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
catch (error) {
|
|
83
|
-
return {
|
|
84
|
-
content: [
|
|
85
|
-
{
|
|
86
|
-
type: "text",
|
|
87
|
-
text: `Error formatting workspace hierarchy: ${error.message}`
|
|
88
|
-
}
|
|
89
|
-
]
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
52
|
/**
|
|
94
53
|
* Format the hierarchy as a tree string
|
|
95
54
|
*/
|
|
@@ -114,5 +73,6 @@ function formatTreeOutput(hierarchy) {
|
|
|
114
73
|
};
|
|
115
74
|
// Generate tree representation
|
|
116
75
|
const treeLines = formatNodeAsTree(hierarchy.root);
|
|
76
|
+
// Return plain text instead of adding code block markers
|
|
117
77
|
return treeLines.join('\n');
|
|
118
78
|
}
|
|
@@ -12,8 +12,8 @@ const logger = new Logger('SponsorService');
|
|
|
12
12
|
*/
|
|
13
13
|
export class SponsorService {
|
|
14
14
|
constructor() {
|
|
15
|
+
this.sponsorUrl = 'https://github.com/sponsors/taazkareem';
|
|
15
16
|
this.isEnabled = config.enableSponsorMessage;
|
|
16
|
-
this.sponsorUrl = config.sponsorUrl;
|
|
17
17
|
logger.info('SponsorService initialized', { enabled: this.isEnabled });
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
@@ -56,7 +56,7 @@ export class SponsorService {
|
|
|
56
56
|
if (this.isEnabled && includeSponsorMessage) {
|
|
57
57
|
content.push({
|
|
58
58
|
type: "text",
|
|
59
|
-
text:
|
|
59
|
+
text: `⯠Support this project by sponsoring the developer at ${this.sponsorUrl}`
|
|
60
60
|
});
|
|
61
61
|
}
|
|
62
62
|
return { content };
|
package/package.json
CHANGED