@taazkareem/clickup-mcp-server 0.1.7 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,15 +1,41 @@
1
1
  # ClickUp MCP Server
2
2
 
3
- A Model Context Protocol (MCP) server for integrating ClickUp tasks with AI applications. This server allows AI agents to interact with ClickUp tasks, spaces, and lists through a standardized protocol.
3
+ 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.
4
4
 
5
5
  ## Features
6
6
 
7
- - 🔄 List and read ClickUp tasks as resources
8
- - Create and update tasks through tools
9
- - 📊 Get spaces and lists with their IDs
10
- - 📝 Generate task descriptions with AI
11
- - 📋 Summarize tasks and analyze priorities
12
- - 🔒 Secure API key management
7
+ - 🔄 **Resource Management**
8
+ - List and read ClickUp tasks as resources
9
+ - View task details, status, and assignments
10
+ - Access task history and relationships
11
+
12
+ - 📂 **Workspace Organization**
13
+ - Create and manage spaces
14
+ - Create, update, and delete folders
15
+ - Create and manage lists (in spaces or folders)
16
+ - Flexible identification using IDs or names
17
+
18
+ - ✨ **Task Operations**
19
+ - Create and update tasks
20
+ - Move tasks between lists
21
+ - Duplicate tasks
22
+ - Set priorities and due dates
23
+ - Assign team members
24
+
25
+ - 📊 **Information Retrieval**
26
+ - Get spaces and lists with their IDs
27
+ - List available statuses
28
+ - Find items by name (case-insensitive)
29
+ - View task relationships
30
+
31
+ - 📝 **AI Integration**
32
+ - Generate task descriptions with AI
33
+ - Summarize tasks and analyze priorities
34
+ - Get AI-powered task recommendations
35
+
36
+ - 🔒 **Security**
37
+ - Secure API key management
38
+ - Environment-based configuration
13
39
 
14
40
  ## Installation
15
41
 
@@ -43,6 +69,7 @@ clickup-mcp-server
43
69
 
44
70
  1. **list_spaces**
45
71
  - Lists all spaces and their lists with IDs
72
+ - Shows available statuses for each list
46
73
  - No parameters required
47
74
 
48
75
  2. **create_task**
@@ -55,51 +82,131 @@ clickup-mcp-server
55
82
  - `status`: Task status
56
83
  - `priority`: Priority level (1-4)
57
84
  - `dueDate`: Due date (ISO string)
85
+ - `assignees`: Array of user IDs
58
86
 
59
- 3. **update_task**
87
+ 3. **create_list**
88
+ - Creates a new list in a space
89
+ - Required parameters:
90
+ - `name`: Name of the list
91
+ - Optional parameters:
92
+ - `spaceId`: ID of the space (optional if spaceName provided)
93
+ - `spaceName`: Name of the space (optional if spaceId provided)
94
+ - `content`: List description
95
+ - `status`: List status
96
+ - `priority`: Priority level (1-4)
97
+ - `dueDate`: Due date (ISO string)
98
+
99
+ 4. **create_folder**
100
+ - Creates a new folder in a space
101
+ - Required parameters:
102
+ - `name`: Name of the folder
103
+ - Optional parameters:
104
+ - `spaceId`: ID of the space (optional if spaceName provided)
105
+ - `spaceName`: Name of the space (optional if spaceId provided)
106
+ - `override_statuses`: Whether to override space statuses
107
+
108
+ 5. **create_list_in_folder**
109
+ - Creates a new list within a folder
110
+ - Required parameters:
111
+ - `name`: Name of the list
112
+ - Optional parameters:
113
+ - `folderId`: ID of the folder (optional if using folderName)
114
+ - `folderName`: Name of the folder
115
+ - `spaceId`: ID of the space (required if using folderName)
116
+ - `spaceName`: Name of the space (alternative to spaceId)
117
+ - `content`: List description
118
+ - `status`: List status
119
+
120
+ 6. **move_task**
121
+ - Moves a task to a different list
122
+ - Required parameters:
123
+ - `taskId`: ID of the task to move
124
+ - `listId`: ID of the destination list
125
+
126
+ 7. **duplicate_task**
127
+ - Creates a copy of a task in a specified list
128
+ - Required parameters:
129
+ - `taskId`: ID of the task to duplicate
130
+ - `listId`: ID of the destination list
131
+
132
+ 8. **update_task**
60
133
  - Updates an existing task
