Skip to main content
Glama

ClickUp MCP Server

MCP server for ClickUp API. Manage projects, tasks, time tracking, goals, and team collaboration with a flexible hierarchical project management system.

Features

  • Hierarchical Organization: Workspace → Space → Folder → List → Task

  • Task Management: Create, update, and track tasks with custom fields

  • Time Tracking: Log time entries and estimates

  • Goals: Set and track goals with progress metrics

  • Custom Fields: Flexible metadata for tasks

  • Collaboration: Comments, assignments, and notifications

  • Search: Find tasks across your workspace

  • Statuses: Customizable per-list status workflows

Setup

Prerequisites

  • ClickUp account (free or paid)

  • API token

Environment Variables

  • CLICKUP_API_TOKEN (required): Your ClickUp API token

How to get credentials:

  1. Go to app.clickup.com

  2. Log in to your account

  3. Click your avatar → Settings

  4. Go to "Apps" in the sidebar

  5. Click "Generate" under "API Token"

  6. Copy the token (starts with pk_)

  7. Store as CLICKUP_API_TOKEN

Direct link: https://app.clickup.com/settings/apps

Important: Keep your API token secure. It has full access to your ClickUp account.

Rate Limits

  • Standard: 100 requests per minute per token

  • Rate limit headers included in responses

  • HTTP 429 response when limit exceeded

  • Consider caching for frequently accessed data

Hierarchy Overview

ClickUp uses a hierarchical structure:

Workspace (Team) └─ Space ├─ Folder (optional) │ └─ List │ └─ Task │ └─ Subtask └─ List (folderless) └─ Task

Available Tools

Workspace & Space Management

list_workspaces

List all accessible workspaces (teams).

Example:

workspaces = await list_workspaces() # Returns: # { # "teams": [ # { # "id": "123", # "name": "My Workspace", # "color": "#FF0000", # "avatar": "https://...", # "members": [...] # } # ] # }

list_spaces

List spaces in a workspace.

Parameters:

  • workspace_id (string, required): Workspace ID

  • archived (bool, optional): Include archived (default: false)

Example:

spaces = await list_spaces(workspace_id="123") # Returns: # { # "spaces": [ # { # "id": "456", # "name": "Marketing", # "private": false, # "statuses": [...], # "multiple_assignees": true, # "features": { # "due_dates": {"enabled": true}, # "time_tracking": {"enabled": true} # } # } # ] # }

get_space

Get space details.

Parameters:

  • space_id (string, required): Space ID

Example:

space = await get_space(space_id="456")

Folder & List Management

list_folders

List folders in a space.

Parameters:

  • space_id (string, required): Space ID

  • archived (bool, optional): Include archived (default: false)

Example:

folders = await list_folders(space_id="456") # Returns: # { # "folders": [ # { # "id": "789", # "name": "Q4 Campaigns", # "orderindex": 0, # "task_count": 15, # "lists": [...] # } # ] # }

list_lists

List lists in a folder or space.

Parameters:

  • folder_id (string, optional): Folder ID

  • space_id (string, optional): Space ID (for folderless lists)

  • archived (bool, optional): Include archived (default: false)

Example:

# Lists in a folder lists = await list_lists(folder_id="789") # Folderless lists in a space lists = await list_lists(space_id="456") # Returns: # { # "lists": [ # { # "id": "abc123", # "name": "Sprint Backlog", # "orderindex": 0, # "status": { # "status": "active", # "color": "#87909e" # }, # "task_count": 42 # } # ] # }

Task Management

list_tasks

List tasks with filters.

Parameters:

  • list_id (string, required): List ID

  • archived (bool, optional): Include archived (default: false)

  • page (int, optional): Page number (default: 0)

  • order_by (string, optional): Order by (created, updated, due_date)

  • reverse (bool, optional): Reverse order (default: true)

  • subtasks (bool, optional): Include subtasks (default: true)

  • statuses (list, optional): Filter by status names

  • include_closed (bool, optional): Include closed tasks (default: false)

  • assignees (list, optional): Filter by assignee user IDs

  • tags (list, optional): Filter by tag names

  • due_date_gt (int, optional): Due date greater than (Unix ms)

  • due_date_lt (int, optional): Due date less than (Unix ms)

