关于 ticktick-mcp
ticktick-mcp 为 Claude Code 等 MCP 客户端提供 TickTick 任务管理能力。它支持完整任务操作,并通过保留未修改字段、写后复核和完成项追踪来减少状态偏差。
主要功能
- 01创建、更新、完成和移动任务
- 02更新时保留未指定字段
- 03设置日期时校验星期
- 04写入后重新读取并核对
- 05追踪尚未处理的已完成任务
适用场景
- 01按项目或截止日期筛选任务
- 02更新任务而不覆盖其他字段
- 03检查并处理外部完成的任务
MCP 相关
MCP 服务向客户端公开任务创建、查询、更新、删除、筛选及完成追踪等工具,并可在需要时同步 TickTick 状态。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
docker run -i --rm -e TICKTICK_CLIENT_ID -e TICKTICK_CLIENT_SECRET -e TICKTICK_USERNAME -e TICKTICK_PASSWORD ghcr.io/partymola/ticktick-mcp:v0.5.0TICKTICK_CLIENT_IDTickTick OAuth client ID. Needed only if you are not mounting a .env file.TICKTICK_CLIENT_SECRET密钥TickTick OAuth client secret. Needed only if you are not mounting a .env file.TICKTICK_USERNAMETickTick account username. Needed only if you are not mounting a .env file.TICKTICK_PASSWORD密钥TickTick account password. Needed only if you are not mounting a .env file.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
ghcr.io/partymola/ticktick-mcp:v0.5.0stdio工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
ticktick-mcp
用于 TickTick 任务管理的 MCP 服务。通过 TickTick v2 API 创建、更新、完成、移动和筛选任务,并支持保留字段的更新、星期日期验证、写入后读取验证以及幂等的完成状态跟踪。
专为 Claude Code 和其他 MCP 客户端设计。
非官方项目,与 TickTick Ltd. 无关联。基于 ticktick-py(MIT)构建。
功能
- 完整的任务生命周期 - 创建、更新、完成、移动、添加子任务和删除任务
- 保留字段的更新 -
ticktick_update_task会重新获取任务,并仅覆盖你设置的字段,因此 API 不会清除你未指定的字段 - 星期日期验证 - 任何设置日期的调用都必须确认星期几,以便在日期错误到达服务端之前将其捕获
- 写入后读取验证 - 创建和更新操作会重新读取任务;如果服务端返回的数据不匹配,则会显示
_verification_warnings - 精简列表 - 列表工具默认返回精简视图,确保大型项目不会超过 MCP 结果大小上限(见下文)
- 获取最新数据 - 读取工具会按需重新同步服务端状态,因此在其他设备上的 TickTick 应用中进行的编辑无需重启即可显示
- 完成状态跟踪 - 将已完成的任务标记为已处理,让 Agent 恰好审核每个任务一次;通过此服务完成的任务也会自动记录为已处理
要求
- Python 3.13+(在 Linux、macOS 和 Windows 上使用 Python 3.13 和 3.14 进行过 CI 测试)
- uv(推荐 - 见下方安装说明)
- TickTick 账户
- 已注册的 TickTick 应用,用于获取 OAuth 凭据(免费 - developer.ticktick.com)
安装
git clone https://github.com/partymola/ticktick-mcp
cd ticktick-mcp
uv sync
这会创建 .venv 并根据 uv.lock 安装依赖,使你可以使用 .venv/bin/ticktick-mcp 控制台脚本;在 Windows 上则为 .venv\Scripts\ticktick-mcp。下文中的所有命令均采用 POSIX 写法。
pip install . 也可以使用。此服务所需的 ticktick-py 分支在 dependencies 中固定为直接 Git 引用,pip 和 uv 都会遵循此设置;推荐使用 uv sync,因为它会安装 uv.lock 中的确切版本,而不是重新解析依赖。
凭据
登录 TickTick 需要两样东西:一个 OAuth 应用(客户端 ID + 密钥)和你自己的账户登录信息。
-
在 developer.ticktick.com 注册一个应用。将 Redirect URI 设置为
http://localhost:8080/redirect。记下 Client ID 和 Client Secret。 -
将模板复制到服务读取的目录中,并填写内容:
mkdir -p ~/.config/ticktick-mcp && cp .env.example ~/.config/ticktick-mcp/.envTICKTICK_CLIENT_ID=your_client_id TICKTICK_CLIENT_SECRET=your_client_secret TICKTICK_REDIRECT_URI=http://localhost:8080/redirect TICKTICK_USERNAME=your_ticktick_email TICKTICK_PASSWORD=your_ticktick_password -
此文件以纯文本形式保存你的账户密码,而且服务不会创建该文件,因此请自行收紧权限。在 POSIX 系统上:
chmod 700 ~/.config/ticktick-mcp chmod 600 ~/.config/ticktick-mcp/.env这些是 POSIX 权限位,在 Windows 上不起作用:文件的访问权限遵循其从父目录继承的 ACL。此处未记录这两个命令在 Windows 上的对应方法。
它旁边的两个令牌文件仅所有者可访问,服务创建的配置目录也会如此——但如果目录已经存在,服务会保留其原有权限。这些同样是 POSIX 权限,在 Windows 上也会设置,但不会限制哪些人可以读取内容。
在注册服务之前,请先在终端中完成一次授权:
.venv/bin/ticktick-mcp auth
此命令会打开浏览器,并要求你粘贴最终跳转到的 URL,然后退出。令牌会缓存在 .env 旁边的 .token-oauth 文件中,之后每次启动都会重复使用。TickTick 不会签发刷新令牌,因此令牌过期后需要重新执行此命令。
不要在 MCP 服务中执行此步骤。提示会从标准输入读取内容,而对于 stdio 服务来说,标准输入就是 JSON-RPC 通道,因此首次工具调用未经授权时会在主机上打开浏览器并阻塞。在容器中则根本无法完成授权——请在主机上运行 auth,并挂载配置目录。
用户名/密码部分无需单独操作:服务会在首次工具调用时按需登录,并将会话令牌缓存为 .token-v2,因此每次启动时都不会重新提交你的凭据。
服务会按以下顺序查找 .env:--dotenv-dir <path> 参数、TICKTICK_MCP_DOTENV_DIR 环境变量,最后是 ~/.config/ticktick-mcp/。如果找不到 .env,服务会直接使用 TICKTICK_* 环境变量,这在容器或 CI 场景中很方便。
隐私与非官方 API
你的 TickTick 凭据只保存在本地 .env 文件(或环境变量)中,只会发送给 TickTick 自己的服务器——绝不会发送给开发者或任何第三方。此服务只会读取和写入你自己的账户数据。
此服务使用 TickTick 的非官方 v2 API(通过 ticktick-py),而非官方 Open API。这是经过深思熟虑的选择:官方 API 没有列出已完成任务的接口,不支持标签,也无法跨项目列出任务,而此服务依赖这些功能。完整的原因、风险权衡以及促使我们重新考虑的条件,请参阅 docs/why-not-the-official-api.md。
注册到 Claude Code
claude mcp add -s user ticktick -- /path/to/ticktick-mcp/.venv/bin/ticktick-mcp --dotenv-dir /path/to/config
如果你的 .env 位于 ~/.config/ticktick-mcp/,或者你通过环境变量提供 TICKTICK_* 变量,则 --dotenv-dir 可选。
然后可以向 Claude 提出以下请求:
- “我这周的 TickTick 清单上有什么?”
- “添加一个周五上午 9 点给牙医打电话的任务。”
- “将买菜任务标记为已完成。”
- “将预算任务移到 Finance 项目。”
Docker
镜像发布在 ghcr.io/partymola/ticktick-mcp。标签带有 v 前缀(:vX.Y.Z),而 :latest 始终指向最近一次发布。
先在有浏览器的机器上完成授权,然后再挂载该目录。 这是唯一的方式,即使使用 docker run -it 也不例外:底层库会自行打开浏览器,而且绝不会打印 URL,因此无法从没有浏览器的容器中复制 URL。随后,它会在标准输入中等待该 URL;对于 stdio 服务,标准输入就是 JSON-RPC 通道。因此,如果容器启动时所在目录没有缓存令牌,它也不会干净地失败,而是会一直等待永远不会到来的输入,从而消耗客户端的请求。
授权需要源码安装(安装)和凭据;没有已发布的包可用于运行它。不要 pip install ticktick-mcp: PyPI 上的同名项目属于另一个项目,描述却几乎相同。
.venv/bin/ticktick-mcp auth # once, on the host, in a terminal
claude mcp add -s user ticktick -- \
docker run --rm -i --user $(id -u):$(id -g) \
-v ~/.config/ticktick-mcp:/data \
ghcr.io/partymola/ticktick-mcp:latest
必须使用 -i——服务通过 stdin 和 stdout 进行 JSON-RPC 通信。
使用 --user 是因为容器默认以 root 身份运行,而它写入挂载目录的任何内容都会归 root 所有。之后,主机上的 ticktick-mcp 将无法再更新其会话令牌缓存,并会在每次启动时退回到受限流的登录流程。你之后还会在主机上运行它:OAuth 令牌不支持刷新,因此到期时需要再次运行 auth。
挂载已完成授权的目录,绝不要挂载空卷。 /data 中存放 .env、缓存的 OAuth 令牌、v2 会话令牌和任务完成跟踪数据库。全新的卷不包含这些内容,而密码登录回退流程会触发 15-30 分钟的锁定。
如果你不想在磁盘上保留 .env,也可以改用环境变量传递凭据。仍然需要挂载目录——它用于存放令牌缓存,而不只是 .env:
docker run --rm -i --user $(id -u):$(id -g) \
-v ~/.config/ticktick-mcp:/data \
-e TICKTICK_CLIENT_ID -e TICKTICK_CLIENT_SECRET \
-e TICKTICK_USERNAME -e TICKTICK_PASSWORD \
ghcr.io/partymola/ticktick-mcp:latest
只写出变量名而不指定值,就会从 shell 中传递其值,因此机密不会出现在命令或 shell 历史记录中。这些变量会覆盖已挂载的 .env:加载文件时未启用 override,因此环境中已有的值优先。授权仍需要在主机上导出这些变量,因为 auth 同样没有 .env 可供读取。
CLI
ticktick-mcp Start the MCP server (stdio transport)
ticktick-mcp --dotenv-dir PATH Directory holding the .env file
ticktick-mcp --version Print the installed package version
auth 是唯一的其他子命令,其作用是在终端中完成浏览器授权步骤,而不是在服务内部完成。所有任务操作都通过下方的 MCP 工具执行。
MCP 工具
| 工具 | 描述 |
|---|---|
ticktick_create_task | 创建任务,保留日期、提醒、优先级和时区字段;对于已写入内容中值得注意的事项,会附加 _verification_warnings |
ticktick_update_task | 仅将你设置的字段覆盖到当前服务端对象上,以此更新任务(未提供的字段绝不会被清除) |
ticktick_complete_task | 将任务标记为已完成并重新验证;区分循环任务向后滚动与普通完成,并记录该完成已处理 |
ticktick_delete_tasks | 按 ID 删除一个或多个任务 |
ticktick_move_task | 将任务移至其他项目 |
ticktick_make_subtask | 在同一项目中,将一个任务嵌套为另一个任务的子任务 |
ticktick_get_tasks_from_project | 列出项目中的所有未完成任务(精简或完整格式) |
ticktick_filter_tasks | 按项目、优先级、标签、状态以及到期日期/完成日期范围的任意组合查找任务 |
ticktick_get_by_id | 按完整 ID 查找任意任务、项目或标签 |
ticktick_get_all | 从本地状态导出所有项目或所有标签 |
ticktick_sync | 立即强制从服务端刷新本地状态 |
ticktick_get_unprocessed_completions | 列出项目中最近完成、但尚未标记为已处理的任务;实际上,这些任务是在此服务之外完成的 |
ticktick_mark_completion_processed | 记录已审核某个已完成任务,并将其排除在后续检查之外 |
ticktick_convert_datetime_to_ticktick_format | 将 ISO 8601 日期时间和 IANA 时区转换为 TickTick 的线缆格式 |
项目:名称或 ID
所有接受项目 ID 的工具也接受项目的名称——ticktick_create_task、ticktick_get_tasks_from_project、ticktick_update_task、ticktick_move_task、ticktick_delete_tasks、ticktick_filter_tasks,以及两个完成跟踪工具:
ticktick_create_task(title="Renew insurance", project_id="Home Admin")
名称匹配时不区分大小写,并忽略首尾空格;"Inbox" 会解析为你的收件箱。ID 仍可照常使用,且始终优先。
如果两个项目同名,调用会失败,并列出两个 ID,而不会擅自选择一个,因为这样可能会把任务放到你意想不到的位置。
三个工具会先确认引用目标,再使用它;如果无法确定目标,则不会继续传递。两个完成跟踪工具这样做,是因为该值是其本地数据库写入时使用的键;如果无法解析,后续就无法按 ID 找到所写入的记录。ticktick_filter_tasks 这样做,是因为它在本地进行筛选;否则,未知项目会返回空列表,看起来像是“没有匹配的任务”,而不是“项目不存在”。这三个工具都会区分这两种失败:如果项目列表无法刷新以供检查,它们会明确说明(outcome: "project_list_unverifiable"),而不会声称项目不存在。
其余工具会原样传递无法识别的值。ticktick_get_tasks_from_project 和 ticktick_move_task 随后会在客户端库自己的本地查找中失败,不会发送任何请求;ticktick_create_task、ticktick_update_task 和 ticktick_delete_tasks 则会在使用该值时将其发送给 TickTick。
任务列表:默认使用紧凑模式
返回列表的工具 - ticktick_get_tasks_from_project 和 ticktick_filter_tasks - 默认使用 detail="compact"。紧凑输出保留浏览所需的字段(id、projectId、title、dueDate、startDate、priority、status、isAllDay、timeZone、tags),以及 contentPreview(content 的前约 200 个字符),并省略体积较大的 content/desc/清单 items 数据和繁杂的同步元数据。这能让大型项目的结果保持在 MCP 结果大小上限内,客户端无需将结果写入磁盘。关键词搜索仍会匹配 title 和 contentPreview。
- 需要完整对象?传入
detail="full"。 - 需要某个任务的完整内容?使用
ticktick_get_by_id。 - 编辑任务: 先用
ticktick_get_by_id获取完整对象,再通过ticktick_update_task传回所有字段。TickTick API 会清除更新中省略的任何字段,因此绝不能将紧凑输出用于更新。
如果紧凑结果仍会超出大小限制,则返回最早到期的任务,并在末尾添加 _truncation_note 元素,报告省略了多少项——不会悄悄丢弃任何内容。可通过更精确的 ticktick_filter_tasks 查询、detail="full" 或 ticktick_get_by_id 获取其余内容。
数据新鲜度:读取结果始终保持最新
服务器运行期间,TickTick 账户可能会在其他设备上的应用中被编辑。为避免读取结果过时,读取工具会按需重新同步服务器状态,并限制同步频率,默认每个时间窗口最多一次(默认 15s,可通过 TICKTICK_MCP_SYNC_TTL_SECONDS 覆盖)。在其他位置所做的更改会在该时间窗口内可见;调用 ticktick_sync 可立即强制刷新,并获取当前任务和项目数量。如果同步失败,则返回最近已知的状态,而不是报错——但 ticktick_get_all 除外。该工具每次调用都会刷新并报告失败,因为完整数据导出不应悄悄返回过时结果。
完成状态跟踪:队列的用途
ticktick_get_unprocessed_completions 会列出项目中已完成、但尚无 Agent 记录处理情况的任务,ticktick_mark_completion_processed 则用于记录某项任务。该队列的用途是处理并非由你完成的任务:在 TickTick 应用中勾选完成的任务,其说明发生了什么的备注正等待读取。
因此,ticktick_complete_task 会记录它自己完成的任务,并通过 completion_recorded 报告记录是否成功。无论记录结果如何,任务都会被视为已完成,因为记录是在 API 调用之后写入的;如果本地写入失败,只会记入日志,不会转为错误。通过此服务完成任务后,无需再调用 ticktick_mark_completion_processed;如果该任务已在此处记录,调用也不会产生任何效果。
有一种情况不会被覆盖,这是有意为之。完成重复任务时,已完成的实例会以新的 id 归档,而执行完成操作的调用无法获取该 id,因此无论由谁完成,该实例都会进入队列。任何形式的重复任务完成都不会被记录,结果中也不会包含 completion_recorded,而不是将其设为 false。不要试图对重复任务系列的 id 调用 ticktick_mark_completion_processed 来弥补:队列显示的并非这个 id,因此该行不会被清除。
通过 ticktick_update_task 重新打开任务时,会清除其先前完成状态的记录,因此下次完成时会正常显示:设置 status: 0,记录就会被清除。否则,在此处完成任务后,该任务会永久排除在队列之外,即使之后你在应用中勾选完成并附上备注也一样。如果你在应用中重新打开任务,则其记录会保留,因此之后在应用中再次完成时仍会排除在队列之外。
记录保存在 completion_tracking.db 中,与 .env 和令牌缓存位于同一目录。
配置
| 变量 | 默认值 | 描述 |
|---|---|---|
TICKTICK_MCP_DOTENV_DIR | ~/.config/ticktick-mcp/ | 存放 .env、缓存令牌和完成跟踪数据库的目录(--dotenv-dir 参数优先)。容器镜像将其设为 /data |
TICKTICK_MCP_SYNC_TTL_SECONDS | 15 | 按需读取重新同步的最短间隔秒数 |
TICKTICK_MCP_INIT_RETRY_SECONDS | 60 | 首次连接失败后,重试客户端登录前的冷却时间 |
TICKTICK_MCP_RATELIMIT_RETRY_SECONDS | 300 | 遇到速率限制(HTTP 429)后,重试登录前的冷却时间;由于 429 的影响会缓慢消退,且每次重试都会延长冷却时间,因此该时间长于初始化冷却时间 |
TICKTICK_MCP_PROTECTED_TASK_IDS | 未设置 | Agent 绝不能修改的任务 ID,以空格或逗号分隔。所有修改类工具在发送任何内容前都会拒绝操作;读取不受影响。未设置表示不启用保护。 |
保护任务,防止被修改
有些任务无论 Agent 收到什么指令,都不应被更改。请在 TICKTICK_MCP_PROTECTED_TASK_IDS 中列出其 ID:
TICKTICK_MCP_PROTECTED_TASK_IDS="60ca9dbc8f08516d9dd56324,60ca9dbc8f08516d9dd56325"
ticktick_update_task、ticktick_complete_task、ticktick_delete_tasks、ticktick_move_task 和 ticktick_make_subtask 随后会拒绝任何指定受保护任务的调用,并返回 outcome: "protected_task"。不会发送任何读取或写入该任务的请求。若批量删除中包含受保护 ID,则会拒绝整个操作,而非部分执行,因为部分删除无法撤销。
由于 TickTick 会将删除和移动操作传播到子任务,如果受保护任务是你指定任务的父任务或子任务,delete、move 和 make_subtask 也会拒绝操作。此检查会先刷新本地状态,因此启用保护后,每次删除、移动或更改父子关系都会额外发送一个请求;如果刷新失败,则会返回 outcome: "protection_unverifiable",因为无法根据未能更新的快照排除存在受保护子任务的可能性。未设置该变量时,不会执行任何额外操作。匹配 ID 时会忽略首尾空格、引号和大小写。始终可以读取受保护任务。
凭据(TICKTICK_CLIENT_ID、TICKTICK_CLIENT_SECRET、TICKTICK_REDIRECT_URI、TICKTICK_USERNAME、TICKTICK_PASSWORD)从 .env 文件读取;如果文件中没有,则直接从环境变量读取。
数据安全
pre-commit 钩子(scripts/check-no-data.sh)会阻止意外提交 *.db 文件及其备份文件、config/ 下除 .gitkeep、*.example 和 *.example.* 之外的所有内容,以及超过 100KB 的文件(uv.lock 除外)。它不会读取文件内容。克隆后安装该钩子:
ln -sf ../../scripts/check-no-data.sh .git/hooks/pre-commit
参与贡献
开发环境设置、测试工作流和 pre-commit 钩子请参阅 CONTRIBUTING.md。变更记录见 CHANGELOG.md。
许可证
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。