cortexaforge-clickup-mcp 0.1.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/LICENSE +21 -0
- package/README.md +71 -0
- package/dist/clickup/client.d.ts +21 -0
- package/dist/clickup/client.js +81 -0
- package/dist/clickup/client.js.map +1 -0
- package/dist/clickup/resolver.d.ts +33 -0
- package/dist/clickup/resolver.js +154 -0
- package/dist/clickup/resolver.js.map +1 -0
- package/dist/clickup/types.d.ts +140 -0
- package/dist/clickup/types.js +2 -0
- package/dist/clickup/types.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +98 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.js +23 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/comments.d.ts +4 -0
- package/dist/tools/comments.js +38 -0
- package/dist/tools/comments.js.map +1 -0
- package/dist/tools/docs.d.ts +4 -0
- package/dist/tools/docs.js +78 -0
- package/dist/tools/docs.js.map +1 -0
- package/dist/tools/tasks.d.ts +4 -0
- package/dist/tools/tasks.js +171 -0
- package/dist/tools/tasks.js.map +1 -0
- package/dist/tools/time.d.ts +4 -0
- package/dist/tools/time.js +95 -0
- package/dist/tools/time.js.map +1 -0
- package/dist/tools/workspace.d.ts +4 -0
- package/dist/tools/workspace.js +35 -0
- package/dist/tools/workspace.js.map +1 -0
- package/dist/utils/errors.d.ts +8 -0
- package/dist/utils/errors.js +17 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/logger.d.ts +6 -0
- package/dist/utils/logger.js +20 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Baden Frosen / CortexaForge
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# cortexaforge-clickup-mcp
|
|
2
|
+
|
|
3
|
+
A free, MIT-licensed, fully-featured **Model Context Protocol** server for ClickUp.
|
|
4
|
+
Works with **Claude Desktop, Claude Code, Hermes, OpenClaw, OpenAI Codex CLI, Cursor, Windsurf**, and any MCP-compatible client.
|
|
5
|
+
|
|
6
|
+
No paywall. No license keys. No "premium tier."
|
|
7
|
+
|
|
8
|
+
> Built from scratch against ClickUp's public REST API. Not derived from, and not affiliated with, any proprietary ClickUp MCP server.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Why
|
|
13
|
+
|
|
14
|
+
Other ClickUp MCP servers gate features behind a paid license. This one doesn't — it's MIT and you can use, fork, or extend it freely. It also supports both stdio and Streamable HTTP transports out of the box, so it works in agent gateways like Hermes and OpenClaw without modification.
|
|
15
|
+
|
|
16
|
+
## Status
|
|
17
|
+
|
|
18
|
+
**Phase 1 (current — v0.1.x)** — 18 tools across:
|
|
19
|
+
- Workspace hierarchy
|
|
20
|
+
- Tasks (CRUD + search)
|
|
21
|
+
- Comments
|
|
22
|
+
- Time tracking
|
|
23
|
+
- Docs (read, create, append)
|
|
24
|
+
|
|
25
|
+
**Phase 2 (planned)** — multi-workspace switching, custom fields, checklists, subtasks, dependencies, attachments, tags, views, goals (~40-60 tools).
|
|
26
|
+
|
|
27
|
+
**Phase 3 (planned)** — chat channels, webhooks, guests, automations, sprints, full ~150 tool parity with the proprietary alternative.
|
|
28
|
+
|
|
29
|
+
## Quickstart
|
|
30
|
+
|
|
31
|
+
### 1. Get your ClickUp credentials
|
|
32
|
+
|
|
33
|
+
- **API key**: ClickUp → top-right avatar → Settings → **Apps** → **API Token** → generate a personal token starting with `pk_`.
|
|
34
|
+
- **Team ID**: open ClickUp in your browser — the URL contains `/t/<TEAM_ID>/`. Or run the curl in [INSTALL.md](docs/INSTALL.md).
|
|
35
|
+
|
|
36
|
+
### 2. Add to your MCP client
|
|
37
|
+
|
|
38
|
+
See [docs/INSTALL.md](docs/INSTALL.md) for one-paste configs for every supported client:
|
|
39
|
+
|
|
40
|
+
- [Claude Desktop](docs/INSTALL.md#claude-desktop)
|
|
41
|
+
- [Claude Code (CLI)](docs/INSTALL.md#claude-code)
|
|
42
|
+
- [Hermes](docs/INSTALL.md#hermes)
|
|
43
|
+
- [OpenClaw](docs/INSTALL.md#openclaw)
|
|
44
|
+
- [OpenAI Codex CLI](docs/INSTALL.md#openai-codex-cli)
|
|
45
|
+
- [Cursor / Windsurf / generic STDIO host](docs/INSTALL.md#generic-stdio-host)
|
|
46
|
+
- [Generic HTTP host](docs/INSTALL.md#generic-http-host)
|
|
47
|
+
|
|
48
|
+
### 3. Talk to it
|
|
49
|
+
|
|
50
|
+
Once installed, ask your AI agent things like:
|
|
51
|
+
|
|
52
|
+
- *"Show me my ClickUp workspace hierarchy."*
|
|
53
|
+
- *"Create a task in the Client Onboarding list called 'Send kickoff email' due tomorrow."*
|
|
54
|
+
- *"Start a timer on the 'Quarterly review' task."*
|
|
55
|
+
- *"Append a page called 'Decision Log — May 25' to the CortexaForge Playbook doc with this content: …"*
|
|
56
|
+
|
|
57
|
+
## Tools
|
|
58
|
+
|
|
59
|
+
18 tools, each accepts **names or IDs** — you don't need to look up IDs. See [docs/TOOLS.md](docs/TOOLS.md) for full reference.
|
|
60
|
+
|
|
61
|
+
## Security
|
|
62
|
+
|
|
63
|
+
The API key has full read/write access to your ClickUp workspace. **Never commit it.** This repo ships a `.env.example` only; your real `.env` is gitignored. When configuring an MCP host, paste the key into that host's config file (e.g. `claude_desktop_config.json`), which lives outside any code repo.
|
|
64
|
+
|
|
65
|
+
## License
|
|
66
|
+
|
|
67
|
+
[MIT](LICENSE). Use it, fork it, sell it, ship it — just keep the copyright notice.
|
|
68
|
+
|
|
69
|
+
## Contributing
|
|
70
|
+
|
|
71
|
+
Issues and PRs welcome. Phase 2 / Phase 3 tools are tracked in [issues](https://github.com/baden-cortexaforge/cortexaforge-clickup-mcp/issues).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface ClientOptions {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
teamId: string;
|
|
4
|
+
maxRetries?: number;
|
|
5
|
+
baseDelayMs?: number;
|
|
6
|
+
}
|
|
7
|
+
type Query = Record<string, string | number | boolean | undefined>;
|
|
8
|
+
export declare class ClickUpClient {
|
|
9
|
+
private apiKey;
|
|
10
|
+
readonly teamId: string;
|
|
11
|
+
private maxRetries;
|
|
12
|
+
private baseDelayMs;
|
|
13
|
+
constructor(opts: ClientOptions);
|
|
14
|
+
private buildUrl;
|
|
15
|
+
private raw;
|
|
16
|
+
get<T = unknown>(version: 2 | 3, path: string, query?: Query): Promise<T>;
|
|
17
|
+
post<T = unknown>(version: 2 | 3, path: string, body?: unknown, query?: Query): Promise<T>;
|
|
18
|
+
put<T = unknown>(version: 2 | 3, path: string, body?: unknown, query?: Query): Promise<T>;
|
|
19
|
+
delete<T = unknown>(version: 2 | 3, path: string, query?: Query): Promise<T>;
|
|
20
|
+
}
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { request } from "undici";
|
|
2
|
+
import { ClickUpError } from "../utils/errors.js";
|
|
3
|
+
import { logger } from "../utils/logger.js";
|
|
4
|
+
const V2 = "https://api.clickup.com/api/v2";
|
|
5
|
+
const V3 = "https://api.clickup.com/api/v3";
|
|
6
|
+
export class ClickUpClient {
|
|
7
|
+
apiKey;
|
|
8
|
+
teamId;
|
|
9
|
+
maxRetries;
|
|
10
|
+
baseDelayMs;
|
|
11
|
+
constructor(opts) {
|
|
12
|
+
if (!opts.apiKey)
|
|
13
|
+
throw new Error("CLICKUP_API_KEY is required");
|
|
14
|
+
if (!opts.teamId)
|
|
15
|
+
throw new Error("CLICKUP_TEAM_ID is required");
|
|
16
|
+
this.apiKey = opts.apiKey;
|
|
17
|
+
this.teamId = opts.teamId;
|
|
18
|
+
this.maxRetries = opts.maxRetries ?? 4;
|
|
19
|
+
this.baseDelayMs = opts.baseDelayMs ?? 500;
|
|
20
|
+
}
|
|
21
|
+
buildUrl(version, path, query) {
|
|
22
|
+
const base = version === 3 ? V3 : V2;
|
|
23
|
+
const url = new URL(base + path);
|
|
24
|
+
if (query) {
|
|
25
|
+
for (const [k, v] of Object.entries(query)) {
|
|
26
|
+
if (v !== undefined)
|
|
27
|
+
url.searchParams.set(k, String(v));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return url.toString();
|
|
31
|
+
}
|
|
32
|
+
async raw(version, method, path, opts = {}) {
|
|
33
|
+
const url = this.buildUrl(version, path, opts.query);
|
|
34
|
+
let attempt = 0;
|
|
35
|
+
while (true) {
|
|
36
|
+
const res = await request(url, {
|
|
37
|
+
method,
|
|
38
|
+
headers: {
|
|
39
|
+
Authorization: this.apiKey,
|
|
40
|
+
"Content-Type": "application/json",
|
|
41
|
+
Accept: "application/json",
|
|
42
|
+
},
|
|
43
|
+
body: opts.body !== undefined ? JSON.stringify(opts.body) : undefined,
|
|
44
|
+
});
|
|
45
|
+
if (res.statusCode === 429 && attempt < this.maxRetries) {
|
|
46
|
+
const retryAfter = Number(res.headers["retry-after"] ?? 0);
|
|
47
|
+
const delay = retryAfter > 0 ? retryAfter * 1000 : this.baseDelayMs * Math.pow(2, attempt);
|
|
48
|
+
logger.warn("ClickUp 429, retrying", { url, delay, attempt });
|
|
49
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
50
|
+
attempt++;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const text = await res.body.text();
|
|
54
|
+
let parsed = undefined;
|
|
55
|
+
if (text.length > 0) {
|
|
56
|
+
try {
|
|
57
|
+
parsed = JSON.parse(text);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
parsed = text;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (res.statusCode >= 200 && res.statusCode < 300)
|
|
64
|
+
return parsed;
|
|
65
|
+
throw new ClickUpError(res.statusCode, parsed);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
get(version, path, query) {
|
|
69
|
+
return this.raw(version, "GET", path, { query });
|
|
70
|
+
}
|
|
71
|
+
post(version, path, body, query) {
|
|
72
|
+
return this.raw(version, "POST", path, { body, query });
|
|
73
|
+
}
|
|
74
|
+
put(version, path, body, query) {
|
|
75
|
+
return this.raw(version, "PUT", path, { body, query });
|
|
76
|
+
}
|
|
77
|
+
delete(version, path, query) {
|
|
78
|
+
return this.raw(version, "DELETE", path, { query });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/clickup/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ClickUpClient } from "./client.js";
|
|
2
|
+
import type { Space, Folder, List } from "./types.js";
|
|
3
|
+
export declare class Resolver {
|
|
4
|
+
private client;
|
|
5
|
+
private cache;
|
|
6
|
+
constructor(client: ClickUpClient);
|
|
7
|
+
private emptyCache;
|
|
8
|
+
private fresh;
|
|
9
|
+
invalidate(): void;
|
|
10
|
+
getSpaces(): Promise<Space[]>;
|
|
11
|
+
getFolders(spaceId: string): Promise<Folder[]>;
|
|
12
|
+
getFolderlessLists(spaceId: string): Promise<List[]>;
|
|
13
|
+
getListsInFolder(folderId: string): Promise<List[]>;
|
|
14
|
+
getAllLists(): Promise<List[]>;
|
|
15
|
+
resolveSpaceId(input: {
|
|
16
|
+
space_id?: string;
|
|
17
|
+
space_name?: string;
|
|
18
|
+
}): Promise<string>;
|
|
19
|
+
resolveListId(input: {
|
|
20
|
+
list_id?: string;
|
|
21
|
+
list_name?: string;
|
|
22
|
+
}): Promise<string>;
|
|
23
|
+
resolveFolderId(input: {
|
|
24
|
+
folder_id?: string;
|
|
25
|
+
folder_name?: string;
|
|
26
|
+
}): Promise<string>;
|
|
27
|
+
resolveTaskId(input: {
|
|
28
|
+
task_id?: string;
|
|
29
|
+
task_name?: string;
|
|
30
|
+
list_name?: string;
|
|
31
|
+
list_id?: string;
|
|
32
|
+
}): Promise<string>;
|
|
33
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { NotFoundError } from "../utils/errors.js";
|
|
2
|
+
const CACHE_TTL_MS = 5 * 60 * 1000;
|
|
3
|
+
export class Resolver {
|
|
4
|
+
client;
|
|
5
|
+
cache = this.emptyCache();
|
|
6
|
+
constructor(client) {
|
|
7
|
+
this.client = client;
|
|
8
|
+
}
|
|
9
|
+
emptyCache() {
|
|
10
|
+
return {
|
|
11
|
+
foldersBySpace: new Map(),
|
|
12
|
+
folderlessListsBySpace: new Map(),
|
|
13
|
+
listsByFolder: new Map(),
|
|
14
|
+
expiresAt: Date.now() + CACHE_TTL_MS,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
fresh() {
|
|
18
|
+
return Date.now() < this.cache.expiresAt;
|
|
19
|
+
}
|
|
20
|
+
invalidate() {
|
|
21
|
+
this.cache = this.emptyCache();
|
|
22
|
+
this.cache.expiresAt = 0;
|
|
23
|
+
}
|
|
24
|
+
async getSpaces() {
|
|
25
|
+
if (this.cache.spaces && this.fresh())
|
|
26
|
+
return this.cache.spaces;
|
|
27
|
+
if (!this.fresh())
|
|
28
|
+
this.cache = this.emptyCache();
|
|
29
|
+
const res = await this.client.get(2, `/team/${this.client.teamId}/space`, { archived: false });
|
|
30
|
+
this.cache.spaces = res.spaces;
|
|
31
|
+
return res.spaces;
|
|
32
|
+
}
|
|
33
|
+
async getFolders(spaceId) {
|
|
34
|
+
const cached = this.cache.foldersBySpace.get(spaceId);
|
|
35
|
+
if (cached && this.fresh())
|
|
36
|
+
return cached;
|
|
37
|
+
const res = await this.client.get(2, `/space/${spaceId}/folder`, { archived: false });
|
|
38
|
+
this.cache.foldersBySpace.set(spaceId, res.folders);
|
|
39
|
+
return res.folders;
|
|
40
|
+
}
|
|
41
|
+
async getFolderlessLists(spaceId) {
|
|
42
|
+
const cached = this.cache.folderlessListsBySpace.get(spaceId);
|
|
43
|
+
if (cached && this.fresh())
|
|
44
|
+
return cached;
|
|
45
|
+
const res = await this.client.get(2, `/space/${spaceId}/list`, { archived: false });
|
|
46
|
+
this.cache.folderlessListsBySpace.set(spaceId, res.lists);
|
|
47
|
+
return res.lists;
|
|
48
|
+
}
|
|
49
|
+
async getListsInFolder(folderId) {
|
|
50
|
+
const cached = this.cache.listsByFolder.get(folderId);
|
|
51
|
+
if (cached && this.fresh())
|
|
52
|
+
return cached;
|
|
53
|
+
const res = await this.client.get(2, `/folder/${folderId}/list`, { archived: false });
|
|
54
|
+
this.cache.listsByFolder.set(folderId, res.lists);
|
|
55
|
+
return res.lists;
|
|
56
|
+
}
|
|
57
|
+
async getAllLists() {
|
|
58
|
+
if (this.cache.allListsFlat && this.fresh())
|
|
59
|
+
return this.cache.allListsFlat;
|
|
60
|
+
const spaces = await this.getSpaces();
|
|
61
|
+
const all = [];
|
|
62
|
+
for (const sp of spaces) {
|
|
63
|
+
const folders = await this.getFolders(sp.id);
|
|
64
|
+
for (const f of folders) {
|
|
65
|
+
const lists = await this.getListsInFolder(f.id);
|
|
66
|
+
for (const l of lists) {
|
|
67
|
+
all.push({ ...l, folder: { id: f.id, name: f.name, hidden: f.hidden }, space: { id: sp.id, name: sp.name } });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const fless = await this.getFolderlessLists(sp.id);
|
|
71
|
+
for (const l of fless) {
|
|
72
|
+
all.push({ ...l, space: { id: sp.id, name: sp.name } });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
this.cache.allListsFlat = all;
|
|
76
|
+
return all;
|
|
77
|
+
}
|
|
78
|
+
async resolveSpaceId(input) {
|
|
79
|
+
if (input.space_id)
|
|
80
|
+
return input.space_id;
|
|
81
|
+
if (!input.space_name)
|
|
82
|
+
throw new Error("Provide space_id or space_name");
|
|
83
|
+
const spaces = await this.getSpaces();
|
|
84
|
+
const match = bestMatch(spaces, (s) => s.name, input.space_name);
|
|
85
|
+
if (!match)
|
|
86
|
+
throw new NotFoundError("space", input.space_name);
|
|
87
|
+
return match.id;
|
|
88
|
+
}
|
|
89
|
+
async resolveListId(input) {
|
|
90
|
+
if (input.list_id)
|
|
91
|
+
return input.list_id;
|
|
92
|
+
if (!input.list_name)
|
|
93
|
+
throw new Error("Provide list_id or list_name");
|
|
94
|
+
const lists = await this.getAllLists();
|
|
95
|
+
const match = bestMatch(lists, (l) => l.name, input.list_name);
|
|
96
|
+
if (!match)
|
|
97
|
+
throw new NotFoundError("list", input.list_name);
|
|
98
|
+
return match.id;
|
|
99
|
+
}
|
|
100
|
+
async resolveFolderId(input) {
|
|
101
|
+
if (input.folder_id)
|
|
102
|
+
return input.folder_id;
|
|
103
|
+
if (!input.folder_name)
|
|
104
|
+
throw new Error("Provide folder_id or folder_name");
|
|
105
|
+
const spaces = await this.getSpaces();
|
|
106
|
+
const all = [];
|
|
107
|
+
for (const sp of spaces)
|
|
108
|
+
all.push(...(await this.getFolders(sp.id)));
|
|
109
|
+
const match = bestMatch(all, (f) => f.name, input.folder_name);
|
|
110
|
+
if (!match)
|
|
111
|
+
throw new NotFoundError("folder", input.folder_name);
|
|
112
|
+
return match.id;
|
|
113
|
+
}
|
|
114
|
+
async resolveTaskId(input) {
|
|
115
|
+
if (input.task_id)
|
|
116
|
+
return input.task_id;
|
|
117
|
+
if (!input.task_name)
|
|
118
|
+
throw new Error("Provide task_id or task_name");
|
|
119
|
+
if (input.list_id || input.list_name) {
|
|
120
|
+
const listId = await this.resolveListId({ list_id: input.list_id, list_name: input.list_name });
|
|
121
|
+
const res = await this.client.get(2, `/list/${listId}/task`, {
|
|
122
|
+
archived: false,
|
|
123
|
+
include_closed: true,
|
|
124
|
+
subtasks: true,
|
|
125
|
+
});
|
|
126
|
+
const match = bestMatch(res.tasks, (t) => t.name, input.task_name);
|
|
127
|
+
if (!match)
|
|
128
|
+
throw new NotFoundError("task in list", input.task_name);
|
|
129
|
+
return match.id;
|
|
130
|
+
}
|
|
131
|
+
const res = await this.client.get(2, `/team/${this.client.teamId}/task`, {
|
|
132
|
+
include_closed: true,
|
|
133
|
+
subtasks: true,
|
|
134
|
+
});
|
|
135
|
+
const match = bestMatch(res.tasks, (t) => t.name, input.task_name);
|
|
136
|
+
if (!match)
|
|
137
|
+
throw new NotFoundError("task", input.task_name);
|
|
138
|
+
return match.id;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function bestMatch(items, getKey, query) {
|
|
142
|
+
const q = query.trim().toLowerCase();
|
|
143
|
+
let m = items.find((i) => getKey(i).toLowerCase() === q);
|
|
144
|
+
if (m)
|
|
145
|
+
return m;
|
|
146
|
+
m = items.find((i) => getKey(i).toLowerCase().startsWith(q));
|
|
147
|
+
if (m)
|
|
148
|
+
return m;
|
|
149
|
+
m = items.find((i) => getKey(i).toLowerCase().includes(q));
|
|
150
|
+
if (m)
|
|
151
|
+
return m;
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../src/clickup/resolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
export interface Team {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
color: string;
|
|
5
|
+
}
|
|
6
|
+
export interface Space {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
private?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface Folder {
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
hidden?: boolean;
|
|
15
|
+
space?: {
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export interface List {
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
folder?: {
|
|
24
|
+
id: string;
|
|
25
|
+
name: string;
|
|
26
|
+
hidden?: boolean;
|
|
27
|
+
};
|
|
28
|
+
space?: {
|
|
29
|
+
id: string;
|
|
30
|
+
name: string;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export interface Task {
|
|
34
|
+
id: string;
|
|
35
|
+
custom_id?: string | null;
|
|
36
|
+
name: string;
|
|
37
|
+
text_content?: string;
|
|
38
|
+
description?: string;
|
|
39
|
+
status: {
|
|
40
|
+
status: string;
|
|
41
|
+
color?: string;
|
|
42
|
+
type?: string;
|
|
43
|
+
};
|
|
44
|
+
date_created?: string;
|
|
45
|
+
date_updated?: string;
|
|
46
|
+
date_closed?: string | null;
|
|
47
|
+
creator?: {
|
|
48
|
+
id: number;
|
|
49
|
+
username: string;
|
|
50
|
+
email?: string;
|
|
51
|
+
};
|
|
52
|
+
assignees?: Array<{
|
|
53
|
+
id: number;
|
|
54
|
+
username: string;
|
|
55
|
+
email?: string;
|
|
56
|
+
}>;
|
|
57
|
+
due_date?: string | null;
|
|
58
|
+
start_date?: string | null;
|
|
59
|
+
url?: string;
|
|
60
|
+
list?: {
|
|
61
|
+
id: string;
|
|
62
|
+
name: string;
|
|
63
|
+
};
|
|
64
|
+
folder?: {
|
|
65
|
+
id: string;
|
|
66
|
+
name: string;
|
|
67
|
+
};
|
|
68
|
+
space?: {
|
|
69
|
+
id: string;
|
|
70
|
+
};
|
|
71
|
+
priority?: {
|
|
72
|
+
id: string;
|
|
73
|
+
priority: string;
|
|
74
|
+
color?: string;
|
|
75
|
+
} | null;
|
|
76
|
+
tags?: Array<{
|
|
77
|
+
name: string;
|
|
78
|
+
tag_fg?: string;
|
|
79
|
+
tag_bg?: string;
|
|
80
|
+
}>;
|
|
81
|
+
}
|
|
82
|
+
export interface Comment {
|
|
83
|
+
id: string;
|
|
84
|
+
comment_text: string;
|
|
85
|
+
user?: {
|
|
86
|
+
id: number;
|
|
87
|
+
username: string;
|
|
88
|
+
email?: string;
|
|
89
|
+
};
|
|
90
|
+
date?: string;
|
|
91
|
+
resolved?: boolean;
|
|
92
|
+
}
|
|
93
|
+
export interface TimeEntry {
|
|
94
|
+
id: string;
|
|
95
|
+
task?: {
|
|
96
|
+
id: string;
|
|
97
|
+
name: string;
|
|
98
|
+
status?: {
|
|
99
|
+
status: string;
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
wid?: string;
|
|
103
|
+
user?: {
|
|
104
|
+
id: number;
|
|
105
|
+
username: string;
|
|
106
|
+
email?: string;
|
|
107
|
+
};
|
|
108
|
+
billable?: boolean;
|
|
109
|
+
start: string | number;
|
|
110
|
+
end?: string | number | null;
|
|
111
|
+
duration: number | string;
|
|
112
|
+
description?: string;
|
|
113
|
+
source?: string;
|
|
114
|
+
at?: string;
|
|
115
|
+
}
|
|
116
|
+
export interface Doc {
|
|
117
|
+
id: string;
|
|
118
|
+
name: string;
|
|
119
|
+
type?: number;
|
|
120
|
+
parent?: {
|
|
121
|
+
id: string;
|
|
122
|
+
type: number;
|
|
123
|
+
};
|
|
124
|
+
workspace_id?: string;
|
|
125
|
+
date_created?: number;
|
|
126
|
+
date_updated?: number;
|
|
127
|
+
creator?: number;
|
|
128
|
+
archived?: boolean;
|
|
129
|
+
public?: boolean;
|
|
130
|
+
}
|
|
131
|
+
export interface DocPage {
|
|
132
|
+
id: string;
|
|
133
|
+
doc_id: string;
|
|
134
|
+
parent_page_id?: string | null;
|
|
135
|
+
workspace_id?: string;
|
|
136
|
+
name: string;
|
|
137
|
+
content?: string;
|
|
138
|
+
date_created?: number;
|
|
139
|
+
date_updated?: number;
|
|
140
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/clickup/types.ts"],"names":[],"mappings":""}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
5
|
+
import { createServer } from "node:http";
|
|
6
|
+
import { buildServer } from "./server.js";
|
|
7
|
+
import { logger } from "./utils/logger.js";
|
|
8
|
+
function help() {
|
|
9
|
+
process.stdout.write([
|
|
10
|
+
"cortexaforge-clickup-mcp",
|
|
11
|
+
"",
|
|
12
|
+
"A free, open-source MCP server for ClickUp.",
|
|
13
|
+
"",
|
|
14
|
+
"Usage:",
|
|
15
|
+
" cortexaforge-clickup-mcp [--transport stdio|http] [--port 3375]",
|
|
16
|
+
"",
|
|
17
|
+
"Environment:",
|
|
18
|
+
" CLICKUP_API_KEY Required. ClickUp personal API token (starts with pk_)",
|
|
19
|
+
" CLICKUP_TEAM_ID Required. ClickUp workspace (team) ID",
|
|
20
|
+
" LOG_LEVEL Optional. debug | info | warn | error (default: info)",
|
|
21
|
+
"",
|
|
22
|
+
].join("\n"));
|
|
23
|
+
}
|
|
24
|
+
function parseArgs(argv) {
|
|
25
|
+
const args = { transport: "stdio", port: 3375 };
|
|
26
|
+
for (let i = 0; i < argv.length; i++) {
|
|
27
|
+
const a = argv[i];
|
|
28
|
+
if (a === "--transport" || a === "-t") {
|
|
29
|
+
const v = argv[++i];
|
|
30
|
+
if (v !== "stdio" && v !== "http") {
|
|
31
|
+
process.stderr.write(`Unknown transport: ${v}\n`);
|
|
32
|
+
process.exit(2);
|
|
33
|
+
}
|
|
34
|
+
args.transport = v;
|
|
35
|
+
}
|
|
36
|
+
else if (a === "--port" || a === "-p") {
|
|
37
|
+
args.port = Number(argv[++i]);
|
|
38
|
+
}
|
|
39
|
+
else if (a === "--help" || a === "-h") {
|
|
40
|
+
help();
|
|
41
|
+
process.exit(0);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return args;
|
|
45
|
+
}
|
|
46
|
+
async function main() {
|
|
47
|
+
const args = parseArgs(process.argv.slice(2));
|
|
48
|
+
const apiKey = process.env.CLICKUP_API_KEY;
|
|
49
|
+
const teamId = process.env.CLICKUP_TEAM_ID;
|
|
50
|
+
if (!apiKey || !teamId) {
|
|
51
|
+
logger.error("Missing required env vars CLICKUP_API_KEY and/or CLICKUP_TEAM_ID");
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
const server = buildServer({ apiKey, teamId });
|
|
55
|
+
if (args.transport === "stdio") {
|
|
56
|
+
const transport = new StdioServerTransport();
|
|
57
|
+
await server.connect(transport);
|
|
58
|
+
logger.info("MCP server up on stdio");
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const transport = new StreamableHTTPServerTransport({
|
|
62
|
+
sessionIdGenerator: () => randomUUID(),
|
|
63
|
+
});
|
|
64
|
+
await server.connect(transport);
|
|
65
|
+
const httpServer = createServer((req, res) => {
|
|
66
|
+
if (!req.url || !req.url.startsWith("/mcp")) {
|
|
67
|
+
res.writeHead(404, { "Content-Type": "text/plain" }).end("not found");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (req.method !== "POST") {
|
|
71
|
+
transport.handleRequest(req, res);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
let body = "";
|
|
75
|
+
req.on("data", (c) => (body += typeof c === "string" ? c : c.toString("utf8")));
|
|
76
|
+
req.on("end", () => {
|
|
77
|
+
let parsed = undefined;
|
|
78
|
+
if (body.length > 0) {
|
|
79
|
+
try {
|
|
80
|
+
parsed = JSON.parse(body);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// leave undefined, transport will handle errors
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
transport.handleRequest(req, res, parsed);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
httpServer.listen(args.port, () => {
|
|
90
|
+
logger.info(`MCP server up on http://localhost:${args.port}/mcp`);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
main().catch((e) => {
|
|
94
|
+
const err = e instanceof Error ? e.stack ?? e.message : String(e);
|
|
95
|
+
logger.error("Fatal error", { error: err });
|
|
96
|
+
process.exit(1);
|
|
97
|
+
});
|
|
98
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAO3C,SAAS,IAAI;IACX,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB;QACE,0BAA0B;QAC1B,EAAE;QACF,6CAA6C;QAC7C,EAAE;QACF,QAAQ;QACR,mEAAmE;QACnE,EAAE;QACF,cAAc;QACd,4EAA4E;QAC5E,2DAA2D;QAC3D,4EAA4E;QAC5E,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,IAAc;IAC/B,MAAM,IAAI,GAAS,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACtD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,aAAa,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YACtC,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YACpB,IAAI,CAAC,KAAK,OAAO,IAAI,CAAC,KAAK,MAAM,EAAE,CAAC;gBAClC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC;gBAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;QACrB,CAAC;aAAM,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YACxC,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAChC,CAAC;aAAM,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YACxC,IAAI,EAAE,CAAC;YACP,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAC3C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAC3C,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;QACvB,MAAM,CAAC,KAAK,CAAC,kEAAkE,CAAC,CAAC;QACjF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,WAAW,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAE/C,IAAI,IAAI,CAAC,SAAS,KAAK,OAAO,EAAE,CAAC;QAC/B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;QAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAChC,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;QACtC,OAAO;IACT,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,6BAA6B,CAAC;QAClD,kBAAkB,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE;KACvC,CAAC,CAAC;IACH,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,MAAM,UAAU,GAAG,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAC3C,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5C,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACtE,OAAO;QACT,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC1B,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YAClC,OAAO;QACT,CAAC;QACD,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAkB,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACjG,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACjB,IAAI,MAAM,GAAY,SAAS,CAAC;YAChC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACpB,IAAI,CAAC;oBACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC5B,CAAC;gBAAC,MAAM,CAAC;oBACP,gDAAgD;gBAClD,CAAC;YACH,CAAC;YACD,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE;QAChC,MAAM,CAAC,IAAI,CAAC,qCAAqC,IAAI,CAAC,IAAI,MAAM,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAU,EAAE,EAAE;IAC1B,MAAM,GAAG,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAClE,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;IAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|