Example:

# All tasks in a list tasks = await list_tasks(list_id="abc123") # Open tasks assigned to specific user tasks = await list_tasks( list_id="abc123", assignees=["12345"], include_closed=False ) # Tasks due this week import time now = int(time.time() * 1000) week_later = now + (7 * 24 * 60 * 60 * 1000) tasks = await list_tasks( list_id="abc123", due_date_gt=now, due_date_lt=week_later ) # Tasks with specific status tasks = await list_tasks( list_id="abc123", statuses=["in progress", "review"] )

get_task

Get task details with custom fields.

Parameters:

  • task_id (string, required): Task ID

Example:

task = await get_task(task_id="xyz789") # Returns: # { # "id": "xyz789", # "name": "Implement user authentication", # "description": "Add OAuth 2.0 support", # "status": { # "status": "in progress", # "color": "#d3d3d3" # }, # "orderindex": "1.00", # "date_created": "1633024800000", # "date_updated": "1633111200000", # "date_closed": null, # "creator": {"id": 123, "username": "user"}, # "assignees": [{"id": 456, "username": "dev"}], # "tags": [{"name": "backend", "tag_fg": "#000", "tag_bg": "#FFF"}], # "parent": null, # "priority": 2, # "due_date": "1633197600000", # "start_date": "1633024800000", # "time_estimate": 7200000, # "time_spent": 3600000, # "custom_fields": [...], # "list": {"id": "abc123", "name": "Sprint"}, # "folder": {"id": "789", "name": "Engineering"}, # "space": {"id": "456"}, # "url": "https://app.clickup.com/t/xyz789" # }

create_task

Create a new task.

Parameters:

  • list_id (string, required): List ID

  • name (string, required): Task name

  • description (string, optional): Task description

  • assignees (list, optional): Assignee user IDs

  • tags (list, optional): Tag names

  • status (string, optional): Status name

  • priority (int, optional): Priority (1=urgent, 2=high, 3=normal, 4=low)

  • due_date (int, optional): Due date (Unix timestamp ms)

  • due_date_time (bool, optional): Include time (default: false)

  • time_estimate (int, optional): Time estimate in milliseconds

  • start_date (int, optional): Start date (Unix timestamp ms)

  • start_date_time (bool, optional): Include time (default: false)

  • notify_all (bool, optional): Notify assignees (default: true)

  • parent (string, optional): Parent task ID (for subtasks)

  • custom_fields (list, optional): Custom field objects

Priority Levels:

  • 1: Urgent (red flag)

  • 2: High (yellow flag)

  • 3: Normal (blue flag, default)

  • 4: Low (gray flag)

Example:

# Simple task task = await create_task( list_id="abc123", name="Write API documentation" ) # Full task with all options import time tomorrow = int((time.time() + 86400) * 1000) task = await create_task( list_id="abc123", name="Deploy to production", description="Deploy version 2.0.0 with new features", assignees=[12345, 67890], tags=["deployment", "urgent"], status="todo", priority=1, due_date=tomorrow, due_date_time=True, time_estimate=3600000, # 1 hour in ms notify_all=True ) # Subtask subtask = await create_task( list_id="abc123", name="Run database migrations", parent="xyz789", # Parent task ID assignees=[12345], priority=2 ) # Task with custom fields task = await create_task( list_id="abc123", name="Bug fix: Login issue", custom_fields=[ {"id": "field_123", "value": "Bug"}, {"id": "field_456", "value": "High"} ] )

update_task

Update task details.

Parameters:

  • task_id (string, required): Task ID

  • name (string, optional): Updated name

  • description (string, optional): Updated description

  • status (string, optional): Updated status

  • priority (int, optional): Updated priority (1-4)

  • due_date (int, optional): Updated due date (Unix ms)

  • time_estimate (int, optional): Updated time estimate (ms)

  • assignees (dict, optional): Assignees {"add": [ids], "rem": [ids]}

Example:

