@taazkareem/clickup-mcp-server 0.6.0 → 0.6.1

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.
Files changed (36) hide show
  1. package/README.md +14 -23
  2. package/build/config.js +34 -2
  3. package/build/index.js +3 -1
  4. package/build/logger.js +8 -38
  5. package/build/server.js +33 -8
  6. package/build/services/clickup/base.js +3 -0
  7. package/build/services/clickup/bulk.js +3 -0
  8. package/build/services/clickup/folder.js +3 -0
  9. package/build/services/clickup/index.js +9 -1
  10. package/build/services/clickup/list.js +3 -0
  11. package/build/services/clickup/tag.js +190 -0
  12. package/build/services/clickup/task.js +138 -0
  13. package/build/services/clickup/types.js +3 -0
  14. package/build/services/clickup/workspace.js +3 -0
  15. package/build/services/shared.js +3 -0
  16. package/build/tools/folder.js +3 -0
  17. package/build/tools/index.js +4 -0
  18. package/build/tools/list.js +3 -0
  19. package/build/tools/tag.js +824 -0
  20. package/build/tools/task/attachments.js +3 -0
  21. package/build/tools/task/bulk-operations.js +10 -0
  22. package/build/tools/task/handlers.js +61 -2
  23. package/build/tools/task/index.js +8 -1
  24. package/build/tools/task/main.js +18 -2
  25. package/build/tools/task/single-operations.js +10 -0
  26. package/build/tools/task/utilities.js +40 -3
  27. package/build/tools/task/workspace-operations.js +222 -0
  28. package/build/tools/utils.js +3 -0
  29. package/build/tools/workspace.js +3 -0
  30. package/build/utils/color-processor.js +183 -0
  31. package/build/utils/concurrency-utils.js +3 -0
  32. package/build/utils/date-utils.js +3 -0
  33. package/build/utils/resolver-utils.js +3 -0
  34. package/build/utils/sponsor-service.js +3 -0
  35. package/build/utils/token-utils.js +49 -0
  36. package/package.json +1 -1
package/README.md CHANGED
@@ -6,7 +6,7 @@
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:** 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.
9
+ > 🚧 **Status Update:** Rolling out v0.6.1 which will add Complete Tag Support including natural language tag color commands, Subtasks Support, Custom ID Support, and Logging Fixes
10
10
 
11
11
  ## Setup
12
12
 
@@ -22,7 +22,6 @@ A Model Context Protocol (MCP) server for integrating ClickUp tasks with AI appl
22
22
 
23
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
-
26
25
  ## NPX Installation
27
26
 