61
134
  - Required parameters:
62
135
  - `taskId`: ID of the task to update
63
136
  - Optional parameters:
64
- - Same as create_task
137
+ - `name`: New task name
138
+ - `description`: New description
139
+ - `status`: New status
140
+ - `priority`: New priority level (1-4)
141
+ - `dueDate`: New due date (ISO string)
65
142
 
66
143
  ### Available Prompts
67
144
 
68
145
  1. **summarize_tasks**
69
- - Provides a summary of all tasks
70
- - Groups by status and highlights priorities
146
+ - Provides a comprehensive summary of tasks
147
+ - Groups tasks by status
148
+ - Highlights priorities and deadlines
149
+ - Suggests task relationships
71
150
 
72
151
  2. **analyze_priorities**
73
- - Analyzes task priorities
74
- - Suggests optimizations and sequencing
152
+ - Analyzes task priority distribution
153
+ - Identifies misaligned priorities
154
+ - Suggests priority adjustments
155
+ - Recommends task sequencing
75
156
 
76
157
  3. **generate_description**
77
158
  - Helps generate detailed task descriptions
78
- - Includes objectives, criteria, and dependencies
159
+ - Includes:
160
+ - Clear objectives
161
+ - Success criteria
162
+ - Required resources
163
+ - Dependencies
164
+ - Potential risks
165
+
166
+ ## Name Resolution
167
+
168
+ Most tools support finding items by either ID or name:
169
+ - Spaces can be referenced by `spaceId` or `spaceName`
170
+ - Folders can be referenced by `folderId` or `folderName` (with space information)
171
+ - Lists can be referenced by `listId` or found within spaces/folders
172
+
173
+ Name matching is case-insensitive for convenience.
174
+
175
+ ## Error Handling
176
+
177
+ The server provides clear error messages for common scenarios:
178
+ - Missing required parameters
179
+ - Invalid IDs or names
180
+ - Items not found
181
+ - Permission issues
182
+ - API errors
79
183
 
80
184
  ## Using with Cursor AI Composer
81
185
 
82
- To add this server to Cursor AI Composer:
186
+ To add this server to Cursor AI Composer, follow these steps:
187
+
188
+ 1. Go to the Features section in the settings.
189
+ 2. Add the following command under MCP Servers:
83
190
 
84
191
  ```bash
85
192
  npx -y @taazkareem/clickup-mcp-server \
86
193
  --env CLICKUP_API_KEY=your_api_key_here \
87
194
  --env TEAM_ID=your_team_id_here
88
195
  ```
196
+ 3. Replace `your_api_key_here` and `your_team_id_here` with your actual ClickUp credentials.
197
+ 4. Click on 'Save' to add the server.
89
198
 
90
199
  You can get these values from:
91
200
  - `CLICKUP_API_KEY`: Get from [ClickUp Settings > Apps](https://app.clickup.com/settings/apps)
92
201
  - `TEAM_ID`: Your ClickUp Team ID (found in the URL when viewing your workspace or via API)
93
202
 
94
- > ⚠️ **Important**: Make sure to replace `your_api_key_here` and `your_team_id_here` with your actual ClickUp credentials.
95
-
96
203
  > **Security Note**: Your API key will be stored securely and will not be exposed to AI models.
97
204
 
98
205
  ## Development
99
206
 
100
207
  1. Clone the repository:
101
208
  ```bash
102
- git clone https://github.com/yourusername/clickup-mcp-server.git
209
+ git clone https://github.com/taazkareem/clickup-mcp-server.git
103
210
  cd clickup-mcp-server
104
211
  ```
105
212
 
@@ -119,4 +226,4 @@ Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md)
119
226
 