# Update task status task = await update_task( task_id="xyz789", status="in progress" ) # Add assignees task = await update_task( task_id="xyz789", assignees={"add": [12345, 67890]} ) # Remove assignees task = await update_task( task_id="xyz789", assignees={"rem": [12345]} ) # Update priority and due date import time next_week = int((time.time() + 7 * 86400) * 1000) task = await update_task( task_id="xyz789", priority=1, due_date=next_week )

delete_task

Delete a task.

Parameters:

  • task_id (string, required): Task ID

Example:

result = await delete_task(task_id="xyz789")

Comments

add_task_comment

Add comment to a task.

Parameters:

  • task_id (string, required): Task ID

  • comment_text (string, required): Comment text

  • assignee (int, optional): Assign comment to user ID

  • notify_all (bool, optional): Notify all assignees (default: true)

Example:

# Simple comment comment = await add_task_comment( task_id="xyz789", comment_text="Great progress on this task!" ) # Comment with assignment comment = await add_task_comment( task_id="xyz789", comment_text="Can you review this?", assignee=12345, notify_all=True )

list_task_comments

Get task comments.

Parameters:

  • task_id (string, required): Task ID

Example:

comments = await list_task_comments(task_id="xyz789") # Returns: # { # "comments": [ # { # "id": "123", # "comment_text": "Great work!", # "user": {"id": 456, "username": "user"}, # "date": "1633024800000" # } # ] # }

Time Tracking

create_time_entry

Track time on a task.

Parameters:

  • task_id (string, required): Task ID

  • duration (int, required): Duration in milliseconds

  • start (int, optional): Start time (Unix ms, defaults to now)

  • description (string, optional): Time entry description

Example:

# Log 2 hours of work two_hours_ms = 2 * 60 * 60 * 1000 time_entry = await create_time_entry( task_id="xyz789", duration=two_hours_ms, description="Implemented OAuth integration" ) # Log time with specific start time import time start_time = int((time.time() - 7200) * 1000) # 2 hours ago time_entry = await create_time_entry( task_id="xyz789", duration=two_hours_ms, start=start_time )

list_time_entries

Get time tracking entries.

Parameters:

  • workspace_id (string, required): Workspace ID

  • start_date (int, optional): Filter by start date (Unix ms)

  • end_date (int, optional): Filter by end date (Unix ms)

  • assignee (int, optional): Filter by assignee user ID

Example:

# All time entries entries = await list_time_entries(workspace_id="123") # Time entries for this week import time week_ago = int((time.time() - 7 * 86400) * 1000) now = int(time.time() * 1000) entries = await list_time_entries( workspace_id="123", start_date=week_ago, end_date=now ) # Time entries for specific user entries = await list_time_entries( workspace_id="123", assignee=12345 )

Goals

list_goals

List goals in a workspace.

Parameters:

  • workspace_id (string, required): Workspace ID

Example:

goals = await list_goals(workspace_id="123") # Returns: # { # "goals": [ # { # "id": "goal_123", # "name": "Q4 Revenue Target", # "due_date": "1640995200000", # "description": "Reach $1M ARR", # "percent_completed": 75, # "color": "#32a852" # } # ] # }

get_goal

Get goal details and progress.

Parameters:

  • goal_id (string, required): Goal ID

Example:

goal = await get_goal(goal_id="goal_123") # Returns: # { # "goal": { # "id": "goal_123", # "name": "Q4 Revenue Target", # "description": "Reach $1M ARR", # "due_date": "1640995200000", # "color": "#32a852", # "percent_completed": 75, # "key_results": [ # { # "id": "kr_456", # "name": "Close 10 enterprise deals", # "type": "number", # "current": 7, # "target": 10, # "percent_completed": 70 # } # ] # } # }

Custom Fields

list_custom_fields

Get custom fields for a list.

Parameters:

  • list_id (string, required): List ID

Example:

fields = await list_custom_fields(list_id="abc123") # Returns: # { # "fields": [ # { # "id": "field_123", # "name": "Priority", # "type": "drop_down", # "type_config": { # "options": [ # {"id": "opt_1", "name": "High", "color": "#FF0000"}, # {"id": "opt_2", "name": "Low", "color": "#00FF00"} # ] # } # }, # { # "id": "field_456", # "name": "Story Points", # "type": "number" # } # ] # }