28
27
  [![NPM Version](https://img.shields.io/npm/v/@taazkareem/clickup-mcp-server.svg?style=flat&logo=npm)](https://www.npmjs.com/package/@taazkareem/clickup-mcp-server)
@@ -55,26 +54,11 @@ Or use this npx command:
55
54
 
56
55
  ## Features
57
56
 
58
- - 🎯 **Task Management**
59
- - Create, retrieve, update, and delete tasks
60
- - Move and duplicate tasks between lists, spaces, and folders
61
- - Single operation or bulk operation
62
- - View and modify task details and properties
63
- - Get task comments
64
- - Set due dates using natural language and relative time expressions
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
67
-
68
- - 📂 **Workspace Organization**
69
- - Complete workspace hierarchy (spaces, folders, lists)
70
- - Tree structure with clear relationships
71
- - Efficient path-based navigation
72
-
73
- - 🔄 **Integration Features**
74
- - Name or ID-based item lookup
75
- - Case-insensitive name matching
76
- - Markdown formatting support
77
- - Built-in API rate limiting
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 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 | • 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 |
78
62
 
79
63
  ## Available Tools
80
64
 
@@ -86,7 +70,8 @@ Or use this npx command:
86
70
  | [update_task](docs/api-reference.md#task-management) | Modify task | `taskId`/`taskName` |
87
71
  | [update_bulk_tasks](docs/api-reference.md#task-management) | Update multiple tasks | `tasks[]` with IDs or names |
88
72
  | [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` |
73
+ | [get_task](docs/api-reference.md#task-management) | Get single task details | `taskId`/`taskName`, optional `subtasks` |
74
+ | [get_workspace_tasks](docs/api-reference.md#task-management) | Get tasks with filtering | At least one filter (tags, list_ids, space_ids, etc.) |
90
75
  | [get_task_comments](docs/api-reference.md#task-management) | Get comments on a task | `taskId`/`taskName` |
91
76
  | [create_task_comment](docs/api-reference.md#task-management) | Add a comment to a task | `commentText`, (`taskId`/(`taskName`+`listName`)) |
92
77
  | [attach_task_file](docs/api-reference.md#task-management) | Attach file to a task | `taskId`/`taskName`, (`file_data` or `file_url`) |
@@ -104,6 +89,12 @@ Or use this npx command:
104
89
  | [get_list](docs/api-reference.md#list-management) | Get list details | `listId`/`listName` |
105
90
  | [update_list](docs/api-reference.md#list-management) | Update list properties | `listId`/`listName` |
106
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`) |
107
98
 
108
99
  See [full documentation](docs/api-reference.md) for optional parameters and advanced usage.
109
100
 
package/build/config.js CHANGED
@@ -1,5 +1,8 @@
1
1
  /**
2
- * Configuration handling for ClickUp API credentials
2
+ * SPDX-FileCopyrightText: © 2025 Talib Kareem <taazkareem@icloud.com>
3
+ * SPDX-License-Identifier: MIT
4
+ *
5
+ * Configuration handling for ClickUp API credentials and application settings
3
6
  *
4
7
  * The required environment variables (CLICKUP_API_KEY and CLICKUP_TEAM_ID) are passed
5
8
  * securely to this file when running the hosted server at smithery.ai. Optionally,
@@ -15,15 +18,44 @@ for (let i = 0; i < args.length; i++) {
15
18
  envArgs.clickupApiKey = value;
16
19
  if (key === 'CLICKUP_TEAM_ID')
17
20
  envArgs.clickupTeamId = value;
21
+ if (key === 'LOG_LEVEL')
22
+ envArgs.logLevel = value;
18
23
  i++;
19
24
  }
20
25
  }
26
+ // Log levels enum
27
+ export var LogLevel;
28
+ (function (LogLevel) {
29
+ LogLevel[LogLevel["TRACE"] = 0] = "TRACE";
30
+ LogLevel[LogLevel["DEBUG"] = 1] = "DEBUG";
31
+ LogLevel[LogLevel["INFO"] = 2] = "INFO";
32
+ LogLevel[LogLevel["WARN"] = 3] = "WARN";
33
+ LogLevel[LogLevel["ERROR"] = 4] = "ERROR";
34
+ })(LogLevel || (LogLevel = {}));
35
+ // Parse LOG_LEVEL string to LogLevel enum
36
+ export const parseLogLevel = (levelStr) => {
37
+ if (!levelStr)
38
+ return LogLevel.ERROR; // Default to ERROR if not specified
39
+ switch (levelStr.toUpperCase()) {
40
+ case 'TRACE': return LogLevel.TRACE;
41
+ case 'DEBUG': return LogLevel.DEBUG;
42
+ case 'INFO': return LogLevel.INFO;
43
+ case 'WARN': return LogLevel.WARN;
44
+ case 'ERROR': return LogLevel.ERROR;
45
+ default:
46
+ console.error(`Invalid LOG_LEVEL: ${levelStr}, defaulting to ERROR`);
47
+ return LogLevel.ERROR;
48
+ }
49
+ };
21
50
  // Load configuration from command line args or environment variables
22
51
  const configuration = {
23
52
  clickupApiKey: envArgs.clickupApiKey || process.env.CLICKUP_API_KEY || '',
24
53
  clickupTeamId: envArgs.clickupTeamId || process.env.CLICKUP_TEAM_ID || '',
25
- enableSponsorMessage: process.env.ENABLE_SPONSOR_MESSAGE !== 'false'
54
+ enableSponsorMessage: process.env.ENABLE_SPONSOR_MESSAGE !== 'false',
55
+ logLevel: parseLogLevel(envArgs.logLevel || process.env.LOG_LEVEL)
26
56
  };
57
+ // Log the configured log level (but only to console to avoid circular dependency)
58
+ console.debug(`Log level set to: ${LogLevel[configuration.logLevel]}`);
27
59
  // Validate only the required variables are present
28
60
  const requiredVars = ['clickupApiKey', 'clickupTeamId'];
29
61
  const missingEnvVars = requiredVars
package/build/index.js CHANGED
@@ -1,5 +1,7 @@
1
- #!/usr/bin/env node
2
1
  /**
2
+ * SPDX-FileCopyrightText: © 2025 Talib Kareem <taazkareem@icloud.com>
3
+ * SPDX-License-Identifier: MIT
4
+ *
3
5
  * ClickUp MCP Server
4
6
  *
5
7
  * This custom server implements the Model Context Protocol (MCP) specification to enable
package/build/logger.js CHANGED
@@ -1,4 +1,7 @@
1
1
  /**
2
+ * SPDX-FileCopyrightText: © 2025 Talib Kareem <taazkareem@icloud.com>
3
+ * SPDX-License-Identifier: MIT
4
+ *
2
5
  * Logger module for MCP Server
3
6
  *
4
7
  * This module provides logging functionality for the server,
@@ -7,6 +10,7 @@
7
10
  import { createWriteStream } from 'fs';
8
11
  import { join, dirname } from 'path';
9
12
  import { fileURLToPath } from 'url';
13
+ import config, { LogLevel } from './config.js';
10
14
  // Get the directory name of the current module
11
15
  const __dirname = dirname(fileURLToPath(import.meta.url));
12
16
  // Current process ID for logging
@@ -15,44 +19,10 @@ const pid = process.pid;
15
19
  const logFileName = 'server.log';
16
20
  const logStream = createWriteStream(join(__dirname, logFileName), { flags: 'w' });
17
21
  console.error(`Logging to ${join(__dirname, logFileName)}`);
18
- // Log levels with numeric values for filtering
19
- export var LogLevel;
20
- (function (LogLevel) {
21
- LogLevel[LogLevel["TRACE"] = 0] = "TRACE";
22
- LogLevel[LogLevel["DEBUG"] = 1] = "DEBUG";
23
- LogLevel[LogLevel["INFO"] = 2] = "INFO";
24
- LogLevel[LogLevel["WARN"] = 3] = "WARN";
25
- LogLevel[LogLevel["ERROR"] = 4] = "ERROR";
26
- })(LogLevel || (LogLevel = {}));
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]}`);
22
+ // Use the configured log level from config.ts
23
+ const configuredLevel = config.logLevel;
24
+ // Re-export LogLevel enum
25
+ export { LogLevel };
56
26
  /**
57
27
  * Check if a log level is enabled based on the configured level
58
28
  * @param level The log level to check
package/build/server.js CHANGED
@@ -1,21 +1,25 @@
1
+ /**
2
+ * SPDX-FileCopyrightText: © 2025 Talib Kareem <taazkareem@icloud.com>
3
+ * SPDX-License-Identifier: MIT
4
+ *
5
+ * MCP Server for ClickUp integration
6
+ */
1
7
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
8
  import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
3
9
  import { workspaceHierarchyTool, handleGetWorkspaceHierarchy } from "./tools/workspace.js";
4
- import { createTaskTool, updateTaskTool, moveTaskTool, duplicateTaskTool, getTaskTool, getTasksTool, deleteTaskTool, getTaskCommentsTool, createTaskCommentTool, createBulkTasksTool, updateBulkTasksTool, moveBulkTasksTool, deleteBulkTasksTool, attachTaskFileTool, handleCreateTask, handleUpdateTask, handleMoveTask, handleDuplicateTask, handleGetTasks, handleDeleteTask, handleGetTaskComments, handleCreateTaskComment, handleCreateBulkTasks, handleUpdateBulkTasks, handleMoveBulkTasks, handleDeleteBulkTasks, handleGetTask, handleAttachTaskFile } from "./tools/task/index.js";
10
+ import { createTaskTool, updateTaskTool, moveTaskTool, duplicateTaskTool, getTaskTool, getTasksTool, deleteTaskTool, getTaskCommentsTool, createTaskCommentTool, createBulkTasksTool, updateBulkTasksTool, moveBulkTasksTool, deleteBulkTasksTool, attachTaskFileTool, getWorkspaceTasksTool, handleCreateTask, handleUpdateTask, handleMoveTask, handleDuplicateTask, handleGetTasks, handleDeleteTask, handleGetTaskComments, handleCreateTaskComment, handleCreateBulkTasks, handleUpdateBulkTasks, handleMoveBulkTasks, handleDeleteBulkTasks, handleGetTask, handleAttachTaskFile, handleGetWorkspaceTasks } from "./tools/task/index.js";
5
11
  import { createListTool, handleCreateList, createListInFolderTool, handleCreateListInFolder, getListTool, handleGetList, updateListTool, handleUpdateList, deleteListTool, handleDeleteList } from "./tools/list.js";
6
12
  import { createFolderTool, handleCreateFolder, getFolderTool, handleGetFolder, updateFolderTool, handleUpdateFolder, deleteFolderTool, handleDeleteFolder } from "./tools/folder.js";
13
+ import { getSpaceTagsTool, handleGetSpaceTags, createSpaceTagTool, handleCreateSpaceTag, updateSpaceTagTool, handleUpdateSpaceTag, deleteSpaceTagTool, handleDeleteSpaceTag, addTagToTaskTool, handleAddTagToTask, removeTagFromTaskTool, handleRemoveTagFromTask } from "./tools/tag.js";
7
14
  import { Logger } from "./logger.js";
8
15
  import { clickUpServices } from "./services/shared.js";
9
16
  // Create a logger instance for server
10
17
  const logger = new Logger('Server');
11
18
  // Use existing services from shared module instead of creating new ones
12
19
  const { workspace } = clickUpServices;
13
- /**
14
- * MCP Server for ClickUp integration
15
- */
16
20
  export const server = new Server({
17
21
  name: "clickup-mcp-server",
18
- version: "0.6.0",
22
+ version: "0.6.1",
19
23
  }, {
20
24
  capabilities: {
21
25
  tools: {},
@@ -47,6 +51,7 @@ export function configureServer() {
47
51
  updateBulkTasksTool,
48
52
  moveBulkTasksTool,
49
53
  deleteBulkTasksTool,
54
+ getWorkspaceTasksTool,
50
55
  createListTool,
51
56
  createListInFolderTool,
52
57
  getListTool,
@@ -55,14 +60,20 @@ export function configureServer() {
55
60
  createFolderTool,
56
61
  getFolderTool,
57
62
  updateFolderTool,
58
- deleteFolderTool
63
+ deleteFolderTool,
64
+ getSpaceTagsTool,
65
+ createSpaceTagTool,
66
+ updateSpaceTagTool,
67
+ deleteSpaceTagTool,
68
+ addTagToTaskTool,
69
+ removeTagFromTaskTool
59
70
  ]
60
71
  };
61
72
  });
62
73
  // Register CallTool handler with proper logging
63
74
  logger.info("Registering tool handlers", {
64
- toolCount: 24,
65
- categories: ["workspace", "task", "list", "folder"]
75
+ toolCount: 31,
76
+ categories: ["workspace", "task", "list", "folder", "tag"]
66
77
  });
67
78
  server.setRequestHandler(CallToolRequestSchema, async (req) => {
68
79
  const { name, arguments: params } = req.params;
@@ -103,6 +114,8 @@ export function configureServer() {
103
114
  return handleMoveBulkTasks(params);
104
115
  case "delete_bulk_tasks":
105
116
  return handleDeleteBulkTasks(params);
117
+ case "get_workspace_tasks":
118
+ return handleGetWorkspaceTasks(params);
106
119
  case "create_list":
107
120
  return handleCreateList(params);
108
121
  case "create_list_in_folder":
@@ -121,6 +134,18 @@ export function configureServer() {
121
134
  return handleUpdateFolder(params);
122
135
  case "delete_folder":
123
136
  return handleDeleteFolder(params);
137
+ case "get_space_tags":
138
+ return handleGetSpaceTags(params);
139
+ case "create_space_tag":
140
+ return handleCreateSpaceTag(params);
141
+ case "update_space_tag":
142
+ return handleUpdateSpaceTag(params);
143
+ case "delete_space_tag":
144
+ return handleDeleteSpaceTag(params);
145
+ case "add_tag_to_task":
146
+ return handleAddTagToTask(params);
147
+ case "remove_tag_from_task":
148
+ return handleRemoveTagFromTask(params);
124
149
  default:
125
150
  logger.error(`Unknown tool requested: ${name}`);
126
151
  throw new Error(`Unknown tool: ${name}`);
@@ -1,4 +1,7 @@
1
1
  /**
2
+ * SPDX-FileCopyrightText: © 2025 Talib Kareem <taazkareem@icloud.com>
3
+ * SPDX-License-Identifier: MIT
4
+ *
2
5
  * Base ClickUp Service Class
3
6
  *
4
7
  * This class provides core functionality for all ClickUp service modules:
@@ -1,4 +1,7 @@
1
1
  /**
2
+ * SPDX-FileCopyrightText: © 2025 Talib Kareem <taazkareem@icloud.com>
3
+ * SPDX-License-Identifier: MIT
4
+ *
2
5
  * ClickUp Bulk Service
3
6
  *
4
7
  * Enhanced implementation for bulk operations that leverages the existing single-operation methods.
@@ -1,4 +1,7 @@
1
1
  /**
2
+ * SPDX-FileCopyrightText: © 2025 Talib Kareem <taazkareem@icloud.com>
3
+ * SPDX-License-Identifier: MIT
4
+ *
2
5
  * ClickUp Folder Service
3
6
  *
4
7
  * Handles all operations related to folders in ClickUp, including:
@@ -1,4 +1,7 @@
1
1
  /**
2
+ * SPDX-FileCopyrightText: © 2025 Talib Kareem <taazkareem@icloud.com>
3
+ * SPDX-License-Identifier: MIT
4
+ *
2
5
  * ClickUp Service Entry Point
3
6
  *
4
7
  * This file re-exports all service modules for the ClickUp API integration.
@@ -13,11 +16,13 @@ export { WorkspaceService } from './workspace.js';
13
16
  export { TaskService } from './task.js';
14
17
  export { ListService } from './list.js';
15
18
  export { FolderService } from './folder.js';
19
+ export { ClickUpTagService } from './tag.js';
16
20
  // Import service classes for the factory function
17
21
  import { WorkspaceService } from './workspace.js';
18
22
  import { TaskService } from './task.js';
19
23
  import { ListService } from './list.js';
20
24
  import { FolderService } from './folder.js';
25
+ import { ClickUpTagService } from './tag.js';
21
26
  import { Logger } from '../../logger.js';
22
27
  // Singleton logger for ClickUp services
23
28
  const logger = new Logger('ClickUpServices');
@@ -43,11 +48,14 @@ export function createClickUpServices(config) {
43
48
  const listService = new ListService(apiKey, teamId, baseUrl, workspaceService);
44
49
  logger.info('Initializing ClickUp Folder service');
45
50
  const folderService = new FolderService(apiKey, teamId, baseUrl, workspaceService);
51
+ logger.info('Initializing ClickUp Tag service');
52
+ const tagService = new ClickUpTagService(apiKey, teamId, baseUrl);
46
53
  const services = {
47
54
  workspace: workspaceService,
48
55
  task: taskService,
49
56
  list: listService,
50
- folder: folderService
57
+ folder: folderService,
58
+ tag: tagService
51
59
  };
52
60
  // Log successful completion
53
61
  logger.info('All ClickUp services initialized successfully', {
@@ -1,4 +1,7 @@
1
1
  /**
2
+ * SPDX-FileCopyrightText: © 2025 Talib Kareem <taazkareem@icloud.com>
3
+ * SPDX-License-Identifier: MIT
4
+ *
2
5
  * ClickUp List Service
3
6
  *
4
7
  * Handles all operations related to lists in ClickUp, including:
@@ -0,0 +1,190 @@
1
+ /**
2
+ * SPDX-FileCopyrightText: © 2025 Talib Kareem <taazkareem@icloud.com>
3
+ * SPDX-License-Identifier: MIT
4
+ *
5
+ * ClickUp Tag Service
6
+ *
7
+ * Provides access to ClickUp API endpoints for tag management:
8
+ * - Space tags (get, create, update, delete)
9
+ * - Task tags (add, remove)
10
+ */
11
+ import { BaseClickUpService } from './base.js';
12
+ /**
13
+ * ClickUp Tag Service class for managing tags
14
+ */
15
+ export class ClickUpTagService extends BaseClickUpService {
16
+ /**
17
+ * Get all tags in a space
18
+ * @param spaceId - ID of the space to get tags from
19
+ * @returns Promise with tags array
20
+ */
21
+ async getSpaceTags(spaceId) {
22
+ try {
23
+ this.logger.debug(`Getting tags for space: ${spaceId}`);
24
+ const response = await this.client.get(`/space/${spaceId}/tag`);
25
+ return {
26
+ success: true,
27
+ data: response.data.tags
28
+ };
29
+ }
30
+ catch (error) {
31
+ this.logger.error(`Failed to get tags for space: ${spaceId}`, error);
32
+ return {
33
+ success: false,
34
+ error: {
35
+ message: error.message || 'Failed to get space tags',
36
+ code: error.code,
37
+ details: error.data
38
+ }
39
+ };
40
+ }
41
+ }
42
+ /**
43
+ * Create a new tag in a space
44
+ * @param spaceId - ID of the space
45
+ * @param tagData - Tag data (name, background color, foreground color)
46
+ * @returns Promise with created tag
47
+ */
48
+ async createSpaceTag(spaceId, tagData) {
49
+ try {
50
+ this.logger.debug(`Creating tag "${tagData.tag_name}" in space: ${spaceId}`);
51
+ // Send tag data wrapped in a 'tag' object
52
+ const response = await this.client.post(`/space/${spaceId}/tag`, {
53
+ tag: {
54
+ name: tagData.tag_name,
55
+ tag_bg: tagData.tag_bg,
56
+ tag_fg: tagData.tag_fg
57
+ }
58
+ });
59
+ return {
60
+ success: true,
61
+ data: response.data.tag
62
+ };
63
+ }
64
+ catch (error) {
65
+ this.logger.error(`Failed to create tag in space: ${spaceId}`, error);
66
+ return {
67
+ success: false,
68
+ error: {
69
+ message: error.message || 'Failed to create space tag',
70
+ code: error.code,
71
+ details: error.data
72
+ }
73
+ };
74
+ }
75
+ }
76
+ /**
77
+ * Update an existing tag in a space
78
+ * @param spaceId - ID of the space
79
+ * @param tagName - Current name of the tag to update
80
+ * @param updateData - Tag data to update (name, colors)
81
+ * @returns Promise with updated tag
82
+ */
83
+ async updateSpaceTag(spaceId, tagName, updateData) {
84
+ try {
85
+ this.logger.debug(`Updating tag "${tagName}" in space: ${spaceId}`);
86
+ // Encode the tag name in the URL
87
+ const encodedTagName = encodeURIComponent(tagName);
88
+ const response = await this.client.put(`/space/${spaceId}/tag/${encodedTagName}`, updateData);
89
+ return {
90
+ success: true,
91
+ data: response.data.tag
92
+ };
93
+ }
94
+ catch (error) {
95
+ this.logger.error(`Failed to update tag "${tagName}" in space: ${spaceId}`, error);
96
+ return {
97
+ success: false,
98
+ error: {
99
+ message: error.message || 'Failed to update space tag',
100
+ code: error.code,
101
+ details: error.data
102
+ }
103
+ };
104
+ }
105
+ }
106
+ /**
107
+ * Delete a tag from a space
108
+ * @param spaceId - ID of the space
109
+ * @param tagName - Name of the tag to delete
110
+ * @returns Promise with success status
111
+ */
112
+ async deleteSpaceTag(spaceId, tagName) {
113
+ try {
114
+ this.logger.debug(`Deleting tag "${tagName}" from space: ${spaceId}`);
115
+ // Encode the tag name in the URL
116
+ const encodedTagName = encodeURIComponent(tagName);
117
+ await this.client.delete(`/space/${spaceId}/tag/${encodedTagName}`);
118
+ return {
119
+ success: true
120
+ };
121
+ }
122
+ catch (error) {
123
+ this.logger.error(`Failed to delete tag "${tagName}" from space: ${spaceId}`, error);
124
+ return {
125
+ success: false,
126
+ error: {
127
+ message: error.message || 'Failed to delete space tag',
128
+ code: error.code,
129
+ details: error.data
130
+ }
131
+ };
132
+ }
133
+ }
134
+ /**
135
+ * Add a tag to a task
136
+ * @param taskId - ID of the task
137
+ * @param tagName - Name of the tag to add
138
+ * @returns Promise with success status
139
+ */
140
+ async addTagToTask(taskId, tagName) {
141
+ try {
142
+ this.logger.debug(`Adding tag "${tagName}" to task: ${taskId}`);
143
+ // Encode the tag name in the URL
144
+ const encodedTagName = encodeURIComponent(tagName);
145
+ await this.client.post(`/task/${taskId}/tag/${encodedTagName}`, {});
146
+ return {
147
+ success: true
148
+ };
149
+ }
150
+ catch (error) {
151
+ this.logger.error(`Failed to add tag "${tagName}" to task: ${taskId}`, error);
152
+ return {
153
+ success: false,
154
+ error: {
155
+ message: error.message || 'Failed to add tag to task',
156
+ code: error.code,
157
+ details: error.data
158
+ }
159
+ };
160
+ }
161
+ }
162
+ /**
163
+ * Remove a tag from a task
164
+ * @param taskId - ID of the task
165
+ * @param tagName - Name of the tag to remove
166
+ * @returns Promise with success status
167
+ */
168
+ async removeTagFromTask(taskId, tagName) {
169
+ try {
170
+ this.logger.debug(`Removing tag "${tagName}" from task: ${taskId}`);
171
+ // Encode the tag name in the URL
172
+ const encodedTagName = encodeURIComponent(tagName);
173
+ await this.client.delete(`/task/${taskId}/tag/${encodedTagName}`);
174
+ return {
175
+ success: true
176
+ };
177
+ }
178
+ catch (error) {
179
+ this.logger.error(`Failed to remove tag "${tagName}" from task: ${taskId}`, error);
180
+ return {
181
+ success: false,
182
+ error: {
183
+ message: error.message || 'Failed to remove tag from task',
184
+ code: error.code,
185
+ details: error.data
186
+ }
187
+ };
188
+ }
189
+ }
190
+ }