120
227
  ## License
121
228
 
122
- This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
229
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
package/build/index.js CHANGED
@@ -143,6 +143,148 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
143
143
  required: ["listId", "name"]
144
144
  }
145
145
  },
146
+ {
147
+ name: "create_list",
148
+ description: "Create a new list in a ClickUp space",
149
+ inputSchema: {
150
+ type: "object",
151
+ properties: {
152
+ spaceId: {
153
+ type: "string",
154
+ description: "ID of the space to create the list in (optional if spaceName is provided)"
155
+ },
156
+ spaceName: {
157
+ type: "string",
158
+ description: "Name of the space to create the list in (optional if spaceId is provided)"
159
+ },
160
+ name: {
161
+ type: "string",
162
+ description: "Name of the list"
163
+ },
164
+ content: {
165
+ type: "string",
166
+ description: "Description or content of the list"
167
+ },
168
+ dueDate: {
169
+ type: "string",
170
+ description: "Due date for the list (ISO string)"
171
+ },
172
+ priority: {
173
+ type: "number",
174
+ description: "Priority of the list (1-4)"
175
+ },
176
+ assignee: {
177
+ type: "number",
178
+ description: "User ID to assign the list to"
179
+ },
180
+ status: {
181
+ type: "string",
182
+ description: "Status of the list"
183
+ }
184
+ },
185
+ required: ["name"]
186
+ }
187
+ },
188
+ {
189
+ name: "create_folder",
190
+ description: "Create a new folder in a ClickUp space",
191
+ inputSchema: {
192
+ type: "object",
193
+ properties: {
194
+ spaceId: {
195
+ type: "string",
196
+ description: "ID of the space to create the folder in (optional if spaceName is provided)"
197
+ },
198
+ spaceName: {
199
+ type: "string",
200
+ description: "Name of the space to create the folder in (optional if spaceId is provided)"
201
+ },
202
+ name: {
203
+ type: "string",
204
+ description: "Name of the folder"
205
+ },
206
+ override_statuses: {
207
+ type: "boolean",
208
+ description: "Whether to override space statuses"
209
+ }
210
+ },
211
+ required: ["name"]
212
+ }
213
+ },
214
+ {
215
+ name: "create_list_in_folder",
216
+ description: "Create a new list in a ClickUp folder",
217
+ inputSchema: {
218
+ type: "object",
219
+ properties: {
220
+ folderId: {
221
+ type: "string",
222
+ description: "ID of the folder to create the list in (optional if folderName and spaceId/spaceName are provided)"
223
+ },
224
+ folderName: {
225
+ type: "string",
226
+ description: "Name of the folder to create the list in"
227
+ },
228
+ spaceId: {
229
+ type: "string",
230
+ description: "ID of the space containing the folder (required if using folderName)"
231
+ },
232
+ spaceName: {
233
+ type: "string",
234
+ description: "Name of the space containing the folder (alternative to spaceId)"
235
+ },
236
+ name: {
237
+ type: "string",
238
+ description: "Name of the list"
239
+ },
240
+ content: {
241
+ type: "string",
242
+ description: "Description or content of the list"
243
+ },
244
+ status: {
245
+ type: "string",
246
+ description: "Status of the list"
247
+ }
248
+ },
249
+ required: ["name"]
250
+ }
251
+ },
252
+ {
253
+ name: "move_task",
254
+ description: "Move a task to a different list",
255
+ inputSchema: {
256
+ type: "object",
257
+ properties: {
258
+ taskId: {
259
+ type: "string",
260
+ description: "ID of the task to move"
261
+ },
262
+ listId: {
263
+ type: "string",
264
+ description: "ID of the destination list"
265
+ }
266
+ },
267
+ required: ["taskId", "listId"]
268
+ }
269
+ },
270
+ {
271
+ name: "duplicate_task",
272
+ description: "Duplicate a task to a list",
273
+ inputSchema: {
274
+ type: "object",
275
+ properties: {
276
+ taskId: {
277
+ type: "string",
278
+ description: "ID of the task to duplicate"
279
+ },
280
+ listId: {
281
+ type: "string",
282
+ description: "ID of the list to create the duplicate in"
283
+ }
284
+ },
285
+ required: ["taskId", "listId"]
286
+ }
287
+ },
146
288
  {
147
289
  name: "update_task",
148
290
  description: "Update an existing task in ClickUp",
@@ -232,6 +374,118 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
232
374
  }]
