@taazkareem/clickup-mcp-server 0.4.60 → 0.4.63

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.
@@ -0,0 +1,120 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
3
+ import { createClickUpServices } from "./services/clickup/index.js";
4
+ import config from "./config.js";
5
+ import { workspaceHierarchyTool, handleGetWorkspaceHierarchy } from "./tools/workspace.js";
6
+ import { createTaskTool, handleCreateTask, updateTaskTool, handleUpdateTask, moveTaskTool, handleMoveTask, duplicateTaskTool, handleDuplicateTask, getTaskTool, handleGetTask, getTasksTool, handleGetTasks, deleteTaskTool, handleDeleteTask, createBulkTasksTool, handleCreateBulkTasks, updateBulkTasksTool, handleUpdateBulkTasks, moveBulkTasksTool, handleMoveBulkTasks, deleteBulkTasksTool, handleDeleteBulkTasks } from "./tools/task.js";
7
+ import { createListTool, handleCreateList, createListInFolderTool, handleCreateListInFolder, getListTool, handleGetList, updateListTool, handleUpdateList, deleteListTool, handleDeleteList } from "./tools/list.js";
8
+ import { createFolderTool, handleCreateFolder, getFolderTool, handleGetFolder, updateFolderTool, handleUpdateFolder, deleteFolderTool, handleDeleteFolder } from "./tools/folder.js";
9
+ // Initialize ClickUp services
10
+ const services = createClickUpServices({
11
+ apiKey: config.clickupApiKey,
12
+ teamId: config.clickupTeamId
13
+ });
14
+ // Extract the workspace service for use in this module
15
+ const { workspace } = services;
16
+ /**
17
+ * MCP Server for ClickUp integration
18
+ */
19
+ export const server = new Server({
20
+ name: "clickup-mcp-server",
21
+ version: "0.4.61",
22
+ }, {
23
+ capabilities: {
24
+ tools: {},
25
+ prompts: {},
26
+ },
27
+ });
28
+ /**
29
+ * Configure the server routes and handlers
30
+ */
31
+ export function configureServer() {
32
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
33
+ return {
34
+ tools: [
35
+ workspaceHierarchyTool,
36
+ createTaskTool,
37
+ getTaskTool,
38
+ getTasksTool,
39
+ updateTaskTool,
40
+ moveTaskTool,
41
+ duplicateTaskTool,
42
+ deleteTaskTool,
43
+ createBulkTasksTool,
44
+ updateBulkTasksTool,
45
+ moveBulkTasksTool,
46
+ deleteBulkTasksTool,
47
+ createListTool,
48
+ createListInFolderTool,
49
+ getListTool,
50
+ updateListTool,
51
+ deleteListTool,
52
+ createFolderTool,
53
+ getFolderTool,
54
+ updateFolderTool,
55
+ deleteFolderTool
56
+ ]
57
+ };
58
+ });
59
+ server.setRequestHandler(CallToolRequestSchema, async (req) => {
60
+ const { name, arguments: params } = req.params;
61
+ // Handle tool calls by routing to the appropriate handler
62
+ switch (name) {
63
+ case "get_workspace_hierarchy":
64
+ return handleGetWorkspaceHierarchy();
65
+ case "create_task":
66
+ return handleCreateTask(params);
67
+ case "update_task":
68
+ return handleUpdateTask(params);
69
+ case "move_task":
70
+ return handleMoveTask(params);
71
+ case "duplicate_task":
72
+ return handleDuplicateTask(params);
73
+ case "get_task":
74
+ return handleGetTask(params);
75
+ case "get_tasks":
76
+ return handleGetTasks(params);
77
+ case "delete_task":
78
+ return handleDeleteTask(params);
79
+ case "create_bulk_tasks":
80
+ return handleCreateBulkTasks(params);
81
+ case "update_bulk_tasks":
82
+ return handleUpdateBulkTasks(params);
83
+ case "move_bulk_tasks":
84
+ return handleMoveBulkTasks(params);
85
+ case "delete_bulk_tasks":
86
+ return handleDeleteBulkTasks(params);
87
+ case "create_list":
88
+ return handleCreateList(params);
89
+ case "create_list_in_folder":
90
+ return handleCreateListInFolder(params);
91
+ case "get_list":
92
+ return handleGetList(params);
93
+ case "update_list":
94
+ return handleUpdateList(params);
95
+ case "delete_list":
96
+ return handleDeleteList(params);
97
+ case "create_folder":
98
+ return handleCreateFolder(params);
99
+ case "get_folder":
100
+ return handleGetFolder(params);
101
+ case "update_folder":
102
+ return handleUpdateFolder(params);
103
+ case "delete_folder":
104
+ return handleDeleteFolder(params);
105
+ default:
106
+ throw new Error(`Unknown tool: ${name}`);
107
+ }
108
+ });
109
+ server.setRequestHandler(ListPromptsRequestSchema, async () => {
110
+ return { prompts: [] };
111
+ });
112
+ server.setRequestHandler(GetPromptRequestSchema, async () => {
113
+ throw new Error("Prompt not found");
114
+ });
115
+ return server;
116
+ }
117
+ /**
118
+ * Export the clickup service for use in tool handlers
119
+ */
120
+ export { workspace };
@@ -0,0 +1,253 @@
1
+ /**
2
+ * Base ClickUp Service Class
3
+ *
4
+ * This class provides core functionality for all ClickUp service modules:
5
+ * - Axios client configuration
6
+ * - Rate limiting and request throttling
7
+ * - Error handling
8
+ * - Common request methods
9
+ */
10
+ import axios from 'axios';
11
+ /**
12
+ * Error types for better error handling
13
+ */
14
+ export var ErrorCode;
15
+ (function (ErrorCode) {
16
+ ErrorCode["RATE_LIMIT"] = "rate_limit_exceeded";
17
+ ErrorCode["NOT_FOUND"] = "resource_not_found";
18
+ ErrorCode["UNAUTHORIZED"] = "unauthorized";
19
+ ErrorCode["VALIDATION"] = "validation_error";
20
+ ErrorCode["SERVER_ERROR"] = "server_error";
21
+ ErrorCode["NETWORK_ERROR"] = "network_error";
22
+ ErrorCode["WORKSPACE_ERROR"] = "workspace_error";
23
+ ErrorCode["INVALID_PARAMETER"] = "invalid_parameter";
24
+ ErrorCode["UNKNOWN"] = "unknown_error";
25
+ })(ErrorCode || (ErrorCode = {}));
26
+ /**
27
+ * Custom error class for ClickUp API errors
28
+ */
29
+ export class ClickUpServiceError extends Error {
30
+ constructor(message, code = ErrorCode.UNKNOWN, data, status, context) {
31
+ super(message);
32
+ this.name = 'ClickUpServiceError';
33
+ this.code = code;
34
+ this.data = data;
35
+ this.status = status;
36
+ this.context = context;
37
+ }
38
+ }
39
+ /**
40
+ * Base ClickUp service class that handles common functionality
41
+ */
42
+ export class BaseClickUpService {
43
+ /**
44
+ * Creates an instance of BaseClickUpService.
45
+ * @param apiKey - ClickUp API key for authentication
46
+ * @param teamId - ClickUp team ID for targeting the correct workspace
47
+ * @param baseUrl - Optional custom base URL for the ClickUp API
48
+ */
49
+ constructor(apiKey, teamId, baseUrl = 'https://api.clickup.com/api/v2') {
50
+ this.defaultRequestSpacing = 600; // Default milliseconds between requests
51
+ this.rateLimit = 100; // Maximum requests per minute (Free Forever plan)
52
+ this.timeout = 65000; // 65 seconds (safely under the 1-minute window)
53
+ this.requestQueue = [];
54
+ this.processingQueue = false;
55
+ this.lastRateLimitReset = 0;
56
+ this.apiKey = apiKey;
57
+ this.teamId = teamId;
58
+ this.requestSpacing = this.defaultRequestSpacing;
59
+ // Configure the Axios client with default settings
60
+ this.client = axios.create({
61
+ baseURL: baseUrl,
62
+ headers: {
63
+ 'Authorization': apiKey,
64
+ 'Content-Type': 'application/json'
65
+ },
66
+ timeout: this.timeout
67
+ });
68
+ // Add response interceptor for error handling
69
+ this.client.interceptors.response.use(response => response, error => this.handleAxiosError(error));
70
+ }
71
+ /**
72
+ * Handle errors from Axios requests
73
+ * @private
74
+ * @param error Error from Axios
75
+ * @returns Never - always throws an error
76
+ */
77
+ handleAxiosError(error) {
78
+ let message = 'Unknown error occurred';
79
+ let code = ErrorCode.UNKNOWN;
80
+ let details = null;
81
+ let status = undefined;
82
+ if (error.response) {
83
+ // Server responded with an error status code
84
+ status = error.response.status;
85
+ details = error.response.data;
86
+ switch (status) {
87
+ case 401:
88
+ message = 'Unauthorized: Invalid API key';
89
+ code = ErrorCode.UNAUTHORIZED;
90
+ break;
91
+ case 403:
92
+ message = 'Forbidden: Insufficient permissions';
93
+ code = ErrorCode.UNAUTHORIZED;
94
+ break;
95
+ case 404:
96
+ message = 'Resource not found';
97
+ code = ErrorCode.NOT_FOUND;
98
+ break;
99
+ case 429:
100
+ message = 'Rate limit exceeded';
101
+ code = ErrorCode.RATE_LIMIT;
102
+ break;
103
+ case 400:
104
+ message = 'Invalid request: ' + (error.response.data?.err || 'Validation error');
105
+ code = ErrorCode.VALIDATION;
106
+ break;
107
+ case 500:
108
+ case 502:
109
+ case 503:
110
+ case 504:
111
+ message = 'ClickUp server error';
112
+ code = ErrorCode.SERVER_ERROR;
113
+ break;
114
+ default:
115
+ message = `ClickUp API error (${status}): ${error.response.data?.err || 'Unknown error'}`;
116
+ }
117
+ }
118
+ else if (error.request) {
119
+ // Request was made but no response received
120
+ message = 'Network error: No response received from ClickUp';
121
+ code = ErrorCode.NETWORK_ERROR;
122
+ details = { request: error.request };
123
+ }
124
+ else {
125
+ // Error setting up the request
126
+ message = `Request setup error: ${error.message}`;
127
+ details = { message: error.message };
128
+ }
129
+ throw new ClickUpServiceError(message, code, details, status);
130
+ }
131
+ /**
132
+ * Process the request queue, respecting rate limits by spacing out requests
133
+ * @private
134
+ */
135
+ async processQueue() {
136
+ if (this.processingQueue || this.requestQueue.length === 0) {
137
+ return;
138
+ }
139
+ this.processingQueue = true;
140
+ try {
141
+ while (this.requestQueue.length > 0) {
142
+ const request = this.requestQueue.shift();
143
+ if (request) {
144
+ try {
145
+ await request();
146
+ }
147
+ catch (error) {
148
+ console.error('Request failed:', error);
149
+ // Continue processing queue even if one request fails
150
+ }
151
+ // Space out requests to stay within rate limit
152
+ if (this.requestQueue.length > 0) {
153
+ await new Promise(resolve => setTimeout(resolve, this.requestSpacing));
154
+ }
155
+ }
156
+ }
157
+ }
158
+ finally {
159
+ this.processingQueue = false;
160
+ }
161
+ }
162
+ /**
163
+ * Handle rate limit headers from ClickUp API
164
+ * @private
165
+ * @param headers Response headers from ClickUp
166
+ */
167
+ handleRateLimitHeaders(headers) {
168
+ const limit = parseInt(headers['x-ratelimit-limit'], 10);
169
+ const remaining = parseInt(headers['x-ratelimit-remaining'], 10);
170
+ const reset = parseInt(headers['x-ratelimit-reset'], 10);
171
+ if (!isNaN(reset)) {
172
+ this.lastRateLimitReset = reset;
173
+ }
174
+ // If we're running low on remaining requests, increase spacing
175
+ if (!isNaN(remaining) && remaining < 10) {
176
+ const timeUntilReset = (this.lastRateLimitReset * 1000) - Date.now();
177
+ if (timeUntilReset > 0) {
178
+ this.requestSpacing = Math.max(this.defaultRequestSpacing, Math.floor(timeUntilReset / remaining));
179
+ }
180
+ }
181
+ else {
182
+ this.requestSpacing = this.defaultRequestSpacing; // Reset to default spacing
183
+ }
184
+ }
185
+ /**
186
+ * Makes an API request with rate limiting.
187
+ * @protected
188
+ * @param fn - Function that executes the API request
189
+ * @returns Promise that resolves with the result of the API request
190
+ */
191
+ async makeRequest(fn) {
192
+ return new Promise((resolve, reject) => {
193
+ this.requestQueue.push(async () => {
194
+ try {
195
+ const result = await fn();
196
+ // Handle rate limit headers if present
197
+ if (result && typeof result === 'object' && 'headers' in result) {
198
+ this.handleRateLimitHeaders(result.headers);
199
+ }
200
+ resolve(result);
201
+ }
202
+ catch (error) {
203
+ if (axios.isAxiosError(error) && error.response?.status === 429) {
204
+ const retryAfter = parseInt(error.response.headers['retry-after'] || '60', 10);
205
+ const resetTime = parseInt(error.response.headers['x-ratelimit-reset'] || '0', 10);
206
+ // Use the more precise reset time if available
207
+ const waitTime = resetTime > 0 ?
208
+ (resetTime * 1000) - Date.now() :
209
+ retryAfter * 1000;
210
+ await new Promise(resolve => setTimeout(resolve, waitTime));
211
+ try {
212
+ // Retry the request once after waiting
213
+ const result = await fn();
214
+ resolve(result);
215
+ }
216
+ catch (retryError) {
217
+ reject(retryError);
218
+ }
219
+ }
220
+ else {
221
+ reject(error);
222
+ }
223
+ }
224
+ });
225
+ this.processQueue().catch(reject);
226
+ });
227
+ }
228
+ /**
229
+ * Gets the ClickUp team ID associated with this service instance
230
+ * @returns The team ID
231
+ */
232
+ getTeamId() {
233
+ return this.teamId;
234
+ }
235
+ /**
236
+ * Helper method to log API operations
237
+ * @protected
238
+ * @param operation - Name of the operation being performed
239
+ * @param details - Details about the operation
240
+ */
241
+ logOperation(operation, details) {
242
+ // This could be enhanced to use a proper logging framework
243
+ console.log(`[ClickUpService] ${operation}:`, details);
244
+ }
245
+ /**
246
+ * Protected helper method to check if cache is available
247
+ * @param cacheService Optional cache service instance
248
+ * @returns True if caching is available and enabled
249
+ */
250
+ isCacheEnabled(cacheService) {
251
+ return !!cacheService && typeof cacheService.isEnabled === 'function' && cacheService.isEnabled();
252
+ }
253
+ }
@@ -0,0 +1,116 @@
1
+ export class BulkProcessor {
2
+ async processBulk(items, processor, options) {
3
+ const opts = {
4
+ batchSize: options?.batchSize ?? 10,
5
+ concurrency: options?.concurrency ?? 3,
6
+ continueOnError: options?.continueOnError ?? false,
7
+ retryCount: options?.retryCount ?? 3,
8
+ retryDelay: options?.retryDelay ?? 1000,
9
+ exponentialBackoff: options?.exponentialBackoff ?? true,
10
+ onProgress: options?.onProgress ?? (() => { })
11
+ };
12
+ const result = {
13
+ success: true,
14
+ successfulItems: [],
15
+ failedItems: [],
16
+ totalItems: items.length,
17
+ successCount: 0,
18
+ failureCount: 0
19
+ };
20
+ if (items.length === 0)
21
+ return result;
22
+ try {
23
+ const totalBatches = Math.ceil(items.length / opts.batchSize);
24
+ let processedItems = 0;
25
+ for (let batchIndex = 0; batchIndex < totalBatches; batchIndex++) {
26
+ const startIdx = batchIndex * opts.batchSize;
27
+ const endIdx = Math.min(startIdx + opts.batchSize, items.length);
28
+ const batch = items.slice(startIdx, endIdx);
29
+ const batchResults = await this.processBatch(batch, processor, startIdx, opts);
30
+ result.successfulItems.push(...batchResults.successfulItems);
31
+ result.failedItems.push(...batchResults.failedItems);
32
+ result.successCount += batchResults.successCount;
33
+ result.failureCount += batchResults.failureCount;
34
+ if (batchResults.failureCount > 0 && !opts.continueOnError) {
35
+ result.success = false;
36
+ return result;
37
+ }
38
+ processedItems += batch.length;
39
+ opts.onProgress(processedItems, items.length, result.successCount, result.failureCount);
40
+ }
41
+ result.success = result.failedItems.length === 0;
42
+ return result;
43
+ }
44
+ catch (error) {
45
+ const err = error;
46
+ console.error('Failed to process bulk operation:', err.message || String(error));
47
+ result.success = false;
48
+ return result;
49
+ }
50
+ }
51
+ async processBatch(batch, processor, startIndex, opts) {
52
+ const result = {
53
+ success: true,
54
+ successfulItems: [],
55
+ failedItems: [],
56
+ totalItems: batch.length,
57
+ successCount: 0,
58
+ failureCount: 0
59
+ };
60
+ try {
61
+ for (let i = 0; i < batch.length; i += opts.concurrency) {
62
+ const concurrentBatch = batch.slice(i, Math.min(i + opts.concurrency, batch.length));
63
+ const promises = concurrentBatch.map((item, idx) => {
64
+ const index = startIndex + i + idx;
65
+ return this.processWithRetry(() => processor(item, index), index, item, opts);
66
+ });
67
+ const results = await Promise.allSettled(promises);
68
+ results.forEach((promiseResult, idx) => {
69
+ const index = startIndex + i + idx;
70
+ if (promiseResult.status === 'fulfilled') {
71
+ result.successfulItems.push(promiseResult.value);
72
+ result.successCount++;
73
+ }
74
+ else {
75
+ const error = promiseResult.reason;
76
+ result.failedItems.push({ item: batch[i + idx], index, error });
77
+ result.failureCount++;
78
+ if (!opts.continueOnError) {
79
+ result.success = false;
80
+ throw new Error(`Bulk operation failed at index ${index}: ${error.message || String(error)}`);
81
+ }
82
+ }
83
+ });
84
+ }
85
+ return result;
86
+ }
87
+ catch (error) {
88
+ const err = error;
89
+ console.error(`Bulk operation failed: ${err.message || String(error)}`, error);
90
+ result.success = false;
91
+ return result;
92
+ }
93
+ }
94
+ async processWithRetry(operation, index, item, options) {
95
+ let attempts = 1;
96
+ let lastError = new Error('Unknown error');
97
+ while (attempts <= options.retryCount) {
98
+ try {
99
+ return await operation();
100
+ }
101
+ catch (error) {
102
+ const err = error;
103
+ console.warn(`Operation failed for item at index ${index}, attempt ${attempts}/${options.retryCount}: ${err.message || String(error)}`);
104
+ lastError = err;
105
+ if (attempts >= options.retryCount)
106
+ break;
107
+ const delay = options.exponentialBackoff
108
+ ? options.retryDelay * Math.pow(2, attempts) + Math.random() * 1000
109
+ : options.retryDelay * Math.pow(1.5, attempts - 1);
110
+ await new Promise(resolve => setTimeout(resolve, delay));
111
+ attempts++;
112
+ }
113
+ }
114
+ throw new Error(`Operation failed after ${attempts} attempts for item at index ${index}: ${lastError?.message || 'Unknown error'}`);
115
+ }
116
+ }
@@ -0,0 +1,133 @@
1
+ /**
2
+ * ClickUp Folder Service
3
+ *
4
+ * Handles all operations related to folders in ClickUp, including:
5
+ * - Creating folders
6
+ * - Retrieving folders
7
+ * - Updating folders
8
+ * - Deleting folders
9
+ * - Finding folders by name
10
+ */
11
+ import { BaseClickUpService, ErrorCode, ClickUpServiceError } from './base.js';
12
+ export class FolderService extends BaseClickUpService {
13
+ /**
14
+ * Creates an instance of FolderService
15
+ * @param apiKey - ClickUp API key
16
+ * @param teamId - ClickUp team ID
17
+ * @param baseUrl - Optional custom API URL
18
+ * @param workspaceService - Optional workspace service for lookups
19
+ */
20
+ constructor(apiKey, teamId, baseUrl, workspaceService) {
21
+ super(apiKey, teamId, baseUrl);
22
+ this.workspaceService = null;
23
+ this.workspaceService = workspaceService || null;
24
+ }
25
+ /**
26
+ * Helper method to handle errors consistently
27
+ * @param error The error that occurred
28
+ * @param message Optional custom error message
29
+ * @returns A ClickUpServiceError
30
+ */
31
+ handleError(error, message) {
32
+ if (error instanceof ClickUpServiceError) {
33
+ return error;
34
+ }
35
+ return new ClickUpServiceError(message || `Folder service error: ${error.message}`, ErrorCode.UNKNOWN, error);
36
+ }
37
+ /**
38
+ * Create a new folder in a space
39
+ * @param spaceId The ID of the space to create the folder in
40
+ * @param folderData The data for the new folder
41
+ * @returns The created folder
42
+ */
43
+ async createFolder(spaceId, folderData) {
44
+ try {
45
+ this.logOperation('createFolder', { spaceId, ...folderData });
46
+ const response = await this.client.post(`/space/${spaceId}/folder`, folderData);
47
+ return response.data;
48
+ }
49
+ catch (error) {
50
+ throw this.handleError(error, `Failed to create folder in space ${spaceId}`);
51
+ }
52
+ }
53
+ /**
54
+ * Get a folder by its ID
55
+ * @param folderId The ID of the folder to retrieve
56
+ * @returns The folder details
57
+ */
58
+ async getFolder(folderId) {
59
+ try {
60
+ this.logOperation('getFolder', { folderId });
61
+ const response = await this.client.get(`/folder/${folderId}`);
62
+ return response.data;
63
+ }
64
+ catch (error) {
65
+ throw this.handleError(error, `Failed to get folder ${folderId}`);
66
+ }
67
+ }
68
+ /**
69
+ * Update an existing folder
70
+ * @param folderId The ID of the folder to update
71
+ * @param updateData The data to update on the folder
72
+ * @returns The updated folder
73
+ */
74
+ async updateFolder(folderId, updateData) {
75
+ try {
76
+ this.logOperation('updateFolder', { folderId, ...updateData });
77
+ const response = await this.client.put(`/folder/${folderId}`, updateData);
78
+ return response.data;
79
+ }
80
+ catch (error) {
81
+ throw this.handleError(error, `Failed to update folder ${folderId}`);
82
+ }
83
+ }
84
+ /**
85
+ * Delete a folder
86
+ * @param folderId The ID of the folder to delete
87
+ * @returns Success indicator
88
+ */
89
+ async deleteFolder(folderId) {
90
+ try {
91
+ this.logOperation('deleteFolder', { folderId });
92
+ await this.client.delete(`/folder/${folderId}`);
93
+ return {
94
+ success: true
95
+ };
96
+ }
97
+ catch (error) {
98
+ throw this.handleError(error, `Failed to delete folder ${folderId}`);
99
+ }
100
+ }
101
+ /**
102
+ * Get all folders in a space
103
+ * @param spaceId The ID of the space to get folders from
104
+ * @returns Array of folders in the space
105
+ */
106
+ async getFoldersInSpace(spaceId) {
107
+ this.logOperation('getFoldersInSpace', { spaceId });
108
+ try {
109
+ const response = await this.client.get(`/space/${spaceId}/folder`);
110
+ return response.data.folders;
111
+ }
112
+ catch (error) {
113
+ throw this.handleError(error, `Failed to get folders in space ${spaceId}`);
114
+ }
115
+ }
116
+ /**
117
+ * Find a folder by its name in a space
118
+ * @param spaceId The ID of the space to search in
119
+ * @param folderName The name of the folder to find
120
+ * @returns The folder if found, otherwise null
121
+ */
122
+ async findFolderByName(spaceId, folderName) {
123
+ this.logOperation('findFolderByName', { spaceId, folderName });
124
+ try {
125
+ const folders = await this.getFoldersInSpace(spaceId);
126
+ const matchingFolder = folders.find(folder => folder.name.toLowerCase() === folderName.toLowerCase());
127
+ return matchingFolder || null;
128
+ }
129
+ catch (error) {
130
+ throw this.handleError(error, `Failed to find folder by name in space ${spaceId}`);
131
+ }
132
+ }
133
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * ClickUp Service Entry Point
3
+ *
4
+ * This file re-exports all service modules for the ClickUp API integration.
5
+ * It also provides a convenient factory method to create instances of all services.
6
+ */
7
+ // Export base service components
8
+ export { BaseClickUpService, ClickUpServiceError, ErrorCode } from './base.js';
9
+ // Export type definitions
10
+ export * from './types.js';
11
+ // Export service modules
12
+ export { WorkspaceService } from './workspace.js';
13
+ export { TaskService } from './task.js';
14
+ export { ListService } from './list.js';
15
+ export { FolderService } from './folder.js';
16
+ export { InitializationService } from './initialization.js';
17
+ // Import service classes for the factory function
18
+ import { WorkspaceService } from './workspace.js';
19
+ import { TaskService } from './task.js';
20
+ import { ListService } from './list.js';
21
+ import { FolderService } from './folder.js';
22
+ import { InitializationService } from './initialization.js';
23
+ /**
24
+ * Factory function to create instances of all ClickUp services
25
+ * @param config Configuration for the services
26
+ * @returns Object containing all service instances
27
+ */
28
+ export function createClickUpServices(config) {
29
+ const { apiKey, teamId, baseUrl } = config;
30
+ // Create the workspace service
31
+ const workspaceService = new WorkspaceService(apiKey, teamId, baseUrl);
32
+ return {
33
+ workspace: workspaceService,
34
+ task: new TaskService(apiKey, teamId, baseUrl, workspaceService),
35
+ list: new ListService(apiKey, teamId, baseUrl, workspaceService),
36
+ folder: new FolderService(apiKey, teamId, baseUrl, workspaceService),
37
+ initialization: new InitializationService({
38
+ apiKey,
39
+ teamId,
40
+ baseUrl
41
+ })
42
+ };
43
+ }