Custom Field Types:

  • text: Text input

  • number: Numeric input

  • drop_down: Dropdown selection

  • date: Date picker

  • checkbox: Boolean checkbox

  • url: URL input

  • email: Email input

  • phone: Phone number

  • currency: Currency value

Search

search_tasks

Search tasks across workspace.

Parameters:

  • workspace_id (string, required): Workspace ID

  • query (string, required): Search query text

  • start_date (int, optional): Filter by start date (Unix ms)

  • end_date (int, optional): Filter by end date (Unix ms)

  • assignees (list, optional): Filter by assignee user IDs

  • statuses (list, optional): Filter by status names

  • tags (list, optional): Filter by tag names

Example:

# Search by keyword tasks = await search_tasks( workspace_id="123", query="authentication" ) # Advanced search with filters tasks = await search_tasks( workspace_id="123", query="bug", assignees=[12345], statuses=["in progress"], tags=["urgent"] )

Common Workflows

Project Setup

# 1. Get workspace workspaces = await list_workspaces() workspace_id = workspaces["teams"][0]["id"] # 2. Create or get space spaces = await list_spaces(workspace_id=workspace_id) space_id = spaces["spaces"][0]["id"] # 3. Get lists lists = await list_lists(space_id=space_id) list_id = lists["lists"][0]["id"] # 4. Create tasks await create_task( list_id=list_id, name="Set up development environment", priority=2 ) await create_task( list_id=list_id, name="Write technical documentation", priority=3 )

Sprint Planning

# Get all tasks tasks = await list_tasks(list_id="abc123") # Sort by priority sorted_tasks = sorted( tasks["tasks"], key=lambda t: t.get("priority", 3) ) # Assign to team members team_members = [12345, 67890, 11111] for i, task in enumerate(sorted_tasks[:10]): assignee = team_members[i % len(team_members)] await update_task( task_id=task["id"], assignees={"add": [assignee]}, status="todo" )

Time Tracking Report

import time # Get this week's time entries week_ago = int((time.time() - 7 * 86400) * 1000) now = int(time.time() * 1000) entries = await list_time_entries( workspace_id="123", start_date=week_ago, end_date=now ) # Calculate total hours total_ms = sum(entry["duration"] for entry in entries["data"]) total_hours = total_ms / (1000 * 60 * 60) print(f"Total hours this week: {total_hours:.2f}")

Goal Tracking

# List all goals goals = await list_goals(workspace_id="123") # Check progress on each goal for goal in goals["goals"]: goal_detail = await get_goal(goal_id=goal["id"]) print(f"Goal: {goal_detail['goal']['name']}") print(f"Progress: {goal_detail['goal']['percent_completed']}%") for kr in goal_detail['goal']['key_results']: print(f" - {kr['name']}: {kr['current']}/{kr['target']}")

Best Practices

  1. Use hierarchy effectively: Organize with Spaces → Folders → Lists

  2. Custom statuses: Set up workflows per list

  3. Custom fields: Add metadata for filtering and reporting

  4. Time tracking: Log time regularly for accurate estimates

  5. Tags: Use tags for cross-list categorization

  6. Goals: Set measurable goals with key results

  7. Priorities: Use priority levels consistently

  8. Assignees: Assign tasks for accountability

  9. Comments: Communicate within tasks

  10. Search: Use search for cross-workspace queries

Rate Limit Handling

import asyncio async def make_request_with_retry(): try: return await list_tasks(list_id="abc123") except httpx.HTTPStatusError as e: if e.response.status_code == 429: # Wait and retry await asyncio.sleep(60) return await list_tasks(list_id="abc123") raise

Error Handling

Common errors:

  • 401 Unauthorized: Invalid API token

  • 403 Forbidden: Insufficient permissions

  • 404 Not Found: Resource not found

  • 429 Too Many Requests: Rate limit exceeded (100 req/min)

  • 500 Internal Server Error: ClickUp service issue

API Documentation

Support

-
security - not tested
A
license - permissive license
-
quality - not tested

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/NimbleBrainInc/mcp-clickup'

If you have feedback or need assistance with the MCP directory API, please join our Discord server