Skip to content

NimbleBrainInc/mcp-clickup

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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

Releases

No releases published

Packages

No packages published