@alanse/clickup-multi-mcp-server 1.0.0 → 1.0.2
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 +108 -35
- package/build/config.js +3 -1
- package/build/server.js +21 -3
- package/build/server.log +1 -0
- package/build/services/clickup/task/task-core.js +99 -0
- package/build/services/shared.js +3 -0
- package/build/tools/task/handlers.js +86 -0
- package/build/tools/task/index.js +2 -2
- package/build/tools/task/single-operations.js +139 -0
- package/build/tools/workspace-helper.js +4 -1
- package/build/tools/workspace.js +46 -0
- package/build/utils/sponsor-service.js +14 -31
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,9 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/images/clickup-social.png" alt="ClickUp Multi-Workspace MCP Server" width="100%">
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
[](https://www.npmjs.com/package/@alanse/clickup-multi-mcp-server)
|
|
5
|
+
<h1 align="center">ClickUp Multi-Workspace MCP Server</h1>
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://github.com/da-okazaki/clickup-multi-mcp-server/stargazers">
|
|
9
|
+
<img src="https://img.shields.io/github/stars/da-okazaki/clickup-multi-mcp-server?style=flat&logo=github" alt="GitHub Stars">
|
|
10
|
+
</a>
|
|
11
|
+
<a href="https://www.npmjs.com/package/@alanse/clickup-multi-mcp-server">
|
|
12
|
+
<img src="https://img.shields.io/npm/v/@alanse/clickup-multi-mcp-server.svg?style=flat&logo=npm" alt="NPM Version">
|
|
13
|
+
</a>
|
|
14
|
+
</p>
|
|
15
|
+
|
|
16
|
+
<p align="center">
|
|
17
|
+
A Model Context Protocol (MCP) server for integrating <strong>multiple ClickUp workspaces</strong> with AI applications. This server allows AI agents to interact with tasks, spaces, lists, and folders across different ClickUp workspaces through a standardized protocol.
|
|
18
|
+
</p>
|
|
7
19
|
|
|
8
20
|
## 🎯 Key Feature: Multi-Workspace Support
|
|
9
21
|
|
|
@@ -22,6 +34,27 @@ Based on the excellent [clickup-mcp-server](https://github.com/taazkareem/clicku
|
|
|
22
34
|
|
|
23
35
|
## Quick Start
|
|
24
36
|
|
|
37
|
+
### Claude Code CLI Setup
|
|
38
|
+
|
|
39
|
+
The easiest way to add this MCP server to Claude Code:
|
|
40
|
+
|
|
41
|
+
**Single Workspace:**
|
|
42
|
+
```bash
|
|
43
|
+
claude mcp add clickup \
|
|
44
|
+
-e CLICKUP_API_KEY=your_api_key_here \
|
|
45
|
+
-e CLICKUP_TEAM_ID=your_team_id_here \
|
|
46
|
+
-- npx -y @alanse/clickup-multi-mcp-server@latest
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Multiple Workspaces:**
|
|
50
|
+
```bash
|
|
51
|
+
claude mcp add clickup \
|
|
52
|
+
-e CLICKUP_WORKSPACES='{"default":"work","workspaces":{"work":{"token":"pk_xxx_work","teamId":"123456"},"personal":{"token":"pk_xxx_personal","teamId":"789012"}}}' \
|
|
53
|
+
-- npx -y @alanse/clickup-multi-mcp-server@latest
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Manual Configuration
|
|
57
|
+
|
|
25
58
|
### Single Workspace (Backwards Compatible)
|
|
26
59
|
|
|
27
60
|
The traditional single workspace setup still works exactly as before:
|
|
@@ -145,17 +178,77 @@ await getTasks({ workspace: "personal", list_id: "987654321" });
|
|
|
145
178
|
await getWorkspaceHierarchy({ workspace: "work" });
|
|
146
179
|
```
|
|
147
180
|
|
|
181
|
+
## Local Development Setup
|
|
182
|
+
|
|
183
|
+
For local development or when running the server directly from source code:
|
|
184
|
+
|
|
185
|
+
### 1. Clone and Install
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
git clone https://github.com/da-okazaki/clickup-multi-mcp-server.git
|
|
189
|
+
cd clickup-multi-mcp-server
|
|
190
|
+
npm install
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### 2. Configure Environment Variables
|
|
194
|
+
|
|
195
|
+
Copy `.env.example` to `.env` and configure your ClickUp credentials:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
cp .env.example .env
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Edit `.env` file:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
# Multi-workspace configuration
|
|
205
|
+
CLICKUP_WORKSPACES={"default":"alanse","workspaces":{"alanse":{"token":"pk_YOUR_TOKEN_1","teamId":"YOUR_TEAM_ID_1","description":"Alanse workspace"},"potz":{"token":"pk_YOUR_TOKEN_2","teamId":"YOUR_TEAM_ID_2","description":"Potz workspace"}}}
|
|
206
|
+
|
|
207
|
+
# Or use single workspace (legacy)
|
|
208
|
+
# CLICKUP_API_KEY=your_api_key_here
|
|
209
|
+
# CLICKUP_TEAM_ID=your_team_id_here
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**Note**: The `.env` file is automatically loaded when the server starts. Environment variables in `.env` are automatically picked up without needing to pass them via command line.
|
|
213
|
+
|
|
214
|
+
### 3. Build and Run
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
# Build the project
|
|
218
|
+
npm run build
|
|
219
|
+
|
|
220
|
+
# Run locally
|
|
221
|
+
node build/index.js
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### 4. Configure Claude Code for Local Development
|
|
225
|
+
|
|
226
|
+
If you want to use your local build with Claude Code, update `~/.claude.json`:
|
|
227
|
+
|
|
228
|
+
```json
|
|
229
|
+
{
|
|
230
|
+
"mcpServers": {
|
|
231
|
+
"clickup": {
|
|
232
|
+
"type": "stdio",
|
|
233
|
+
"command": "node",
|
|
234
|
+
"args": ["/absolute/path/to/clickup-multi-mcp-server/build/index.js"]
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**Important**: When using local build with Claude Code:
|
|
241
|
+
- Environment variables are loaded from `.env` file in the project root
|
|
242
|
+
- No need to specify `env` in `~/.claude.json` (unless you want to override `.env` values)
|
|
243
|
+
- Rebuild after making changes: `npm run build`
|
|
244
|
+
|
|
148
245
|
## Smithery Installation (Quick Start)
|
|
149
246
|
|
|
150
247
|
[](https://smithery.ai/server/@TaazKareem/clickup-mcp-server)
|
|
151
248
|
|
|
152
249
|
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.
|
|
153
250
|
|
|
154
|
-
## NPX Installation
|
|
155
251
|
|
|
156
|
-
[](https://www.npmjs.com/package/@taazkareem/clickup-mcp-server)
|
|
157
|
-
[](https://github.com/TaazKareem/clickup-mcp-server/blob/main/package.json)
|
|
158
|
-
[](https://npmcharts.com/compare/@taazkareem/clickup-mcp-server?minimal=true)
|
|
159
252
|
|
|
160
253
|
Add this entry to your client's MCP settings JSON file:
|
|
161
254
|
|
|
@@ -335,11 +428,12 @@ npm run sse-client
|
|
|
335
428
|
| ⚡ **Integration Features** | 🏗️ **Architecture & Performance** |
|
|
336
429
|
| • 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 | • **70% codebase reduction** for improved performance<br>• **Unified architecture** across all transport types<br>• **Zero code duplication**<br>• **HTTP Streamable transport** (MCP Inspector compatible)<br>• **Legacy SSE support** for backwards compatibility |
|
|
337
430
|
|
|
338
|
-
## Available Tools (
|
|
431
|
+
## Available Tools (42 Total)
|
|
339
432
|
|
|
340
433
|
| Tool | Description | Required Parameters |
|
|
341
434
|
| ------------------------------------------------------------------ | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
|
|
342
435
|
| [get_workspace_hierarchy](docs/user-guide.md#workspace-navigation) | Get workspace structure | None |
|
|
436
|
+
| [get_available_workspaces](docs/user-guide.md#workspace-navigation) | Get all available workspaces | None |
|
|
343
437
|
| [create_task](docs/user-guide.md#task-management) | Create a task | `name`, (`listId`/`listName`) |
|
|
344
438
|
| [create_bulk_tasks](docs/user-guide.md#task-management) | Create multiple tasks | `tasks[]` |
|
|
345
439
|
| [update_task](docs/user-guide.md#task-management) | Modify task | `taskId`/`taskName` |
|
|
@@ -355,6 +449,11 @@ npm run sse-client
|
|
|
355
449
|
| [move_task](docs/user-guide.md#task-management) | Move task | `taskId`/`taskName`, `listId`/`listName` |
|
|
356
450
|
| [move_bulk_tasks](docs/user-guide.md#task-management) | Move multiple tasks | `tasks[]` with IDs or names, target list |
|
|
357
451
|
| [duplicate_task](docs/user-guide.md#task-management) | Copy task | `taskId`/`taskName`, `listId`/`listName` |
|
|
452
|
+
| [merge_task](docs/user-guide.md#task-management) | Merge two tasks | `taskId`, `mergeFromId` |
|
|
453
|
+
| [get_task_time_in_status](docs/user-guide.md#task-management) | Get time in status for a task | `taskId`/`taskName` |
|
|
454
|
+
| [get_bulk_tasks_time_in_status](docs/user-guide.md#task-management)| Get bulk time in status | `taskIds[]` |
|
|
455
|
+
| [add_task_to_list](docs/user-guide.md#list-management) | Add task to additional list | `listId`, `taskId` |
|
|
456
|
+
| [remove_task_from_list](docs/user-guide.md#list-management) | Remove task from list | `listId`, `taskId` |
|
|
358
457
|
| [create_list](docs/user-guide.md#list-management) | Create list in space | `name`, `spaceId`/`spaceName` |
|
|
359
458
|
| [create_folder](docs/user-guide.md#folder-management) | Create folder | `name`, `spaceId`/`spaceName` |
|
|
360
459
|
| [create_list_in_folder](docs/user-guide.md#list-management) | Create list in folder | `name`, `folderId`/`folderName` |
|
|
@@ -436,35 +535,9 @@ The server provides clear error messages for:
|
|
|
436
535
|
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).
|
|
437
536
|
This can be also be specified on the command line as, e.g. `--env LOG_LEVEL=info`.
|
|
438
537
|
|
|
439
|
-
## Support the Developer
|
|
440
|
-
|
|
441
|
-
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!
|
|
442
|
-
If you find this project useful, please consider supporting:
|
|
443
|
-
|
|
444
|
-
[](https://github.com/sponsors/TaazKareem)
|
|
445
|
-
|
|
446
|
-
<a href="https://buymeacoffee.com/taazkareem">
|
|
447
|
-
<img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" width="200" alt="Buy Me A Coffee">
|
|
448
|
-
</a>
|
|
449
|
-
|
|
450
|
-
## Acknowledgements
|
|
451
|
-
|
|
452
|
-
Special thanks to [ClickUp](https://clickup.com) for their excellent API and services that make this integration possible.
|
|
453
|
-
|
|
454
|
-
## Contributing
|
|
455
|
-
|
|
456
|
-
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
457
538
|
|
|
458
539
|
## License
|
|
459
540
|
|
|
460
541
|
[](https://opensource.org/licenses/MIT)
|
|
461
542
|
|
|
462
543
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
463
|
-
|
|
464
|
-
## Disclaimer
|
|
465
|
-
|
|
466
|
-
This software makes use of third-party APIs and may reference trademarks
|
|
467
|
-
or brands owned by third parties. The use of such APIs or references does not imply
|
|
468
|
-
any affiliation with or endorsement by the respective companies. All trademarks and
|
|
469
|
-
brand names are the property of their respective owners. This project is an independent
|
|
470
|
-
work and is not officially associated with or sponsored by any third-party company mentioned.
|
package/build/config.js
CHANGED
|
@@ -21,6 +21,9 @@
|
|
|
21
21
|
* - SSE_PORT: Port for SSE server (default: 3000)
|
|
22
22
|
* - ENABLE_STDIO: Enable STDIO transport (default: true)
|
|
23
23
|
*/
|
|
24
|
+
// Load environment variables from .env file
|
|
25
|
+
import dotenv from 'dotenv';
|
|
26
|
+
dotenv.config();
|
|
24
27
|
// Parse any command line environment arguments
|
|
25
28
|
const args = process.argv.slice(2);
|
|
26
29
|
const envArgs = {};
|
|
@@ -125,7 +128,6 @@ const configuration = {
|
|
|
125
128
|
clickupApiKey: envArgs.clickupApiKey || process.env.CLICKUP_API_KEY || '',
|
|
126
129
|
clickupTeamId: envArgs.clickupTeamId || process.env.CLICKUP_TEAM_ID || '',
|
|
127
130
|
clickupWorkspaces: parseWorkspaces(),
|
|
128
|
-
enableSponsorMessage: process.env.ENABLE_SPONSOR_MESSAGE !== 'false',
|
|
129
131
|
documentSupport: envArgs.documentSupport || process.env.DOCUMENT_SUPPORT || process.env.DOCUMENT_MODULE || process.env.DOCUMENT_MODEL || 'false',
|
|
130
132
|
logLevel: parseLogLevel(envArgs.logLevel || process.env.LOG_LEVEL),
|
|
131
133
|
disabledTools: ((envArgs.disabledTools || process.env.DISABLED_TOOLS || process.env.DISABLED_COMMANDS)?.split(',').map(cmd => cmd.trim()).filter(cmd => cmd !== '') || []),
|
package/build/server.js
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
8
8
|
import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, ListResourcesRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
9
9
|
import config from "./config.js";
|
|
10
|
-
import { workspaceHierarchyTool, handleGetWorkspaceHierarchy } from "./tools/workspace.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";
|
|
10
|
+
import { workspaceHierarchyTool, handleGetWorkspaceHierarchy, availableWorkspacesTool, handleGetAvailableWorkspaces } from "./tools/workspace.js";
|
|
11
|
+
import { createTaskTool, updateTaskTool, moveTaskTool, duplicateTaskTool, getTaskTool, deleteTaskTool, getTaskCommentsTool, createTaskCommentTool, createBulkTasksTool, updateBulkTasksTool, moveBulkTasksTool, deleteBulkTasksTool, attachTaskFileTool, getWorkspaceTasksTool, getTaskTimeEntriesTool, startTimeTrackingTool, stopTimeTrackingTool, addTimeEntryTool, deleteTimeEntryTool, getCurrentTimeEntryTool, mergeTaskTool, getTimeInStatusTool, getBulkTimeInStatusTool, addTaskToListTool, removeTaskFromListTool, handleCreateTask, handleUpdateTask, handleMoveTask, handleDuplicateTask, handleDeleteTask, handleGetTaskComments, handleCreateTaskComment, handleCreateBulkTasks, handleUpdateBulkTasks, handleMoveBulkTasks, handleDeleteBulkTasks, handleGetTask, handleAttachTaskFile, handleGetWorkspaceTasks, handleGetTaskTimeEntries, handleStartTimeTracking, handleStopTimeTracking, handleAddTimeEntry, handleDeleteTimeEntry, handleGetCurrentTimeEntry, mergeTaskHandler, getTimeInStatusHandler, getBulkTimeInStatusHandler, addTaskToListHandler, removeTaskFromListHandler } from "./tools/task/index.js";
|
|
12
12
|
import { createListTool, handleCreateList, createListInFolderTool, handleCreateListInFolder, getListTool, handleGetList, updateListTool, handleUpdateList, deleteListTool, handleDeleteList } from "./tools/list.js";
|
|
13
13
|
import { createFolderTool, handleCreateFolder, getFolderTool, handleGetFolder, updateFolderTool, handleUpdateFolder, deleteFolderTool, handleDeleteFolder } from "./tools/folder.js";
|
|
14
14
|
import { getSpaceTagsTool, handleGetSpaceTags, addTagToTaskTool, handleAddTagToTask, removeTagFromTaskTool, handleRemoveTagFromTask } from "./tools/tag.js";
|
|
@@ -81,6 +81,7 @@ export function configureServer() {
|
|
|
81
81
|
// Collect all tool definitions
|
|
82
82
|
const allTools = [
|
|
83
83
|
workspaceHierarchyTool,
|
|
84
|
+
availableWorkspacesTool,
|
|
84
85
|
createTaskTool,
|
|
85
86
|
getTaskTool,
|
|
86
87
|
updateTaskTool,
|
|
@@ -101,6 +102,11 @@ export function configureServer() {
|
|
|
101
102
|
addTimeEntryTool,
|
|
102
103
|
deleteTimeEntryTool,
|
|
103
104
|
getCurrentTimeEntryTool,
|
|
105
|
+
mergeTaskTool,
|
|
106
|
+
getTimeInStatusTool,
|
|
107
|
+
getBulkTimeInStatusTool,
|
|
108
|
+
addTaskToListTool,
|
|
109
|
+
removeTaskFromListTool,
|
|
104
110
|
createListTool,
|
|
105
111
|
createListInFolderTool,
|
|
106
112
|
getListTool,
|
|
@@ -156,7 +162,9 @@ export function configureServer() {
|
|
|
156
162
|
// Handle tool calls by routing to the appropriate handler
|
|
157
163
|
switch (name) {
|
|
158
164
|
case "get_workspace_hierarchy":
|
|
159
|
-
return handleGetWorkspaceHierarchy();
|
|
165
|
+
return handleGetWorkspaceHierarchy(params);
|
|
166
|
+
case "get_available_workspaces":
|
|
167
|
+
return handleGetAvailableWorkspaces();
|
|
160
168
|
case "create_task":
|
|
161
169
|
return handleCreateTask(params);
|
|
162
170
|
case "update_task":
|
|
@@ -221,6 +229,16 @@ export function configureServer() {
|
|
|
221
229
|
return handleDeleteTimeEntry(params);
|
|
222
230
|
case "get_current_time_entry":
|
|
223
231
|
return handleGetCurrentTimeEntry(params);
|
|
232
|
+
case "merge_task":
|
|
233
|
+
return mergeTaskHandler(params);
|
|
234
|
+
case "get_task_time_in_status":
|
|
235
|
+
return getTimeInStatusHandler(params);
|
|
236
|
+
case "get_bulk_tasks_time_in_status":
|
|
237
|
+
return getBulkTimeInStatusHandler(params);
|
|
238
|
+
case "add_task_to_list":
|
|
239
|
+
return addTaskToListHandler(params);
|
|
240
|
+
case "remove_task_from_list":
|
|
241
|
+
return removeTaskFromListHandler(params);
|
|
224
242
|
case "create_document":
|
|
225
243
|
return handleCreateDocument(params);
|
|
226
244
|
case "get_document":
|
package/build/server.log
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Logging initialized to /Users/daichiokazaki/Documents/project/alanse/clickup-multi-mcp-server/build/server.log
|
|
@@ -601,4 +601,103 @@ export class TaskServiceCore extends BaseClickUpService {
|
|
|
601
601
|
});
|
|
602
602
|
this.logger.debug('Cached task name to ID mapping', { taskName, taskId, listId });
|
|
603
603
|
}
|
|
604
|
+
/**
|
|
605
|
+
* Merge two tasks together
|
|
606
|
+
* @param taskId ID of the task to merge into (destination)
|
|
607
|
+
* @param data Merge configuration including merge_from_id
|
|
608
|
+
* @returns The merged task
|
|
609
|
+
*/
|
|
610
|
+
async mergeTask(taskId, data) {
|
|
611
|
+
try {
|
|
612
|
+
this.logOperation('mergeTask', { taskId, ...data });
|
|
613
|
+
const path = `/task/${taskId}/merge`;
|
|
614
|
+
this.traceRequest('POST', path, data);
|
|
615
|
+
return await this.makeRequest(async () => {
|
|
616
|
+
const response = await this.client.post(path, data);
|
|
617
|
+
return response.data;
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
catch (error) {
|
|
621
|
+
throw this.handleError(error, `Failed to merge task ${taskId}`);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* Get time in status for a task
|
|
626
|
+
* @param taskId ID of the task
|
|
627
|
+
* @returns Time in status data
|
|
628
|
+
*/
|
|
629
|
+
async getTimeInStatus(taskId) {
|
|
630
|
+
try {
|
|
631
|
+
this.logOperation('getTimeInStatus', { taskId });
|
|
632
|
+
const path = `/task/${taskId}/time_in_status`;
|
|
633
|
+
this.traceRequest('GET', path);
|
|
634
|
+
return await this.makeRequest(async () => {
|
|
635
|
+
const response = await this.client.get(path);
|
|
636
|
+
return response.data;
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
catch (error) {
|
|
640
|
+
throw this.handleError(error, `Failed to get time in status for task ${taskId}`);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Get time in status for multiple tasks
|
|
645
|
+
* @param taskIds Array of task IDs
|
|
646
|
+
* @returns Bulk time in status data
|
|
647
|
+
*/
|
|
648
|
+
async getBulkTimeInStatus(taskIds) {
|
|
649
|
+
try {
|
|
650
|
+
this.logOperation('getBulkTimeInStatus', { taskIds, count: taskIds.length });
|
|
651
|
+
// Convert array to query string: ?task_ids=id1&task_ids=id2
|
|
652
|
+
const queryParams = taskIds.map(id => `task_ids=${id}`).join('&');
|
|
653
|
+
const path = `/task/bulk_time_in_status/task_ids?${queryParams}`;
|
|
654
|
+
this.traceRequest('GET', path);
|
|
655
|
+
return await this.makeRequest(async () => {
|
|
656
|
+
const response = await this.client.get(path);
|
|
657
|
+
return response.data;
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
catch (error) {
|
|
661
|
+
throw this.handleError(error, `Failed to get bulk time in status`);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
/**
|
|
665
|
+
* Add a task to an additional list (multiple list membership)
|
|
666
|
+
* @param listId ID of the list to add the task to
|
|
667
|
+
* @param taskId ID of the task to add
|
|
668
|
+
* @returns The updated task
|
|
669
|
+
*/
|
|
670
|
+
async addTaskToList(listId, taskId) {
|
|
671
|
+
try {
|
|
672
|
+
this.logOperation('addTaskToList', { listId, taskId });
|
|
673
|
+
const path = `/list/${listId}/task/${taskId}`;
|
|
674
|
+
this.traceRequest('POST', path);
|
|
675
|
+
return await this.makeRequest(async () => {
|
|
676
|
+
const response = await this.client.post(path);
|
|
677
|
+
return response.data;
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
catch (error) {
|
|
681
|
+
throw this.handleError(error, `Failed to add task ${taskId} to list ${listId}`);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* Remove a task from a list
|
|
686
|
+
* @param listId ID of the list to remove the task from
|
|
687
|
+
* @param taskId ID of the task to remove
|
|
688
|
+
* @returns Success indicator
|
|
689
|
+
*/
|
|
690
|
+
async removeTaskFromList(listId, taskId) {
|
|
691
|
+
try {
|
|
692
|
+
this.logOperation('removeTaskFromList', { listId, taskId });
|
|
693
|
+
const path = `/list/${listId}/task/${taskId}`;
|
|
694
|
+
this.traceRequest('DELETE', path);
|
|
695
|
+
await this.makeRequest(async () => {
|
|
696
|
+
await this.client.delete(path);
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
catch (error) {
|
|
700
|
+
throw this.handleError(error, `Failed to remove task ${taskId} from list ${listId}`);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
604
703
|
}
|
package/build/services/shared.js
CHANGED
|
@@ -21,12 +21,15 @@ const workspaceServicesMap = new Map();
|
|
|
21
21
|
*/
|
|
22
22
|
export function getClickUpServices(workspaceId) {
|
|
23
23
|
const wsId = workspaceId || getDefaultWorkspace();
|
|
24
|
+
console.error('[DEBUG] getClickUpServices called with workspaceId:', workspaceId);
|
|
25
|
+
console.error('[DEBUG] Resolved workspace ID:', wsId);
|
|
24
26
|
// Check if services already exist for this workspace
|
|
25
27
|
let services = workspaceServicesMap.get(wsId);
|
|
26
28
|
if (!services) {
|
|
27
29
|
logger.info(`Creating ClickUp services for workspace: ${wsId}`);
|
|
28
30
|
// Get workspace configuration
|
|
29
31
|
const workspaceConfig = getWorkspaceConfig(wsId);
|
|
32
|
+
console.error('[DEBUG] Workspace config:', JSON.stringify(workspaceConfig));
|
|
30
33
|
// Create the services instance
|
|
31
34
|
services = createClickUpServices({
|
|
32
35
|
apiKey: workspaceConfig.token,
|
|
@@ -15,6 +15,7 @@ import { validateTaskIdentification, validateListIdentification, validateTaskUpd
|
|
|
15
15
|
import { handleResolveAssignees } from '../member.js';
|
|
16
16
|
import { isNameMatch } from '../../utils/resolver-utils.js';
|
|
17
17
|
import { Logger } from '../../logger.js';
|
|
18
|
+
import { sponsorService } from '../../utils/sponsor-service.js';
|
|
18
19
|
// Use default workspace services for backwards compatibility
|
|
19
20
|
const defaultServices = getClickUpServices();
|
|
20
21
|
const { task: taskService, list: listService, workspace: workspaceService } = defaultServices;
|
|
@@ -917,3 +918,88 @@ export async function deleteTaskHandler(params) {
|
|
|
917
918
|
await taskService.deleteTask(taskId);
|
|
918
919
|
return true;
|
|
919
920
|
}
|
|
921
|
+
/**
|
|
922
|
+
* Handler for merging two tasks
|
|
923
|
+
*/
|
|
924
|
+
export async function mergeTaskHandler(params) {
|
|
925
|
+
try {
|
|
926
|
+
const { taskId, mergeFromId } = params;
|
|
927
|
+
if (!taskId || !mergeFromId) {
|
|
928
|
+
throw new Error('taskId and mergeFromId are required');
|
|
929
|
+
}
|
|
930
|
+
const result = await taskService.mergeTask(taskId, {
|
|
931
|
+
merge_from_id: mergeFromId
|
|
932
|
+
});
|
|
933
|
+
return sponsorService.createResponse(result, true);
|
|
934
|
+
}
|
|
935
|
+
catch (error) {
|
|
936
|
+
return sponsorService.createErrorResponse(error, params);
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
/**
|
|
940
|
+
* Handler for getting time in status for a task
|
|
941
|
+
*/
|
|
942
|
+
export async function getTimeInStatusHandler(params) {
|
|
943
|
+
try {
|
|
944
|
+
const { taskId } = params;
|
|
945
|
+
if (!taskId) {
|
|
946
|
+
throw new Error('taskId is required');
|
|
947
|
+
}
|
|
948
|
+
const result = await taskService.getTimeInStatus(taskId);
|
|
949
|
+
return sponsorService.createResponse(result, true);
|
|
950
|
+
}
|
|
951
|
+
catch (error) {
|
|
952
|
+
return sponsorService.createErrorResponse(error, params);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
/**
|
|
956
|
+
* Handler for getting time in status for multiple tasks
|
|
957
|
+
*/
|
|
958
|
+
export async function getBulkTimeInStatusHandler(params) {
|
|
959
|
+
try {
|
|
960
|
+
const { taskIds } = params;
|
|
961
|
+
if (!taskIds || !Array.isArray(taskIds) || taskIds.length === 0) {
|
|
962
|
+
throw new Error('taskIds array is required and must not be empty');
|
|
963
|
+
}
|
|
964
|
+
const result = await taskService.getBulkTimeInStatus(taskIds);
|
|
965
|
+
return sponsorService.createResponse(result, true);
|
|
966
|
+
}
|
|
967
|
+
catch (error) {
|
|
968
|
+
return sponsorService.createErrorResponse(error, params);
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
/**
|
|
972
|
+
* Handler for adding a task to an additional list
|
|
973
|
+
*/
|
|
974
|
+
export async function addTaskToListHandler(params) {
|
|
975
|
+
try {
|
|
976
|
+
const { listId, taskId } = params;
|
|
977
|
+
if (!listId || !taskId) {
|
|
978
|
+
throw new Error('listId and taskId are required');
|
|
979
|
+
}
|
|
980
|
+
const result = await taskService.addTaskToList(listId, taskId);
|
|
981
|
+
return sponsorService.createResponse(result, true);
|
|
982
|
+
}
|
|
983
|
+
catch (error) {
|
|
984
|
+
return sponsorService.createErrorResponse(error, params);
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
/**
|
|
988
|
+
* Handler for removing a task from a list
|
|
989
|
+
*/
|
|
990
|
+
export async function removeTaskFromListHandler(params) {
|
|
991
|
+
try {
|
|
992
|
+
const { listId, taskId } = params;
|
|
993
|
+
if (!listId || !taskId) {
|
|
994
|
+
throw new Error('listId and taskId are required');
|
|
995
|
+
}
|
|
996
|
+
await taskService.removeTaskFromList(listId, taskId);
|
|
997
|
+
return sponsorService.createResponse({
|
|
998
|
+
success: true,
|
|
999
|
+
message: `Task ${taskId} removed from list ${listId}`
|
|
1000
|
+
}, true);
|
|
1001
|
+
}
|
|
1002
|
+
catch (error) {
|
|
1003
|
+
return sponsorService.createErrorResponse(error, params);
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// Re-export from main module
|
|
10
10
|
export * from './main.js';
|
|
11
11
|
// Re-export single task operation tools
|
|
12
|
-
export { createTaskTool, getTaskTool, getTasksTool, updateTaskTool, moveTaskTool, duplicateTaskTool, deleteTaskTool, getTaskCommentsTool, createTaskCommentTool } from './single-operations.js';
|
|
12
|
+
export { createTaskTool, getTaskTool, getTasksTool, updateTaskTool, moveTaskTool, duplicateTaskTool, deleteTaskTool, getTaskCommentsTool, createTaskCommentTool, mergeTaskTool, getTimeInStatusTool, getBulkTimeInStatusTool, addTaskToListTool, removeTaskFromListTool } from './single-operations.js';
|
|
13
13
|
// Re-export bulk task operation tools
|
|
14
14
|
export { createBulkTasksTool, updateBulkTasksTool, moveBulkTasksTool, deleteBulkTasksTool } from './bulk-operations.js';
|
|
15
15
|
// Re-export workspace task operation tools
|
|
@@ -21,7 +21,7 @@ export { attachTaskFileTool, handleAttachTaskFile } from './attachments.js';
|
|
|
21
21
|
// Re-export handlers
|
|
22
22
|
export {
|
|
23
23
|
// Single task operation handlers
|
|
24
|
-
createTaskHandler, getTaskHandler, getTasksHandler, updateTaskHandler, moveTaskHandler, duplicateTaskHandler, deleteTaskHandler, getTaskCommentsHandler, createTaskCommentHandler,
|
|
24
|
+
createTaskHandler, getTaskHandler, getTasksHandler, updateTaskHandler, moveTaskHandler, duplicateTaskHandler, deleteTaskHandler, getTaskCommentsHandler, createTaskCommentHandler, mergeTaskHandler, getTimeInStatusHandler, getBulkTimeInStatusHandler, addTaskToListHandler, removeTaskFromListHandler,
|
|
25
25
|
// Bulk task operation handlers
|
|
26
26
|
createBulkTasksHandler, updateBulkTasksHandler, moveBulkTasksHandler, deleteBulkTasksHandler,
|
|
27
27
|
// Team task operation handlers
|
|
@@ -467,3 +467,142 @@ export const deleteTaskTool = {
|
|
|
467
467
|
}
|
|
468
468
|
}
|
|
469
469
|
};
|
|
470
|
+
/**
|
|
471
|
+
* Tool definition for merging two tasks
|
|
472
|
+
*/
|
|
473
|
+
export const mergeTaskTool = {
|
|
474
|
+
name: "merge_task",
|
|
475
|
+
description: `Merges two ClickUp tasks together. The merge_from task will be merged into the destination task.
|
|
476
|
+
|
|
477
|
+
Example usage:
|
|
478
|
+
{
|
|
479
|
+
"taskId": "abc123", // Destination task ID (merge into this)
|
|
480
|
+
"mergeFromId": "xyz789" // Source task ID (merge from this)
|
|
481
|
+
}`,
|
|
482
|
+
inputSchema: {
|
|
483
|
+
type: "object",
|
|
484
|
+
properties: {
|
|
485
|
+
taskId: {
|
|
486
|
+
type: "string",
|
|
487
|
+
description: "REQUIRED: ID of the destination task (merge into this task)"
|
|
488
|
+
},
|
|
489
|
+
mergeFromId: {
|
|
490
|
+
type: "string",
|
|
491
|
+
description: "REQUIRED: ID of the source task (merge from this task)"
|
|
492
|
+
}
|
|
493
|
+
},
|
|
494
|
+
required: ["taskId", "mergeFromId"]
|
|
495
|
+
}
|
|
496
|
+
};
|
|
497
|
+
/**
|
|
498
|
+
* Tool definition for getting time in status for a task
|
|
499
|
+
*/
|
|
500
|
+
export const getTimeInStatusTool = {
|
|
501
|
+
name: "get_task_time_in_status",
|
|
502
|
+
description: `Gets the time tracking information for how long a task has been in each status.
|
|
503
|
+
|
|
504
|
+
Example usage:
|
|
505
|
+
{
|
|
506
|
+
"taskId": "abc123"
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
Returns:
|
|
510
|
+
- current_status: Current status with time spent
|
|
511
|
+
- status_history: Array of all status changes with timestamps`,
|
|
512
|
+
inputSchema: {
|
|
513
|
+
type: "object",
|
|
514
|
+
properties: {
|
|
515
|
+
taskId: {
|
|
516
|
+
type: "string",
|
|
517
|
+
description: "REQUIRED: ID of the task to get time in status for"
|
|
518
|
+
}
|
|
519
|
+
},
|
|
520
|
+
required: ["taskId"]
|
|
521
|
+
}
|
|
522
|
+
};
|
|
523
|
+
/**
|
|
524
|
+
* Tool definition for getting time in status for multiple tasks
|
|
525
|
+
*/
|
|
526
|
+
export const getBulkTimeInStatusTool = {
|
|
527
|
+
name: "get_bulk_tasks_time_in_status",
|
|
528
|
+
description: `Gets the time in status information for multiple tasks at once. More efficient than calling get_task_time_in_status multiple times.
|
|
529
|
+
|
|
530
|
+
Example usage:
|
|
531
|
+
{
|
|
532
|
+
"taskIds": ["abc123", "xyz789", "def456"]
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
Returns an object with task IDs as keys and their time in status data as values.`,
|
|
536
|
+
inputSchema: {
|
|
537
|
+
type: "object",
|
|
538
|
+
properties: {
|
|
539
|
+
taskIds: {
|
|
540
|
+
type: "array",
|
|
541
|
+
description: "REQUIRED: Array of task IDs to get time in status for",
|
|
542
|
+
items: {
|
|
543
|
+
type: "string"
|
|
544
|
+
},
|
|
545
|
+
minItems: 1
|
|
546
|
+
}
|
|
547
|
+
},
|
|
548
|
+
required: ["taskIds"]
|
|
549
|
+
}
|
|
550
|
+
};
|
|
551
|
+
/**
|
|
552
|
+
* Tool definition for adding a task to an additional list
|
|
553
|
+
*/
|
|
554
|
+
export const addTaskToListTool = {
|
|
555
|
+
name: "add_task_to_list",
|
|
556
|
+
description: `Adds a task to an additional list, enabling multiple list membership for the task.
|
|
557
|
+
|
|
558
|
+
Example usage:
|
|
559
|
+
{
|
|
560
|
+
"listId": "12345",
|
|
561
|
+
"taskId": "abc123"
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
Note: This does NOT move the task. The task will belong to multiple lists after this operation.`,
|
|
565
|
+
inputSchema: {
|
|
566
|
+
type: "object",
|
|
567
|
+
properties: {
|
|
568
|
+
listId: {
|
|
569
|
+
type: "string",
|
|
570
|
+
description: "REQUIRED: ID of the list to add the task to"
|
|
571
|
+
},
|
|
572
|
+
taskId: {
|
|
573
|
+
type: "string",
|
|
574
|
+
description: "REQUIRED: ID of the task to add to the list"
|
|
575
|
+
}
|
|
576
|
+
},
|
|
577
|
+
required: ["listId", "taskId"]
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
/**
|
|
581
|
+
* Tool definition for removing a task from a list
|
|
582
|
+
*/
|
|
583
|
+
export const removeTaskFromListTool = {
|
|
584
|
+
name: "remove_task_from_list",
|
|
585
|
+
description: `Removes a task from a specific list. If the task belongs to multiple lists, it will only be removed from the specified list.
|
|
586
|
+
|
|
587
|
+
Example usage:
|
|
588
|
+
{
|
|
589
|
+
"listId": "12345",
|
|
590
|
+
"taskId": "abc123"
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
Warning: If this is the task's only list, the task may be deleted or moved to an archive depending on ClickUp settings.`,
|
|
594
|
+
inputSchema: {
|
|
595
|
+
type: "object",
|
|
596
|
+
properties: {
|
|
597
|
+
listId: {
|
|
598
|
+
type: "string",
|
|
599
|
+
description: "REQUIRED: ID of the list to remove the task from"
|
|
600
|
+
},
|
|
601
|
+
taskId: {
|
|
602
|
+
type: "string",
|
|
603
|
+
description: "REQUIRED: ID of the task to remove from the list"
|
|
604
|
+
}
|
|
605
|
+
},
|
|
606
|
+
required: ["listId", "taskId"]
|
|
607
|
+
}
|
|
608
|
+
};
|
|
@@ -25,7 +25,10 @@ export const workspaceParameter = {
|
|
|
25
25
|
*/
|
|
26
26
|
export function getServicesForWorkspace(params) {
|
|
27
27
|
try {
|
|
28
|
-
|
|
28
|
+
console.error('[DEBUG] getServicesForWorkspace called with workspace:', params.workspace);
|
|
29
|
+
const services = getClickUpServices(params.workspace);
|
|
30
|
+
console.error('[DEBUG] Retrieved services for workspace:', params.workspace || 'default');
|
|
31
|
+
return services;
|
|
29
32
|
}
|
|
30
33
|
catch (error) {
|
|
31
34
|
// Enhance error message with available workspaces
|
package/build/tools/workspace.js
CHANGED
|
@@ -30,6 +30,9 @@ export const workspaceHierarchyTool = {
|
|
|
30
30
|
*/
|
|
31
31
|
export async function handleGetWorkspaceHierarchy(params = {}) {
|
|
32
32
|
try {
|
|
33
|
+
// DEBUG: Log received parameters
|
|
34
|
+
console.error('[DEBUG] handleGetWorkspaceHierarchy called with params:', JSON.stringify(params));
|
|
35
|
+
console.error('[DEBUG] params.workspace =', params.workspace);
|
|
33
36
|
// Get services for the specified workspace
|
|
34
37
|
const services = getServicesForWorkspace(params);
|
|
35
38
|
const { workspace: workspaceService } = services;
|
|
@@ -44,6 +47,49 @@ export async function handleGetWorkspaceHierarchy(params = {}) {
|
|
|
44
47
|
return sponsorService.createErrorResponse(`Error getting workspace hierarchy: ${error.message}`);
|
|
45
48
|
}
|
|
46
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Tool definition for retrieving available workspaces
|
|
52
|
+
*/
|
|
53
|
+
export const availableWorkspacesTool = {
|
|
54
|
+
name: 'get_available_workspaces',
|
|
55
|
+
description: `Gets list of all available workspaces configured in the ClickUp MCP server. Returns workspace identifiers, default workspace, and descriptions if available.`,
|
|
56
|
+
inputSchema: {
|
|
57
|
+
type: 'object',
|
|
58
|
+
properties: {}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Handler for the get_available_workspaces tool
|
|
63
|
+
*/
|
|
64
|
+
export async function handleGetAvailableWorkspaces() {
|
|
65
|
+
try {
|
|
66
|
+
// Import config functions
|
|
67
|
+
const { getAvailableWorkspaces, getDefaultWorkspace, getWorkspaceConfig } = await import('../config.js');
|
|
68
|
+
// Get list of available workspace identifiers
|
|
69
|
+
const workspaceIds = getAvailableWorkspaces();
|
|
70
|
+
const defaultWorkspace = getDefaultWorkspace();
|
|
71
|
+
// Get detailed information for each workspace
|
|
72
|
+
const workspaces = workspaceIds.map(id => {
|
|
73
|
+
const config = getWorkspaceConfig(id);
|
|
74
|
+
return {
|
|
75
|
+
id,
|
|
76
|
+
teamId: config.teamId,
|
|
77
|
+
description: config.description || (id === 'default' ? 'Default workspace' : undefined),
|
|
78
|
+
isDefault: id === defaultWorkspace
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
const result = {
|
|
82
|
+
default: defaultWorkspace,
|
|
83
|
+
workspaces,
|
|
84
|
+
count: workspaces.length
|
|
85
|
+
};
|
|
86
|
+
// Use sponsor service to create the response
|
|
87
|
+
return sponsorService.createResponse(result, true);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
return sponsorService.createErrorResponse(`Error getting available workspaces: ${error.message}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
47
93
|
/**
|
|
48
94
|
* Format the hierarchy as a tree string
|
|
49
95
|
*/
|
|
@@ -1,37 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* SPDX-FileCopyrightText: © 2025 Talib Kareem <taazkareem@icloud.com>
|
|
3
|
+
* SPDX-FileCopyrightText: © 2025 Daichi Okazaki (Alanse)
|
|
3
4
|
* SPDX-License-Identifier: MIT
|
|
4
5
|
*
|
|
5
|
-
*
|
|
6
|
+
* Response Service Module
|
|
6
7
|
*
|
|
7
|
-
* Provides
|
|
8
|
+
* Provides utilities for creating standardized MCP responses
|
|
8
9
|
*/
|
|
9
10
|
import { Logger } from '../logger.js';
|
|
10
|
-
import config from '../config.js';
|
|
11
11
|
// Create logger instance for this module
|
|
12
|
-
const logger = new Logger('
|
|
12
|
+
const logger = new Logger('ResponseService');
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
14
|
+
* ResponseService - Provides standardized response formatting
|
|
15
15
|
*/
|
|
16
|
-
export class
|
|
16
|
+
export class ResponseService {
|
|
17
17
|
constructor() {
|
|
18
|
-
|
|
19
|
-
this.isEnabled = config.enableSponsorMessage;
|
|
20
|
-
logger.info('SponsorService initialized', { enabled: this.isEnabled });
|
|
18
|
+
logger.info('ResponseService initialized');
|
|
21
19
|
}
|
|
22
20
|
/**
|
|
23
|
-
*
|
|
21
|
+
* Creates a standardized response
|
|
24
22
|
*/
|
|
25
|
-
|
|
26
|
-
return {
|
|
27
|
-
isEnabled: this.isEnabled,
|
|
28
|
-
url: this.sponsorUrl
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Creates a response with optional sponsorship message
|
|
33
|
-
*/
|
|
34
|
-
createResponse(data, includeSponsorMessage = false) {
|
|
23
|
+
createResponse(data, _includeSponsorMessage = false) {
|
|
35
24
|
const content = [];
|
|
36
25
|
// Special handling for workspace hierarchy which contains a preformatted tree
|
|
37
26
|
if (data && typeof data === 'object' && 'hierarchy' in data && typeof data.hierarchy === 'string') {
|
|
@@ -55,13 +44,6 @@ export class SponsorService {
|
|
|
55
44
|
text: JSON.stringify(data, null, 2)
|
|
56
45
|
});
|
|
57
46
|
}
|
|
58
|
-
// Then add sponsorship message if enabled
|
|
59
|
-
if (this.isEnabled && includeSponsorMessage) {
|
|
60
|
-
content.push({
|
|
61
|
-
type: "text",
|
|
62
|
-
text: `\n♥ Support this project by sponsoring the developer at ${this.sponsorUrl}`
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
47
|
return { content };
|
|
66
48
|
}
|
|
67
49
|
/**
|
|
@@ -74,7 +56,7 @@ export class SponsorService {
|
|
|
74
56
|
});
|
|
75
57
|
}
|
|
76
58
|
/**
|
|
77
|
-
* Creates a bulk operation response
|
|
59
|
+
* Creates a bulk operation response
|
|
78
60
|
*/
|
|
79
61
|
createBulkResponse(result) {
|
|
80
62
|
return this.createResponse({
|
|
@@ -86,8 +68,9 @@ export class SponsorService {
|
|
|
86
68
|
id: failure.item?.id || failure.item,
|
|
87
69
|
error: failure.error.message
|
|
88
70
|
}))
|
|
89
|
-
}
|
|
71
|
+
});
|
|
90
72
|
}
|
|
91
73
|
}
|
|
92
|
-
// Export a singleton instance
|
|
93
|
-
|
|
74
|
+
// Export a singleton instance for backwards compatibility
|
|
75
|
+
// (keeping the name 'sponsorService' to avoid changing all imports)
|
|
76
|
+
export const sponsorService = new ResponseService();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alanse/clickup-multi-mcp-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "ClickUp MCP Server with Multi-Workspace Support - Integrate multiple ClickUp workspaces with AI through Model Context Protocol",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "build/index.js",
|