@taazkareem/clickup-mcp-server 0.2.1 → 0.2.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 +46 -244
- package/build/config.js +5 -7
- package/build/index.js +3 -3
- package/build/services/clickup.js +16 -16
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,38 +2,20 @@
|
|
|
2
2
|
|
|
3
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
|
-
## Quick Start
|
|
5
|
+
## Quick Start
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
```bash
|
|
9
|
-
npm install -g @taazkareem/clickup-mcp-server
|
|
10
|
-
```
|
|
7
|
+
Directions for use with Cursor Composer Agent:
|
|
11
8
|
|
|
12
|
-
|
|
9
|
+
1. Get your credentials:
|
|
13
10
|
- ClickUp API key from [ClickUp Settings](https://app.clickup.com/settings/apps)
|
|
14
11
|
- Team ID from your ClickUp workspace URL
|
|
15
|
-
|
|
16
|
-
3.
|
|
17
|
-
```bash
|
|
18
|
-
clickup-mcp-server --env CLICKUP_API_KEY=your_api_key_here --env TEAM_ID=your_team_id_here
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
> **Security Note**: Your API key will be stored securely and not exposed to AI models.
|
|
22
|
-
|
|
23
|
-
## Using with Cursor AI Composer
|
|
24
|
-
|
|
25
|
-
1. Go to Features in settings
|
|
26
|
-
2. Add under MCP Servers:
|
|
27
|
-
```bash
|
|
28
|
-
clickup-mcp-server --env CLICKUP_API_KEY=your_api_key_here --env TEAM_ID=your_team_id_here
|
|
29
|
-
```
|
|
30
|
-
3. Replace the credentials and click Save
|
|
31
|
-
|
|
32
|
-
## Alternative Installation
|
|
33
|
-
Run directly without installing:
|
|
12
|
+
2. Go to Features in settings
|
|
13
|
+
3. Add under MCP Servers:
|
|
34
14
|
```bash
|
|
35
|
-
npx @taazkareem/clickup-mcp-server --env CLICKUP_API_KEY=your_api_key_here --env
|
|
15
|
+
npx -y @taazkareem/clickup-mcp-server --env CLICKUP_API_KEY=your_api_key_here --env CLICKUP_TEAM_ID=your_team_id_here
|
|
36
16
|
```
|
|
17
|
+
4. Replace the credentials and click Save
|
|
18
|
+
5. Use Natural Language to interact with your ClickUp Workspace!
|
|
37
19
|
|
|
38
20
|
## Features
|
|
39
21
|
|
|
@@ -65,224 +47,44 @@ npx @taazkareem/clickup-mcp-server --env CLICKUP_API_KEY=your_api_key_here --env
|
|
|
65
47
|
|
|
66
48
|
## Available Tools
|
|
67
49
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
3. **get_task**
|
|
107
|
-
- Gets detailed information about a specific task
|
|
108
|
-
- Task Identification (required):
|
|
109
|
-
```
|
|
110
|
-
taskId: "123" # Task ID from ClickUp
|
|
111
|
-
-- OR --
|
|
112
|
-
taskName: "My Task" # Task name (case insensitive)
|
|
113
|
-
```
|
|
114
|
-
- Optional:
|
|
115
|
-
```
|
|
116
|
-
listName: "My List" # Narrow search to specific list
|
|
117
|
-
```
|
|
118
|
-
- Returns full task details including attachments and custom fields
|
|
119
|
-
|
|
120
|
-
4. **create_task**
|
|
121
|
-
- Creates a new task in ClickUp
|
|
122
|
-
- List Identification (required):
|
|
123
|
-
```
|
|
124
|
-
listId: "123" # List ID from ClickUp
|
|
125
|
-
-- OR --
|
|
126
|
-
listName: "My List" # List name (case insensitive)
|
|
127
|
-
```
|
|
128
|
-
- Task Details:
|
|
129
|
-
```
|
|
130
|
-
# Required
|
|
131
|
-
taskName: "New Task" # Name of the task to create
|
|
132
|
-
|
|
133
|
-
# Optional
|
|
134
|
-
description: "..." # Task description (markdown supported)
|
|
135
|
-
status: "In Progress" # Task status
|
|
136
|
-
priority: 1-4 # Priority level (1=Urgent, 4=Low)
|
|
137
|
-
dueDate: timestamp # Due date
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
5. **create_bulk_tasks**
|
|
141
|
-
- Creates multiple tasks in a list
|
|
142
|
-
- List Identification (required):
|
|
143
|
-
```
|
|
144
|
-
listId: "123" # List ID from ClickUp
|
|
145
|
-
-- OR --
|
|
146
|
-
listName: "My List" # List name (case insensitive)
|
|
147
|
-
```
|
|
148
|
-
- Tasks Array (required):
|
|
149
|
-
```
|
|
150
|
-
tasks: [
|
|
151
|
-
{
|
|
152
|
-
taskName: "Task 1", # Required
|
|
153
|
-
description: "...", # Optional
|
|
154
|
-
status: "In Progress", # Optional
|
|
155
|
-
priority: 1-4, # Optional
|
|
156
|
-
dueDate: timestamp # Optional
|
|
157
|
-
},
|
|
158
|
-
// ... more tasks
|
|
159
|
-
]
|
|
160
|
-
```
|
|
161
|
-
- Handles rate limiting automatically
|
|
162
|
-
|
|
163
|
-
6. **update_task**
|
|
164
|
-
- Updates an existing task
|
|
165
|
-
- Task Identification (required):
|
|
166
|
-
```
|
|
167
|
-
taskId: "123" # Task ID from ClickUp
|
|
168
|
-
-- OR --
|
|
169
|
-
taskName: "My Task" # Task name (case insensitive)
|
|
170
|
-
```
|
|
171
|
-
- Optional Updates:
|
|
172
|
-
```
|
|
173
|
-
listName: "My List" # Narrow search to specific list
|
|
174
|
-
newName: "Updated Task" # New task name
|
|
175
|
-
description: "..." # New description
|
|
176
|
-
status: "Done" # New status
|
|
177
|
-
priority: 1-4 # New priority
|
|
178
|
-
dueDate: timestamp # New due date
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
7. **delete_task**
|
|
182
|
-
- Permanently deletes a task
|
|
183
|
-
- Task Identification (required):
|
|
184
|
-
```
|
|
185
|
-
taskId: "123" # Task ID from ClickUp
|
|
186
|
-
-- OR --
|
|
187
|
-
taskName: "My Task" # Task name (case insensitive)
|
|
188
|
-
```
|
|
189
|
-
- Optional:
|
|
190
|
-
```
|
|
191
|
-
listName: "My List" # Narrow search to specific list
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
8. **move_task**
|
|
195
|
-
- Moves a task to a different list
|
|
196
|
-
- Source Task (required):
|
|
197
|
-
```
|
|
198
|
-
taskId: "123" # Task ID from ClickUp
|
|
199
|
-
-- OR --
|
|
200
|
-
taskName: "My Task" # Task name (case insensitive)
|
|
201
|
-
```
|
|
202
|
-
- Destination List (required):
|
|
203
|
-
```
|
|
204
|
-
destinationListId: "456" # Target list ID
|
|
205
|
-
-- OR --
|
|
206
|
-
destinationListName: "My List" # Target list name
|
|
207
|
-
```
|
|
208
|
-
- Optional:
|
|
209
|
-
```
|
|
210
|
-
sourceListName: "Old List" # Narrow task search to specific list
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
9. **duplicate_task**
|
|
214
|
-
- Creates a copy of a task in specified list
|
|
215
|
-
- Source Task (required):
|
|
216
|
-
```
|
|
217
|
-
taskId: "123" # Task ID from ClickUp
|
|
218
|
-
-- OR --
|
|
219
|
-
taskName: "My Task" # Task name (case insensitive)
|
|
220
|
-
```
|
|
221
|
-
- Destination List (required):
|
|
222
|
-
```
|
|
223
|
-
destinationListId: "456" # Target list ID
|
|
224
|
-
-- OR --
|
|
225
|
-
destinationListName: "My List" # Target list name
|
|
226
|
-
```
|
|
227
|
-
- Optional:
|
|
228
|
-
```
|
|
229
|
-
sourceListName: "Current List" # Narrow task search to specific list
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
10. **create_list**
|
|
233
|
-
- Creates a new list in a space
|
|
234
|
-
- Space Identification (required):
|
|
235
|
-
```
|
|
236
|
-
spaceId: "123" # Space ID from ClickUp
|
|
237
|
-
-- OR --
|
|
238
|
-
spaceName: "My Space" # Space name (case insensitive)
|
|
239
|
-
```
|
|
240
|
-
- List Details:
|
|
241
|
-
```
|
|
242
|
-
# Required
|
|
243
|
-
listName: "New List" # Name for the new list
|
|
244
|
-
|
|
245
|
-
# Optional
|
|
246
|
-
content: "..." # List description
|
|
247
|
-
dueDate: timestamp # List due date
|
|
248
|
-
priority: 1-4 # List priority
|
|
249
|
-
assignee: "user_id" # Assign to user
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
11. **create_folder**
|
|
253
|
-
- Creates a new folder in a space
|
|
254
|
-
- Space Identification (required):
|
|
255
|
-
```
|
|
256
|
-
spaceId: "123" # Space ID from ClickUp
|
|
257
|
-
-- OR --
|
|
258
|
-
spaceName: "My Space" # Space name (case insensitive)
|
|
259
|
-
```
|
|
260
|
-
- Folder Details:
|
|
261
|
-
```
|
|
262
|
-
# Required
|
|
263
|
-
folderName: "New Folder" # Name for the new folder
|
|
264
|
-
|
|
265
|
-
# Optional
|
|
266
|
-
overrideStatuses: true/false # Override space statuses
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
12. **create_list_in_folder**
|
|
270
|
-
- Creates a new list within a folder
|
|
271
|
-
- Folder Identification (required):
|
|
272
|
-
```
|
|
273
|
-
folderId: "123" # Folder ID from ClickUp
|
|
274
|
-
-- OR --
|
|
275
|
-
folderName: "My Folder" # Folder name (case insensitive)
|
|
276
|
-
```
|
|
277
|
-
- List Details:
|
|
278
|
-
```
|
|
279
|
-
# Required
|
|
280
|
-
listName: "New List" # Name for the new list
|
|
281
|
-
|
|
282
|
-
# Optional
|
|
283
|
-
content: "..." # List description
|
|
284
|
-
status: "Active" # Initial list status
|
|
285
|
-
```
|
|
50
|
+
### Workspace Tools
|
|
51
|
+
**get_workspace_hierarchy**
|
|
52
|
+
Returns complete workspace structure (spaces, folders, lists). No parameters required.
|
|
53
|
+
|
|
54
|
+
### Task Tools
|
|
55
|
+
**get_tasks** `(listId|listName)`
|
|
56
|
+
Get tasks from list with optional filters (archived, page, order_by, reverse, subtasks, statuses, include_closed, assignees, due_date_gt/lt, custom_fields).
|
|
57
|
+
|
|
58
|
+
**get_task** `(taskId|taskName, ?listName)`
|
|
59
|
+
Get detailed task info including attachments and custom fields.
|
|
60
|
+
|
|
61
|
+
**create_task** `(listId|listName, taskName)`
|
|
62
|
+
Create task with optional description (markdown), status, priority (1-4), dueDate.
|
|
63
|
+
|
|
64
|
+
**create_bulk_tasks** `(listId|listName, tasks[])`
|
|
65
|
+
Bulk create tasks with automatic rate limiting. Each task: name (required), description, status, priority, dueDate (optional).
|
|
66
|
+
|
|
67
|
+
**update_task** `(taskId|taskName, ?listName)`
|
|
68
|
+
Update task name, description, status, priority (1-4), dueDate.
|
|
69
|
+
|
|
70
|
+
**delete_task** `(taskId|taskName, ?listName)`
|
|
71
|
+
Permanently delete a task.
|
|
72
|
+
|
|
73
|
+
**move_task** `(taskId|taskName, destinationListId|destinationListName, ?sourceListName)`
|
|
74
|
+
Move task to different list, preserving task data.
|
|
75
|
+
|
|
76
|
+
**duplicate_task** `(taskId|taskName, destinationListId|destinationListName, ?sourceListName)`
|
|
77
|
+
Create copy of task in specified list.
|
|
78
|
+
|
|
79
|
+
### List & Folder Tools
|
|
80
|
+
**create_list** `(spaceId|spaceName, listName)`
|
|
81
|
+
Create list with optional content, dueDate, priority (1-4), assignee.
|
|
82
|
+
|
|
83
|
+
**create_folder** `(spaceId|spaceName, folderName, ?overrideStatuses)`
|
|
84
|
+
Create folder in space.
|
|
85
|
+
|
|
86
|
+
**create_list_in_folder** `(folderId|folderName, listName)`
|
|
87
|
+
Create list in folder with optional content and status.
|
|
286
88
|
|
|
287
89
|
## Available Prompts
|
|
288
90
|
|
package/build/config.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// Parse command line arguments for --env flags
|
|
2
1
|
const args = process.argv.slice(2);
|
|
3
2
|
const envArgs = {};
|
|
4
3
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -6,16 +5,15 @@ for (let i = 0; i < args.length; i++) {
|
|
|
6
5
|
const [key, value] = args[i + 1].split('=');
|
|
7
6
|
if (key === 'CLICKUP_API_KEY')
|
|
8
7
|
envArgs.clickupApiKey = value;
|
|
9
|
-
if (key === '
|
|
10
|
-
envArgs.
|
|
11
|
-
i++;
|
|
8
|
+
if (key === 'CLICKUP_TEAM_ID')
|
|
9
|
+
envArgs.clickupTeamId = value;
|
|
10
|
+
i++;
|
|
12
11
|
}
|
|
13
12
|
}
|
|
14
13
|
const configuration = {
|
|
15
|
-
clickupApiKey: envArgs.clickupApiKey || '',
|
|
16
|
-
|
|
14
|
+
clickupApiKey: envArgs.clickupApiKey || process.env.CLICKUP_API_KEY || '',
|
|
15
|
+
clickupTeamId: envArgs.clickupTeamId || process.env.CLICKUP_TEAM_ID || '',
|
|
17
16
|
};
|
|
18
|
-
// Check for missing environment variables
|
|
19
17
|
const missingEnvVars = Object.entries(configuration)
|
|
20
18
|
.filter(([_, value]) => !value)
|
|
21
19
|
.map(([key]) => key);
|
package/build/index.js
CHANGED
|
@@ -25,7 +25,7 @@ import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema
|
|
|
25
25
|
import { ClickUpService } from "./services/clickup.js";
|
|
26
26
|
import config from "./config.js";
|
|
27
27
|
// Initialize ClickUp service
|
|
28
|
-
const clickup = ClickUpService.initialize(config.clickupApiKey, config.
|
|
28
|
+
const clickup = ClickUpService.initialize(config.clickupApiKey, config.clickupTeamId);
|
|
29
29
|
/**
|
|
30
30
|
* Create an MCP server with capabilities for tools and prompts.
|
|
31
31
|
* Resources have been removed as they are being replaced with direct tool calls.
|
|
@@ -852,7 +852,7 @@ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
|
852
852
|
try {
|
|
853
853
|
switch (request.params.name) {
|
|
854
854
|
case "summarize_tasks": {
|
|
855
|
-
const spaces = await clickup.getSpaces(config.
|
|
855
|
+
const spaces = await clickup.getSpaces(config.clickupTeamId);
|
|
856
856
|
const tasks = [];
|
|
857
857
|
// Gather all tasks
|
|
858
858
|
for (const space of spaces) {
|
|
@@ -893,7 +893,7 @@ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
|
893
893
|
};
|
|
894
894
|
}
|
|
895
895
|
case "analyze_priorities": {
|
|
896
|
-
const spaces = await clickup.getSpaces(config.
|
|
896
|
+
const spaces = await clickup.getSpaces(config.clickupTeamId);
|
|
897
897
|
const tasks = [];
|
|
898
898
|
for (const space of spaces) {
|
|
899
899
|
const lists = await clickup.getLists(space.id);
|
|
@@ -6,10 +6,10 @@ import axios from 'axios';
|
|
|
6
6
|
export class ClickUpService {
|
|
7
7
|
client;
|
|
8
8
|
static instance;
|
|
9
|
-
|
|
9
|
+
clickupTeamId;
|
|
10
10
|
rateLimitRemaining = 100; // Default to lowest tier limit
|
|
11
11
|
rateLimitReset = 0;
|
|
12
|
-
constructor(apiKey,
|
|
12
|
+
constructor(apiKey, clickupTeamId) {
|
|
13
13
|
this.client = axios.create({
|
|
14
14
|
baseURL: 'https://api.clickup.com/api/v2',
|
|
15
15
|
headers: {
|
|
@@ -35,7 +35,7 @@ export class ClickUpService {
|
|
|
35
35
|
}
|
|
36
36
|
throw error;
|
|
37
37
|
});
|
|
38
|
-
this.
|
|
38
|
+
this.clickupTeamId = clickupTeamId;
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
41
41
|
* Checks if we're close to hitting rate limits and waits if necessary.
|
|
@@ -73,13 +73,13 @@ export class ClickUpService {
|
|
|
73
73
|
/**
|
|
74
74
|
* Initializes the ClickUpService singleton instance.
|
|
75
75
|
* @param apiKey - The ClickUp API key for authentication
|
|
76
|
-
* @param
|
|
76
|
+
* @param clickupTeamId - The team/workspace ID to operate on
|
|
77
77
|
* @returns The singleton instance of ClickUpService
|
|
78
78
|
* @throws Error if initialization fails
|
|
79
79
|
*/
|
|
80
|
-
static initialize(apiKey,
|
|
80
|
+
static initialize(apiKey, clickupTeamId) {
|
|
81
81
|
if (!ClickUpService.instance) {
|
|
82
|
-
ClickUpService.instance = new ClickUpService(apiKey,
|
|
82
|
+
ClickUpService.instance = new ClickUpService(apiKey, clickupTeamId);
|
|
83
83
|
}
|
|
84
84
|
return ClickUpService.instance;
|
|
85
85
|
}
|
|
@@ -244,13 +244,13 @@ export class ClickUpService {
|
|
|
244
244
|
}
|
|
245
245
|
/**
|
|
246
246
|
* Gets all lists in the workspace.
|
|
247
|
-
* @param
|
|
247
|
+
* @param clickupTeamId - ID of the team/workspace
|
|
248
248
|
* @returns Promise resolving to array of ClickUpList objects
|
|
249
249
|
* @throws Error if the API request fails
|
|
250
250
|
*/
|
|
251
|
-
async getAllLists(
|
|
251
|
+
async getAllLists(clickupTeamId) {
|
|
252
252
|
return this.makeRequest(async () => {
|
|
253
|
-
const response = await this.client.get(`/team/${
|
|
253
|
+
const response = await this.client.get(`/team/${clickupTeamId}/list`);
|
|
254
254
|
return response.data.lists;
|
|
255
255
|
});
|
|
256
256
|
}
|
|
@@ -267,9 +267,9 @@ export class ClickUpService {
|
|
|
267
267
|
});
|
|
268
268
|
}
|
|
269
269
|
// Spaces
|
|
270
|
-
async getSpaces(
|
|
270
|
+
async getSpaces(clickupTeamId) {
|
|
271
271
|
return this.makeRequest(async () => {
|
|
272
|
-
const response = await this.client.get(`/team/${
|
|
272
|
+
const response = await this.client.get(`/team/${clickupTeamId}/space`);
|
|
273
273
|
return response.data.spaces;
|
|
274
274
|
});
|
|
275
275
|
}
|
|
@@ -279,8 +279,8 @@ export class ClickUpService {
|
|
|
279
279
|
return response.data;
|
|
280
280
|
});
|
|
281
281
|
}
|
|
282
|
-
async findSpaceByName(
|
|
283
|
-
const spaces = await this.getSpaces(
|
|
282
|
+
async findSpaceByName(clickupTeamId, spaceName) {
|
|
283
|
+
const spaces = await this.getSpaces(clickupTeamId);
|
|
284
284
|
return spaces.find(space => space.name.toLowerCase() === spaceName.toLowerCase()) || null;
|
|
285
285
|
}
|
|
286
286
|
/**
|
|
@@ -448,7 +448,7 @@ export class ClickUpService {
|
|
|
448
448
|
}
|
|
449
449
|
async findListByNameGlobally(listName) {
|
|
450
450
|
// First try the direct lists
|
|
451
|
-
const lists = await this.getAllLists(this.
|
|
451
|
+
const lists = await this.getAllLists(this.clickupTeamId);
|
|
452
452
|
const directList = lists.find(list => list.name.toLowerCase() === listName.toLowerCase());
|
|
453
453
|
if (directList)
|
|
454
454
|
return directList;
|
|
@@ -477,9 +477,9 @@ export class ClickUpService {
|
|
|
477
477
|
* @throws Error if API requests fail
|
|
478
478
|
*/
|
|
479
479
|
async getWorkspaceHierarchy() {
|
|
480
|
-
const spaces = await this.getSpaces(this.
|
|
480
|
+
const spaces = await this.getSpaces(this.clickupTeamId);
|
|
481
481
|
const root = {
|
|
482
|
-
id: this.
|
|
482
|
+
id: this.clickupTeamId,
|
|
483
483
|
name: 'Workspace',
|
|
484
484
|
type: 'workspace',
|
|
485
485
|
children: []
|
package/package.json
CHANGED