Skip to main content
Glama
README.md
# ticktick-mcp

MCP server for **TickTick / 滴答清单** (and **Dida365 / 滴答清单 CN**), built on
the **private web API** — the same endpoints the web app at `ticktick.com/webapp`
calls — not the small public Open API. The outcome of a reverse-engineering
session against the 2026 web bundle (full findings:
[docs/reverse-engineering.md](docs/reverse-engineering.md)).

TypeScript + Node.js (`@modelcontextprotocol/sdk`), stdio transport, no native
dependencies. Auth is a browser session cookie, so the server sees exactly what
the signed-in web app sees: every project, task, tag, habit and calendar.

## Why not the Open API

TickTick publishes `/open/v1` (see [docs/open-api.md](docs/open-api.md)). It is
Bearer-authenticated, stable, and tiny — no tags, no search, no habits, no
calendar, no trash, no batch delete. The private `/api/v2` + `/api/v3` surface
this server uses has **~164 usable endpoints** on a real account (measured — see
the findings doc). The trade-off is honesty: those endpoints are undocumented and
move with the web app.

## Tools

34 tools. Every one below was exercised against a live account during development.

| Tool | What it does |
|---|---|
| `list_tasks` | Tasks in a project (`projectId: "inbox"` resolves the inbox) |
| `get_task` | A single task by id |
| `create_task` | Create a task (title, dates, priority, tags, recurrence, subtasks) |
| `update_task` | Patch fields on a task |
| `complete_task` / `uncomplete_task` | Set status 2 / 0 |
| `delete_task` | Trash a task, or `forever: true` to hard-delete |
| `move_task` | Move a task between projects |
| `list_completed_tasks` | Completed tasks by date range, one project or all |
| `list_trash` / `restore_task` | Trash listing and restore |
| `batch_tasks` | Add/update/delete many tasks at once¹ |
| `search_tasks` | Full-text search |
| `list_projects` / `get_project` | Projects (lists) |
| `create_project` / `update_project` / `delete_project` | Project lifecycle |
| `list_tags` / `rename_tag` / `merge_tags` / `delete_tag` | Tags |
| `list_columns` | Kanban columns |
| `get_current_user` | Profile: id, inbox id, plan |
| `sync_check` | Offline-first delta pull of the whole account |
| `get_preferences` | User preferences |
| `list_templates` / `list_countdowns` | Templates, countdowns |
| `list_habits` / `list_habit_sections` / `query_habit_checkins` | Habits |
| `list_calendar_accounts` / `list_calendar_subscriptions` / `list_calendar_events` | Calendars |

¹ Some accounts are gated: `POST /api/v2/batch/task` answers `403 access_forbidden`.
The tool reports that plainly instead of hiding it.

## Install

```bash
npm install -g @powercess/ticktick-mcp     # or: npx @powercess/ticktick-mcp
```

From a source checkout:

```bash
npm install
npm run build
npm test                                   # hermetic unit tests, no credentials
node scripts/smoke-client.mjs list_projects '{}'
```

Configure as an MCP server:

```json
{
  "mcpServers": {
    "ticktick": {
      "command": "npx",
      "args": ["-y", "@powercess/ticktick-mcp"],
      "env": {
        "TICKTICK_COOKIE": "t=<session cookie>; _csrf_token=<csrf>; ap_user_id=<id>"
      }
    }
  }
}
```

## Authentication

Two credential types, auto-detected from shape — no mode flag needed:

| Credential | Env var | API surface | Tools |
|---|---|---|---|
| **Web session cookie** | `TICKTICK_COOKIE` | private `/api/v2` + `/api/v3` | **all 36** |
| **Personal API token** (`tp_…`) | `TICKTICK_API_TOKEN` | official `/open/v1` | ~28 (stable subset) |

Precedence: tool argument → environment → `~/.ticktick-mcp/credentials.json`.

### Web session cookie (full feature set)

Grab it from a logged-in browser — DevTools → Network → any `api.ticktick.com`
request → Request Headers → `cookie` — and pass the whole value.