233
375
  };
234
376
  }
377
+ case "create_list": {
378
+ const args = request.params.arguments;
379
+ if (!args.name) {
380
+ throw new Error("name is required");
381
+ }
382
+ let spaceId = args.spaceId;
383
+ if (!spaceId && args.spaceName) {
384
+ const space = await clickup.findSpaceByName(config.teamId, args.spaceName);
385
+ if (!space) {
386
+ throw new Error(`Space with name "${args.spaceName}" not found`);
387
+ }
388
+ spaceId = space.id;
389
+ }
390
+ if (!spaceId) {
391
+ throw new Error("Either spaceId or spaceName must be provided");
392
+ }
393
+ const { spaceId: _, spaceName: __, ...listData } = args;
394
+ const list = await clickup.createList(spaceId, listData);
395
+ return {
396
+ content: [{
397
+ type: "text",
398
+ text: `Created list ${list.id}: ${list.name}`
399
+ }]
400
+ };
401
+ }
402
+ case "create_folder": {
403
+ const args = request.params.arguments;
404
+ if (!args.name) {
405
+ throw new Error("name is required");
406
+ }
407
+ let spaceId = args.spaceId;
408
+ if (!spaceId && args.spaceName) {
409
+ const space = await clickup.findSpaceByName(config.teamId, args.spaceName);
410
+ if (!space) {
411
+ throw new Error(`Space with name "${args.spaceName}" not found`);
412
+ }
413
+ spaceId = space.id;
414
+ }
415
+ if (!spaceId) {
416
+ throw new Error("Either spaceId or spaceName must be provided");
417
+ }
418
+ const { spaceId: _, spaceName: __, ...folderData } = args;
419
+ const folder = await clickup.createFolder(spaceId, folderData);
420
+ return {
421
+ content: [{
422
+ type: "text",
423
+ text: `Created folder ${folder.id}: ${folder.name}`
424
+ }]
425
+ };
426
+ }
427
+ case "create_list_in_folder": {
428
+ const args = request.params.arguments;
429
+ if (!args.name) {
430
+ throw new Error("name is required");
431
+ }
432
+ let folderId = args.folderId;
433
+ if (!folderId && args.folderName) {
434
+ let spaceId = args.spaceId;
435
+ if (!spaceId && args.spaceName) {
436
+ const space = await clickup.findSpaceByName(config.teamId, args.spaceName);
437
+ if (!space) {
438
+ throw new Error(`Space with name "${args.spaceName}" not found`);
439
+ }
440
+ spaceId = space.id;
441
+ }
442
+ if (!spaceId) {
443
+ throw new Error("Either spaceId or spaceName must be provided when using folderName");
444
+ }
445
+ const folder = await clickup.findFolderByName(spaceId, args.folderName);
446
+ if (!folder) {
447
+ throw new Error(`Folder with name "${args.folderName}" not found`);
448
+ }
449
+ folderId = folder.id;
450
+ }
451
+ if (!folderId) {
452
+ throw new Error("Either folderId or folderName (with space information) must be provided");
453
+ }
454
+ const { folderId: _, folderName: __, spaceId: ___, spaceName: ____, ...listData } = args;
455
+ const list = await clickup.createListInFolder(folderId, listData);
456
+ return {
457
+ content: [{
458
+ type: "text",
459
+ text: `Created list ${list.id}: ${list.name} in folder`
460
+ }]
461
+ };
462
+ }
463
+ case "move_task": {
464
+ const args = request.params.arguments;
465
+ if (!args.taskId || !args.listId) {
466
+ throw new Error("taskId and listId are required");
467
+ }
468
+ const task = await clickup.moveTask(args.taskId, args.listId);
469
+ return {
470
+ content: [{
471
+ type: "text",
472
+ text: `Moved task ${task.id} to list ${args.listId}`
473
+ }]
474
+ };
475
+ }
476
+ case "duplicate_task": {
477
+ const args = request.params.arguments;
478
+ if (!args.taskId || !args.listId) {
479
+ throw new Error("taskId and listId are required");
480
+ }
481
+ const task = await clickup.duplicateTask(args.taskId, args.listId);
482
+ return {
483
+ content: [{
484
+ type: "text",
485
+ text: `Duplicated task ${args.taskId} to new task ${task.id} in list ${args.listId}`
486
+ }]
487
+ };
488
+ }
235
489
  case "update_task": {
236
490
  const args = request.params.arguments;
237
491
  if (!args.taskId) {
@@ -67,4 +67,60 @@ export class ClickUpService {
67
67
  const response = await this.client.get(`/space/${spaceId}`);
68
68
  return response.data;
69
69
  }
70
+ async findSpaceByName(teamId, spaceName) {
71
+ const spaces = await this.getSpaces(teamId);
72
+ return spaces.find(space => space.name.toLowerCase() === spaceName.toLowerCase()) || null;
73
+ }
74
+ async createList(spaceId, data) {
75
+ const response = await this.client.post(`/space/${spaceId}/list`, data);
76
+ return response.data;
77
+ }
78
+ // Folders
79
+ async getFolders(spaceId) {
80
+ const response = await this.client.get(`/space/${spaceId}/folder`);
81
+ return response.data.folders;
82
+ }
83
+ async getFolder(folderId) {
84
+ const response = await this.client.get(`/folder/${folderId}`);
85
+ return response.data;
86
+ }
87
+ async createFolder(spaceId, data) {
88
+ const response = await this.client.post(`/space/${spaceId}/folder`, data);
89
+ return response.data;
90
+ }
91
+ async deleteFolder(folderId) {
92
+ await this.client.delete(`/folder/${folderId}`);
93
+ }
94
+ async createListInFolder(folderId, data) {
95
+ const response = await this.client.post(`/folder/${folderId}/list`, data);
96
+ return response.data;
97
+ }
98
+ async findFolderByName(spaceId, folderName) {
99
+ const folders = await this.getFolders(spaceId);
100
+ return folders.find(folder => folder.name.toLowerCase() === folderName.toLowerCase()) || null;
101
+ }
102
+ // Additional helper methods
103
+ async moveTask(taskId, listId) {
104
+ const response = await this.client.post(`/task/${taskId}`, {
105
+ list: listId
106
+ });
107
+ return response.data;
108
+ }
109
+ async duplicateTask(taskId, listId) {
110
+ const response = await this.client.post(`/task/${taskId}/duplicate`, {
111
+ list: listId
112
+ });
113
+ return response.data;
114
+ }
115
+ async deleteList(listId) {
116
+ await this.client.delete(`/list/${listId}`);
117
+ }
118
+ async updateList(listId, data) {
119
+ const response = await this.client.put(`/list/${listId}`, data);
120
+ return response.data;
121
+ }
122
+ async findListByName(spaceId, listName) {
123
+ const lists = await this.getLists(spaceId);
124
+ return lists.find(list => list.name.toLowerCase() === listName.toLowerCase()) || null;
125
+ }
70
126
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taazkareem/clickup-mcp-server",
3
- "version": "0.1.7",
3
+ "version": "0.2.0",
4
4
  "description": "ClickUp MCP Server - Integrate ClickUp tasks with AI through Model Context Protocol",
5
5
  "type": "module",
6
6
  "main": "build/index.js",