ClickUp MCP Server
This server lets an AI assistant operate a ClickUp workspace through MCP — finding, reading, creating, updating, deleting, and administering tasks, lists, docs, people, time, and more, with profile-based write restrictions.
Workspace discovery: list workspaces, spaces, folders, lists, seats, and members; search across tasks, docs, chats, attachments, and dashboards.
Tasks: list, get, create (single/bulk), update (single/bulk), delete, link/unlink, assign, set status/priority/dates, add tags, dependencies, custom fields, attachments, and reminders.
Task context: comments and threaded replies, checklists and checklist items, task members, subtasks, and due/start date handling.
Structure management: create/update/delete folders and lists, create lists from templates, and manage list statuses (list, create, update, delete, reorder).
Docs: get, list, search, create, update; manage pages (list, create, update, delete) with content formats.
Custom fields: list/create/update/delete field definitions, and get/set/remove/bulk-set values on tasks.
Dependencies: create, get, update, delete, bulk, graph, conflict/resolve/timeline analysis at task and workspace level.
Time tracking: list/create/update/delete time entries, start/stop/current timer, filter by task/date/assignee, billable flags.
Chat: list/get/create/update/delete channels, members/followers, send/update/delete messages, replies, reactions, tagged users, unread counts, search.
Goals: list, get, create, update, delete goals and key results.
People administration: list/invite/update/remove users, guests, groups; manage guest access to tasks/lists/folders; view workspace seats.
Webhooks: list, create, update, delete webhooks, and process incoming payloads with HMAC validation.
Views: list/create/get/update/delete views, set filters/grouping/sorting/settings, duplicate, share, and get tasks from a view.
Project intelligence: health, bottlenecks, velocity, dependencies, sprint, workload, risk, and time-report analysis.
Safety profiles:
readis observe-only;agentis append-only;corecovers normal editing;fulladds membership, guest, and webhook administration. Attachment reads can be confined withCLICKUP_ATTACH_ROOT.
Provides comprehensive ClickUp integration with tools for managing tasks, lists, docs, chat, goals, webhooks, guests, time tracking, dependencies, and project intelligence analysis.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ClickUp MCP Serverlist tasks in Marketing list"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
ClickUp MCP Server
A Model Context Protocol server for ClickUp, built around two ideas:
Everything takes human names. find(scope: "Cavalry/Findings", assignee: "me", due: "overdue") — no IDs, no walking the tree to discover them. Names that don't resolve raise an error listing the valid options, because a confidently empty result is worse than a failure.
You choose what it can do. Four capability profiles, enforced on every outgoing request. Hand an unattended agent the agent profile and it can create tasks and comments but cannot alter or delete anything that already exists.
18 tools, 354 tests. Version 4.3.0 — see CHANGELOG.md. A heavily renovated fork of nsxdavid/clickup-mcp-server.
Status: 4.x is new. It has been through five adversarial red-team rounds but has not yet run in production. The previous 3.x line is still shipped in this repo and still what the reference deployment runs — see Running 3.x.
Quick start
Get a token from ClickUp → Settings → Apps → API Token (it starts with pk_). The workspace is discovered automatically — there is nothing else to configure.
No install:
{
"mcpServers": {
"clickup": {
"command": "npx",
"args": ["-y", "github:benthesoundguy/clickup-mcp-server"],
"env": { "CLICKUP_API_TOKEN": "pk_your_token_here" }
}
}
}Or from a clone, which is what you want if you plan to change anything:
git clone https://github.com/benthesoundguy/clickup-mcp-server
cd clickup-mcp-server
npm install # builds automatically
npm run check # verifies the token and connects — do this before wiring up a client{
"mcpServers": {
"clickup": {
"command": "node",
"args": ["/absolute/path/to/clickup-mcp-server/build/v4/index.js"],
"env": { "CLICKUP_API_TOKEN": "pk_your_token_here" }
}
}
}Where that block goes
The shape above works as-is in Claude Desktop, Claude Code, Cursor, Cline, and Windsurf — they all use the mcpServers key. Two clients differ:
VS Code (
.vscode/mcp.json) usesserversinstead ofmcpServers. Same inner shape. Copying a Cursor config unchanged is the most common setup mistake.Zed (
settings.json) usescontext_servers, and nests the command:{ "context_servers": { "clickup": { "command": { "path": "node", "args": ["/path/to/build/v4/index.js"] } } } }
Claude Code can skip the file entirely:
claude mcp add clickup --env CLICKUP_API_TOKEN=pk_... -- npx -y github:benthesoundguy/clickup-mcp-serverPutting the token in a file instead
If you would rather not paste a token into a client config — desktop apps rewrite those files and can persist a stale copy — put it in a .env next to the install and omit the env block entirely:
echo 'CLICKUP_API_TOKEN=pk_your_token_here' > .envThe server looks in <cwd>/.env, <install>/.env, and <install>/../.env, in that order, and says which one it used at startup. The token from the file outranks the environment, so rotating it in one place actually takes effect. Every other setting works the other way round — an explicit value in your client config always wins, so a stray .env can never widen MCP_PROFILE. Set MCP_STRICT_ENV=1 on a server to switch the whole lookup off.
When it doesn't work
npm run check # from a clone
node build/v4/index.js --checkThis prints every input the server resolved — which .env it found and what it applied, whether the token is present and the right shape, the active profile and tool count, the Node version and build stamp — and then actually connects to ClickUp and reports who you are and your rate budget. It never prints the token, so the output is safe to paste into an issue.
If the token is missing, the server does not die silently in stdio mode. It starts, registers its tools, and every call answers with what's wrong and how to fix it, so the problem shows up in your conversation rather than in a log file you have to go find. (In HTTP mode it still exits 1 — an unattended deployment should fail loudly.)
Related MCP server: ClickUp MCP Server
Capability profiles
One binary, four profiles, selected with MCP_PROFILE. Install once and add a client entry per profile, enabling whichever a given agent should have.
| tools | schema cost | What it can do |
| 11 | 2,236 tok | Observe only. No write of any kind can leave the process. |
| 12 | 2,635 tok | Read, plus append: create tasks, comments, chat messages, checklist items, time logs. Cannot alter or delete anything existing. |
| 16 | 4,129 tok | Everything a normal user does. No membership, guest, or webhook administration. |
| 18 | 4,748 tok | Unrestricted, including membership and webhooks. |
Schema cost is what the tool definitions consume in the model's context on every request, before any work happens. For comparison, 3.x costs ~18,600 tokens for 88 tools.
agent is the interesting one. It can add but never alter or destroy, so the worst an unattended agent can do is create clutter you can delete. That guarantee is enforced in three layers, and only the third is a security boundary:
Tool filtering — which tools appear at all (context cost + tool selection)
Action filtering — which actions a tool advertises (context cost + honesty)
Write policy — an allowlist checked on every outgoing request, including uploads ← the guarantee
Layers 1 and 2 depend on every tool being tagged correctly by every future contributor. Layer 3 does not: it inspects the actual request on its way out, so a mistagged tool, a refactor, or an endpoint added next year cannot widen a profile. The test suite proves this by calling core-only handlers directly with an agent context — bypassing layers 1 and 2 entirely — and asserting nothing reaches the wire.
Things that look additive but are excluded from agent on purpose: attaching a tag, setting a custom field, and adding a dependency all mutate an existing task; creating a webhook starts streaming your data to an external endpoint. Append-only and safe are not the same property.
Why the default is core and not full
full grants membership administration — inviting a user consumes a billable seat, removing one changes a real person's access — plus webhooks, which send workspace data off-site. None of that is what a first connection is for, and a default nobody changes has to be the safe one. Ask for administration by name when you want it; until you do, the refusal tells you exactly how.
Attachments and the filesystem
attach reads a file from the machine the server runs on. That is a resource the write policy cannot see — it inspects URLs, and a file read has no URL — so it is governed separately by CLICKUP_ATTACH_ROOT:
Set → reads are confined to that directory. Containment is checked against the file's real path, after resolving
..and every symlink.Unset →
coreandfullmay read any file the process can. Underagent,attachis not offered at all (12 tools instead of 13), because there is no safe default root: the working directory is usually the project directory, which is where.envlives.
A misconfigured root is fatal at startup rather than ignored — a boundary that silently isn't there is worse than none.
Tools
Tool | Min profile | Job |
| read | Query tasks anywhere. Scope, status, assignee, tags, due date — all by name. |
| read | One task in full, optionally with comments and subtasks. |
| read | Workspace structure, printing the exact paths other tools accept. |
| read | What values are legal here — statuses a list accepts, tags in a space, assignable people. |
| read | Identity, workspace, rate-limit budget, server health. |
| read | Search ClickUp Docs, or read one. |
| read | Read a task's comment thread, or post to it. |
| read |
|
| read | Inspect a list's custom fields, or set one by name. |
| read |
|
| read |
|
| agent | Create one or more tasks — pass an array for bulk. |
| agent | Upload a local file to a task (max 25MB). See above. |
| core | Update, move, assign, close, or delete — pass several IDs for bulk. |
| core |
|
| core |
|
| full | Members, guests, seats, groups, invitations, admin rights. |
| full |
|
Tools narrow rather than vanish where it makes sense: under read, comment shows only its reading arguments and checklist advertises only list, so the schema tells the truth about what this connection can do instead of advertising actions that would be refused.
The rule everything follows
Never return a confident wrong answer. ClickUp makes this easy to get wrong, because it answers bad input with cheerful nonsense:
Request | ClickUp says | Which reads as |
|
| "Sam has no work" — there is no Sam |
|
| a filtered search that wasn't |
|
| "moved" — it didn't move |
|
| "moved" — silently ignored |
|
| a permissions problem — it's a typo |
|
| an outage — it's a bad enum |
So this server resolves names and raises on ambiguity ("Findings" matching four lists is an error naming all four, never a coin flip); raises rather than returning empty when a filter value doesn't resolve; validates enums client-side against what the list actually accepts; verifies writes it cannot trust by reading the object back; and never overstates a count — a query that stopped paging reports 100+ matches, and any client-side filter reports how much it actually scanned.
Errors say what failed, why, and what to do next, with the valid options listed.
Environment variables
Variable | Default | Notes |
| — | Required. ClickUp personal API token. |
|
|
|
| unset | Absolute directory that |
| discovered | Only needed if the token can see several workspaces and you want a specific one. |
|
| Set to |
|
| Bind address. Loopback by default — put a proxy or tunnel in front rather than binding |
|
| Also selects HTTP mode if set. |
| generated | Static bearer token, min 16 chars. Optional once |
| — | Authorization server issuer URL. Setting it makes this an OAuth resource server. |
| — | Required with OAuth. This server's canonical URI — the audience inbound tokens must name. Never inferred from the request. |
|
| Override, if your issuer mints a different audience value. |
| discovered | Signing keys, if the issuer publishes no discovery document. |
| — | Advertised in the metadata document. Informational. |
| off | Set to |
| off in strict | Re-enables the |
| off | Disables the |
| — | Cloudflare Access team. Enables Access JWT validation. |
| — | Access application AUD tag. Required alongside the team domain — neither alone enables anything. |
Remote mode (Claude web + mobile, and any HTTP client)
The server speaks streamable HTTP, and accepts three independent credentials. Any one of them authenticates a request; they are meant to coexist, because different clients can present different things.
Credential | For | Set with |
OAuth 2.1 access token | Hosted clients — claude.ai connectors, ChatGPT connectors, anything spec-compliant |
|
Cloudflare Access JWT | An origin behind a CF Tunnel |
|
Static bearer token | Scripts, n8n, curl, CI |
|
MCP_TRANSPORT=http MCP_AUTH_TOKEN=$(openssl rand -hex 24) \
MCP_PROFILE=core CLICKUP_API_TOKEN=... node build/v4/index.jsGET /health is an unauthenticated probe reporting version, active profile, tool count and attachment root.
OAuth (what hosted clients want)
This server does not need to be an OAuth provider, and isn't one. Since the 2025-06-18 MCP spec, an MCP server is a resource server: it names the authorization server it trusts and validates the tokens that server issues. Login, consent and token issuance belong to your IdP — Cloudflare Access, WorkOS, Auth0, Descope, Stytch, Keycloak, anything with OIDC discovery.
MCP_TRANSPORT=http \
MCP_PUBLIC_URL=https://mcp.example.com \
MCP_OAUTH_ISSUER=https://your-idp.example.com \
CLICKUP_API_TOKEN=pk_... node build/v4/index.jsThat is the whole configuration. The server then:
serves RFC 9728 Protected Resource Metadata at
/.well-known/oauth-protected-resource, naming your issuer, unauthenticated;answers an unauthenticated request with
401and aWWW-Authenticateheader pointing at that document, which is how a client discovers where to log in;discovers your issuer's signing keys via
/.well-known/openid-configuration(or RFC 8414), or usesMCP_OAUTH_JWKS_URLif you set it;validates every token: RS256 pinned, signature against the issuer's JWKS,
exp,nbf,iss, andaud— the token must name this server.
That last check is the one that matters. Without it, a token your IdP minted for some other service could be replayed here. It's why MCP_PUBLIC_URL is required rather than inferred: the expected audience must never come from the request, because the Host header is set by the caller.
MCP_AUTH_TOKEN becomes optional once an issuer is configured — an OAuth-only deployment doesn't need a shared password it never uses.
Note on Dynamic Client Registration. The 2026-07-28 spec deprecated DCR in favour of Client ID Metadata Documents. That change lands on authorization servers and clients; a resource server is unaffected either way, which is a good reason to delegate rather than roll your own AS.
The claude.ai connector caveat
Claude's custom connector UI accepts OAuth fields only — Authorization URL, Token URL, Client ID, Client Secret. There is no field for a static bearer token or a custom header (#112, #411). So:
With OAuth configured, connect it as a normal custom connector. This is the intended path.
Without OAuth, the only way in is the token-in-URL form,
/mcp/<token>, enabled withMCP_ALLOW_TOKEN_IN_PATH=1. It works, but it puts a credential in a URL where proxies log it, which is why strict mode refuses it. Treat it as a workaround, not a deployment.
Cloudflare Access (optional third auth mode)
Set CF_ACCESS_TEAM_DOMAIN and CF_ACCESS_AUD and the server validates the Cf-Access-Jwt-Assertion header Access puts on every request it forwards: RS256 against the team JWKS, plus exp, iss, and aud. Both Access flows validate through one path — a browser login carries email, a service token carries common_name.
This is defence in depth. A request reaching the origin without passing through Access — a tunnel misconfiguration, a second ingress, something on the host's network — cannot impersonate an Access-authenticated caller. It fails closed: alg is pinned to RS256 (so alg: none and HS256 confusion are rejected), an unreachable JWKS denies rather than bypasses, and the JWKS URL comes from configuration, never from the token.
Bearer auth keeps working. A request is authorized by a valid Access JWT or a valid bearer token, so header-capable agents need no changes.
The origin does not serve /.well-known/oauth-* — with Managed OAuth enabled, Access is the authorization server and serves discovery at the edge.
Strict mode (MCP_STRICT_ENV=1)
The posture for an unattended deployment. Secrets must come from the environment, the server never invents or persists a credential, and it exits 1 with an actionable message rather than starting misconfigured. It also refuses the URL-path token form, which lands the credential in proxy access logs.
This matters because the .env-file lookup deliberately outranks process.env — a desktop host rewrites its own config file from memory on quit, so the file has to win there. On a server that precedence is backwards: a stray .env in the working directory would silently outrank the systemd unit. Strict mode turns the lookup off.
See deploy/DEPLOY.md for the full recipe: VPS setup script, hardened systemd unit, Cloudflare Tunnel, and connecting it to Claude.
Upgrading from 3.x
The tool names are entirely different — 4.x is a rewrite, not a rename. Anything holding hard-coded 3.x tool names (saved prompts, agent instructions, scripts) needs updating.
The mapping is mostly many-to-one:
3.x | 4.x |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Not carried over: project_intelligence (the eight local analysis reports) and reminders_create. Status management — creating, renaming, reordering statuses — is also absent; meta reads statuses but does not change them. If you need any of these, run 3.x.
Running 3.x
3.x is still built and shipped from this repo:
npm run start:v3 # via the package script
node build/index.js # the 3.x entry point directlyPoint an MCP client at build/index.js instead of build/v4/index.js to keep using it.
The reference systemd unit in deploy/ is deliberately still pinned to 3.x, because a running service should not change major version because a package default moved underneath it. Migrate it by pointing ExecStart at build/v4/index.js and setting MCP_PROFILE explicitly.
Known ClickUp API limitations
Not bugs here — the API genuinely lacks these, and this server reports the limit rather than faking around it.
Tasks cannot be moved between lists.
POST /list/{dest}/task/{id}returns200 {}and does nothing without the "Tasks in Multiple Lists" ClickApp;PUTwithlist_idis silently ignored;/move404s.update's move path reads the task back and fails loudly rather than reporting a move that didn't happen.Attachments have no list endpoint —
taskreads them off the task object. Uploads are multipart-only, capped at 25MB.Docs cannot be renamed or deleted, and pages cannot be deleted.
Custom field definitions can be listed and created, not edited or deleted.
Date custom fields require Unix milliseconds;
YYYY-MM-DDis rejected by ClickUp for those. Taskdue_date/start_dateaccept both and are converted here.Status and tag names are stored lower-cased; matching here is case-insensitive throughout.
Lists override their space's statuses constantly, so "what statuses are valid" is a per-list question.
metaanswers it per list.ClickUp answers an invalid enum with HTTP 500, so enums are validated client-side before sending.
The rate limit is roughly 100 requests/minute per token, shared across everything using it.
whoamireports the live budget; the server paces itself against thex-ratelimit-*headers.
Webhook receiver (optional)
Process ClickUp webhook events without external infrastructure:
WEBHOOK_PORT=3001 WEBHOOK_SECRET=your_secret node build/webhook-receiver/index.jsHMAC-SHA256 validation over the raw request body; when a secret is configured, unsigned requests are rejected
Structured event parsing — type, object, operation, changes, user, timestamp
Optional forwarding to a callback URL (
WEBHOOK_FORWARD_URL)Pure Node.js
http, zero extra dependencies
Development
npm install
npm run build
npm test # 354 tests, mocked HTTP — no token needed
npm run smoke # live CRUD walk (needs CLICKUP_API_TOKEN; creates and
# deletes its own sandbox in your workspace)Architecture notes for 4.x live in src/v4/README.md; the design rationale and measurements are in V4-PLAN.md.
Debugging a fix that "didn't work"
Call whoami. It reports the running build's version and stamp. MCP hosts spawn their own server process at session start and hold it, so a rebuild does not reach an already-running session — if the stamp predates your change, restart the host app. This accounted for several phantom bug reports before the tool existed.
License
MIT — see LICENSE. Fork of nsxdavid/clickup-mcp-server by David Whatley.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- -licenseNot gradedqualityNot gradedmaintenanceAn enhanced Model Context Protocol server that enables AI assistants to interact with ClickUp workspaces, supporting task relationships, comments, checklists, and workspace management through natural language.02
- AlicenseAqualityDmaintenanceA Model Context Protocol server that enables AI agents to interact with ClickUp workspaces, allowing task creation, management, and workspace organization through natural language commands.2121,8572MIT
- AlicenseAqualityAmaintenanceA comprehensive MCP server for the ClickUp API exposing 166 tools to manage Spaces, Folders, Lists, Tasks, Docs, and more, enabling LLMs to read and drive a ClickUp Workspace.1001Apache 2.0
- FlicenseNot gradedqualityDmaintenanceComplete Model Context Protocol server for ClickUp, enabling interaction with tasks, spaces, lists, docs, goals, time tracking, and more through 93 tools and 18 React MCP apps.
Related MCP Connectors
A comprehensive Model Context Protocol (MCP) server that enables AI assistants to interact with yo…
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
MCP server for AI access to SmartBear tools, including BugSnag, Reflect, Swagger, PactFlow, QTM4J.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/benthesoundguy/clickup-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server