```json
{
  "mcpServers": {
    "ticktick": {
      "command": "npx",
      "args": ["-y", "@powercess/ticktick-mcp"],
      "env": {
        "TICKTICK_COOKIE": "t=<session cookie>; _csrf_token=<csrf>; ap_user_id=<id>"
      }
    }
  }
}
```

### Personal API token (no cookie, stable)

Create one in the web app: **Settings → Account → API Token → Create**. Long-lived,
no 2FA prompt, no browser required.

```json
{
  "mcpServers": {
    "ticktick": {
      "command": "npx",
      "args": ["-y", "@powercess/ticktick-mcp"],
      "env": {
        "TICKTICK_API_TOKEN": "tp_<your token>"
      }
    }
  }
}
```

Token mode covers projects, tasks (CRUD, complete, move, batch, completed,
search), tags, columns, habits, focus, countdowns and project groups — about
28 of the 36 tools. Web-only tools (sync_check, trash, templates, calendar,
preferences, tag rename/merge/delete) return a clear error explaining that a
cookie session is needed.

See [docs/authentication.md](docs/authentication.md) for the full walkthrough,
Dida365 setup and every supported input.

## Layout

```
src/config.ts      credential resolution (env → file), site selection
src/client.ts      HTTP client: cookie + x-csrftoken, JSON, typed errors
src/api.ts         endpoint functions (sync, projects, tasks, tags, habits, calendar)
src/errors.ts      TickTickError + human-readable formatting
src/tools/*.ts     MCP tool surface (tasks, projects, account)
src/index.ts       server bootstrap
scripts/           smoke-client.mjs
test/              node:test suites (hermetic)
docs/              reverse-engineering findings, auth guide, Open API notes
```

## Limitations (honest)

- **Undocumented and unstable.** These endpoints are what the web app happens to
  call today; TickTick can change them without notice. The `sync_check` checkpoint
  format and the `x-csrftoken` requirement are reverse-engineered, not promised.
- **Session cookies expire.** There is no OAuth refresh here — when the cookie
  dies, refresh it by hand. (The official Open API is the right choice if you
  need long-lived tokens.)
- **Batch writes are account-gated.** `batch_tasks` may 403 on your account.
- **Not every endpoint is wired.** ~164 are usable; the tools cover the common
  read/write surface. Rarer ones (team collaboration, calendar OAuth handshakes,
  MFA, account merge) are deliberately out of scope — see the findings doc.
- **A few endpoints need a full object, not a patch.** `update_project` merges the
  current project before writing for exactly this reason.
- **No rate-limit handling.** TickTick may throttle; the server surfaces the error.

## Privacy

The session cookie is a live credential for the whole account. It lives in
`~/.ticktick-mcp/credentials.json` (mode `0600`, gitignored) or the environment,
never in the package directory. Captured traffic, cookies and account ids are
never committed. Revoke by logging out of the web app (or rotating the session).

## License

MIT

TDQS

B3.1/5.0

Scored across 38 tools

Disambiguation4/5

Most tools target a distinct resource+action (e.g. list_projects vs get_project vs get_project_with_data), and descriptions clarify subtle overlaps. Slight confusion remains between batch_tasks and the individual task CRUD tools, and between list_focus/create_focus and the broader list_* read-only tools, but boundaries are mostly clear.

Naming Consistency4/5

Names overwhelmingly follow a consistent snake_case verb_noun pattern (list_projects, create_task, update_task, delete_task, complete_task, move_task, etc.). Minor deviations like sync_check (noun_verb) and get_project_with_data (verb_noun_phrase) prevent a perfect score.

Tool Count3/5

38 tools is heavy, though the breadth of the TickTick domain (tasks, projects, tags, habits, focus, calendar, templates, countdowns, sync) distributes them across many resources. Several tools are narrow single-purpose read operations, making the surface feel somewhat bloated.

Completeness3/5

Task and project CRUD/lifecycle coverage is strong, but several domains are read-only with obvious gaps: tags have rename/merge/delete but no create_tag; habits, calendar, templates, countdowns and preferences lack create/update/delete operations. These gaps would force agents to work around missing operations.

Maintenance

ActivityMaintained
ResponsivenessNo issues