mcpField
T
ticktick-mcp

ticktick-mcp

本地服务
github.com/partymola生产力12 周前更新

关于 ticktick-mcp

ticktick-mcp 为 Claude Code 等 MCP 客户端提供 TickTick 任务管理能力。它支持完整任务操作,并通过保留未修改字段、写后复核和完成项追踪来减少状态偏差。

主要功能

  1. 01创建、更新、完成和移动任务
  2. 02更新时保留未指定字段
  3. 03设置日期时校验星期
  4. 04写入后重新读取并核对
  5. 05追踪尚未处理的已完成任务

适用场景

  1. 01按项目或截止日期筛选任务
  2. 02更新任务而不覆盖其他字段
  3. 03检查并处理外部完成的任务

MCP 相关

MCP 服务向客户端公开任务创建、查询、更新、删除、筛选及完成追踪等工具,并可在需要时同步 TickTick 状态。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"partymola-ticktick": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"TICKTICK_CLIENT_ID",
"-e",
"TICKTICK_CLIENT_SECRET",
"-e",
"TICKTICK_USERNAME",
"-e",
"TICKTICK_PASSWORD",
"ghcr.io/partymola/ticktick-mcp:v0.5.0"
],
"env": {
"TICKTICK_CLIENT_ID": "<TICKTICK_CLIENT_ID>",
"TICKTICK_CLIENT_SECRET": "<TICKTICK_CLIENT_SECRET>",
"TICKTICK_USERNAME": "<TICKTICK_USERNAME>",
"TICKTICK_PASSWORD": "<TICKTICK_PASSWORD>"
}
}
}
}
启动命令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.0
需要配置的环境变量
TICKTICK_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+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
ocighcr.io/partymola/ticktick-mcp:v0.5.0

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

ticktick-mcp

CI License: GPL v3 Python 3.13+ Glama MCP Server

用于 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 + 密钥)和你自己的账户登录信息。

  1. 在 developer.ticktick.com 注册一个应用。将 Redirect URI 设置为 http://localhost:8080/redirect。记下 Client ID 和 Client Secret。

  2. 将模板复制到服务读取的目录中,并填写内容:

    mkdir -p ~/.config/ticktick-mcp && cp .env.example ~/.config/ticktick-mcp/.env
    
    TICKTICK_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
    
  3. 此文件以纯文本形式保存你的账户密码,而且服务不会创建该文件,因此请自行收紧权限。在 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_SECONDS15按需读取重新同步的最短间隔秒数
TICKTICK_MCP_INIT_RETRY_SECONDS60首次连接失败后,重试客户端登录前的冷却时间
TICKTICK_MCP_RATELIMIT_RETRY_SECONDS300遇到速率限制(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。

许可证

GPL-3.0-or-later

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。