mcpField
T
Task Checkpoint

Task Checkpoint

本地服务
github.com/qddfxp记忆与知识05 周前更新

关于 Task Checkpoint

Task Checkpoint 是面向长时间编码或文档任务的 Python MCP 服务。它记录工作区变更和步骤说明,便于在新会话续做或回退,且不会改动 Git 历史。

主要功能

  1. 01保存工作区变更和任务步骤
  2. 02在新会话恢复任务进度
  3. 03预览并还原较早状态
  4. 04导出和导入交接包
  5. 05跟踪多个挂起任务

适用场景

  1. 01中断后继续尚未完成的工作
  2. 02任务中撤销错误变更
  3. 03将任务交接到其他目录或机器

MCP 相关

stdio MCP 服务提供初始化、保存、恢复、查看、还原和转移检查点的工具。配套的 `SKILL.md` 会指导 Agent 在每一步完成后保存。

配置

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

mcp.json · 通用配置
{
"mcpServers": {
"qddfxp-task-checkpoint": {
"command": "uvx",
"args": [
"task-checkpoint-mcp"
]
}
}
}
启动命令uvx task-checkpoint-mcp

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypitask-checkpoint-mcp0.1.7

工具

10

收录的工具列表 · 更新于 2 周前

参数类型必填说明
goalstring否任务目标
namestring是任务名
rootstring是工作区根目录
storestring否存档目录;省略时用工作区内 .checkpoints
excludearray否额外的排除模式,按单个名字段匹配(目录名或路径第一段),如 ["config", "*.local"]
constraintsstring否约束

详细介绍

Task Checkpoint MCP

PyPI npm License: MIT Python 3.10+ Dependencies: 0 MCP server

给长任务做"做一步、存一步"的存档:中断后新会话能接着做,做错了能退回任意一步。

一个 stdio MCP 服务器,只用 Python 标准库,不装任何第三方包。

快速开始 | 工具 | 客户端配置 | 使用限制 | English

快速开始

一、装

pipx install task-checkpoint-mcp

二、在客户端里接上(Claude Code、Codex、Cursor 等都是同一段配置)

{
  "mcpServers": {
    "task-checkpoint": { "command": "tc-mcp", "args": [] }
  }
}

三、把 SKILL.md 装进技能目录,不装的话 Agent 不会主动存档

tc-mcp --install-skill ~/.claude/skills/task-checkpoint

SKILL.md 随包一起装(wheel 里的包数据),不需要仓库、也不需要联网。想看内容用 tc-mcp --print-skill,想知道它在哪用 tc-mcp --skill-path。

(技能目录按客户端而定,见下面"把 SKILL.md 装进 Agent 的技能目录"。)

四、交给 Agent 用。 一个任务就四步:

tc_init    开任务
tc_save    每完成一步存一次(带 conclusion 和 next)
tc_resume  新会话开头先调这个接上进度
tc_restore 退回去(先 apply:false 预览,再 apply:true)

五、不用记工具名,直接说人话。

用 task-checkpoint 开个任务,目标是把 user 模块拆成 service 和 repository 两层。每完成一步存一次档,带结论和下一步。

它会调 tc_init 建任务,之后每完成一步调一次 tc_save。中途换会话、或者隔天接着做,你说一句"接着上次的做",它调 tc_resume 就把进度拿回来了。

("每完成一步就存档"这条约束的可靠来源是 SKILL.md —— 装进技能目录之后它是硬规则;不装,就只能靠你每次提醒。)

中途被打断、隔天换个模型重开,新会话调一次 tc_resume 拿到的是这个:

任务:重构认证模块
目标:把 session 改成 JWT
当前步骤:3
下一步:把三个视图函数切到新入口,删旧函数
未落档:src/views/auth.py, src/views/user.py

handoff 字段就是这段文本,可以直接粘给新会话。它同时告诉你哪几个文件改了但还没落档。

为什么不直接用 git stash 或随手 commit 一下

做法缺什么
git stash一次性的,不能命名、不能跨会话交接,也没有"这一步在做什么、结论是什么"
随手一个 commit会污染真实历史;半成品未必允许 commit;还得你记得先 commit
手写进度笔记和文件状态脱钩,回退时要自己对着时间线拼
本工具文件变化后台自动记(变更层),步骤语义由模型声明(任务层);只额外加 refs/checkpoints/...,不动你的 git 历史

值得装:多步、可能被中断、需要能退回的编码或文档任务。 不值得装:一次能做完、不需要回退也不需要交接的改动。

装之前先知道

  • 需要 Python 3.10 或更新,只用标准库。
  • 不碰你的 git 历史:不 commit、不 reset、不 clean、不动已有分支和 HEAD,只额外加 refs/checkpoints/... 引用。
  • 不是 git 仓库也能用,功能一样,只是少了那层 git 引用。
  • 不保存聊天记录,只保存工作区文件和模型主动声明的步骤说明。
  • 存档默认写在工作区的 .checkpoints/;指定外部 store 时,工作区仅留一个不含文件内容的 .task-checkpoint-store.json 路径指针。
  • 敏感文件识别是路径黑名单,盖不全。 别把凭据放在被扫路径里 —— 详见"使用限制"。

安装

方式一:装成命令(推荐)
pipx install task-checkpoint-mcp
# 或
pip install task-checkpoint-mcp

也可以直接从 git 装,跟着仓库走、不走 PyPI 的版本号:

pipx install "git+https://github.com/qddfxp/task-checkpoint-mcp"

装完在客户端里用 tc-mcp 启动。包里有两个等价的入口点:tc-mcp 和 task-checkpoint-mcp(后者是给 uvx 这类按包名找命令的 runner 用的):

{
  "mcpServers": {
    "task-checkpoint": { "command": "tc-mcp", "args": [] }
  }
}
方式二:直接用源码(不用安装)
git clone https://github.com/qddfxp/task-checkpoint-mcp
{
  "mcpServers": {
    "task-checkpoint": {
      "command": "/absolute/path/to/python",
      "args": ["/absolute/path/to/task-checkpoint-mcp/scripts/tc_mcp.py"]
    }
  }
}

command 要写解释器的绝对路径,不要写 python —— 客户端不一定能解析到你要的那个。装过之后也可以直接 python -m tc_mcp。

方式三:用 npx 启动

npm 上有一个同名的 task-checkpoint-mcp,但它是启动器,不是服务器本体:

npx -y task-checkpoint-mcp

它只做一件事:找到本机装了 tc_mcp 的 Python 解释器,然后把 stdio 透传给 python -m tc_mcp。所以本机仍然要先有 Python 包(方式一或方式二)。没有的话它会打印安装命令、以退出码 1 结束,而不是丢一堆 traceback 给你。

适合客户端只认 npm 式启动命令的情况:

{
  "mcpServers": {
    "task-checkpoint": { "command": "npx", "args": ["-y", "task-checkpoint-mcp"] }
  }
}

npx -y task-checkpoint-mcp --version / --help 是启动器自己的开关,不需要本机有 Python。

配置文件放哪

上面那段 mcpServers JSON 要写进客户端的配置文件。各客户端的位置和顶层键:

客户端配置文件顶层键
Claude DesktopWindows %APPDATA%\Claude\claude_desktop_config.json;macOS ~/Library/Application Support/Claude/claude_desktop_config.jsonmcpServers
Claude Code项目根目录 .mcp.jsonmcpServers
Cursor全局 ~/.cursor/mcp.json;项目内 .cursor/mcp.json 优先mcpServers
Windsurf~/.codeium/windsurf/mcp_config.jsonmcpServers
ZCode~/.zcode/cli/config.jsonmcpServers
VS Code / Copilot项目内 .vscode/mcp.json;用户级 %APPDATA%\Code\User\mcp.jsonservers
Codex CLI~/.codex/config.tomlTOML 的 [mcp_servers],不是 JSON

两个容易踩的:

VS Code 的顶层键是 servers,不是 mcpServers。 直接抄上面的 JSON 不会生效,得改键名:

{
  "servers": {
    "task-checkpoint": { "command": "tc-mcp", "args": [] }
  }
}

Codex 用 TOML。 同样一段配置要写成:

[mcp_servers.task-checkpoint]
command = "tc-mcp"
args = []

其余客户端以各自的文档为准。

怎么用

最重要的一条:文件变化由后台线程自动记录,但"这一步在做什么、结论是什么、下一步干什么"只有模型主动调 tc_save 才会留下。

所以要让 Agent 每完成一步就存一步 —— 这份约束写在 SKILL.md 里,得把它装进 Agent 的技能目录(见下面"把 SKILL.md 装进 Agent 的技能目录")。不装它,文件回退点照常产生,但没人知道当初要干什么、下一步该干什么。

四条铁律:

  1. 开长任务前先 tc_init,一个任务一个名。已有活动任务会被挂起而不是关闭,可以 tc_switch 切回去。
  2. 每完成一步就 tc_save,并且必须填 conclusion 和 next。不填,新会话就只看得到一堆文件路径。
  3. 新会话、或中断后继续时,第一件事是 tc_resume,不要从零猜进度。
  4. 回退前先预览:先 apply: false 看清单,确认了再 apply: true。

一步的粒度:能独立说清"做完了、结论是 X"的单元。太细(每个文件一次)会淹没有效信息,太粗(整个任务一次)就失去了回退的意义。

工具

10 个。第一个参数都是 root,指工作区目录(通常是当前项目的绝对路径)。

工具什么时候用必填
tc_init长任务开工。已有活动任务会被挂起而不是关闭root, name
tc_save每完成一步root, title
tc_resume新会话开头、接手别人中断的工作(只读)root
tc_show想看有哪些步骤 / 变更记录root
tc_restore退回某一步或某条变更记录。先预览再执行root,加 index 或 drift_id
tc_capture想立刻记一次文件变化(不等后台线程)root
tc_switch回到之前挂起的任务root, task_id
tc_export导出交接包给另一个目录 / 另一台机器root, to
tc_import导入别人的交接包,在这里接续任务root, package
tc_compress存档太大了,回收旧变更层空间root

tc_save 的完整参数:

  • title(必填)——这一步一句话标题,写"做了什么",不写"改了什么"
  • conclusion——这一步的结论。最有价值的字段
  • next——下一步要干什么。接续工作的关键
  • description——为什么这么做(决策理由,事后没人记得)
  • verified——已验证项列表(跑了什么测试、确认了什么事实)
  • open_questions——还没解决、留给后面的问题
  • close: true——收尾时用。关闭后不能再存档,但还能读

回退操作本身也会被记成一条变更记录,返回里的 recovered 就是它的 drift_id —— 退错了可以再用它退回来。

返回值里几个值得看的字段
  • tc_resume.handoff —— 一段现成的交接文本,可以直接粘给新会话;drift_paths 是工作区里还没落档的改动;health.errors 是存档自身的问题
  • tc_save.idempotent —— 同一步(标题、文件摘要、结论、下一步、已验证项都一样)重复存,不会产生重复步骤
  • tc_save.active_task_changed —— 传了别人的 task_id 时活动任务会被切过去(原任务变 suspended),这个字段就是在提示这件事
  • tc_restore.recovered —— 回退本身也会被记成一条变更记录,这就是它的 drift_id
  • tc_restore.plan.unrestorable / skipped_paths —— 目标里没能还原的文件;预览和执行给的是同一份清单
  • tc_capture.waiting / partial —— 还在静默期,以及中间那条不完整的记录
  • tc_init.exclude —— 回读你这次设进去的排除模式
  • tc_export.path —— 交接包目录,里面有一个 HANDOFF.md,是给接手方的提示词

把 SKILL.md 装进 Agent 的技能目录

SKILL.md 是这个项目的另一半功能,不是可选文档:MCP 服务器负责存取,SKILL.md 负责让模型每完成一步真的去调 tc_save。

复制到客户端扫描的技能目录,目录名即技能名:

客户端放这里
Claude Code~/.claude/skills/task-checkpoint/SKILL.md
Codex CLI~/.codex/skills/task-checkpoint/SKILL.md
ZCode~/.zcode/skills/task-checkpoint/SKILL.md
跨客户端共用~/.agents/skills/task-checkpoint/SKILL.md

~/.agents/skills/ 是多个客户端共用的技能目录;客户端专属目录优先于它 —— 同名技能以客户端专属目录里的那份为准。OpenCode 等其它客户端放到它自己文档里的技能目录即可,规则不变。

tc-mcp --install-skill ~/.claude/skills/task-checkpoint

SKILL.md 是随包一起安装的(wheel 里的包数据),所以 pipx install 的用户不需要仓库,也不需要联网。目标已存在时会拒绝覆盖 —— 确实要覆盖加 --force;只想看内容用 tc-mcp --print-skill。

克隆了仓库的话,cp SKILL.md <技能目录>/ 效果一样。

Windows 路径形如 C:\Users\<你>\.claude\skills\task-checkpoint\SKILL.md。各客户端的技能目录可能不同,以它自己的文档为准;要求只有一条:文件落在技能目录下的 <技能名>/SKILL.md。重启客户端后生效。

自检(可选)

装完最快的一条,确认入口点活着、拿到版本号:

tc-mcp --version        # 版本号
tc-mcp --help           # 所有开关

下面几条都要先克隆仓库 —— pip 装出来的包里没有 tests/ 和 tools/。

在克隆下来的仓库里跑一遍回归测试:

python -m unittest discover -s tests -p "test_*.py" -v

最后一行是 OK 就对了。整套测试(100 多个用例)跑一次的时间完全看环境:

跑在哪实测
CI 的 ubuntu runner4.7 秒
CI 的 windows runner39.8 秒
本机 Windows(E 盘)156~340 秒

同一套代码差了七十倍。开销集中在 git 子进程(refs/checkpoints/ 相关用例占大头)和静默期等待,对磁盘和杀毒的实时扫描极其敏感 —— 别把秒数当承诺,也别拿一个数字去对比另一台机器。

全部只用标准库,不需要 pytest;在 Python 3.10 上也能跑,只有读 pyproject.toml 的那几条会因为 tomllib 被跳过(3.11+ 全跑)。

仓库里还能跑真机端到端演练(起真 MCP 子进程、真杀进程、建约 190 MB 的重工作区、逐项核对"不动你 git"的承诺):

python tools/drill.py

它跑完默认把场地删掉;想看场地就 TC_DRILL_KEEP=1 python tools/drill.py(演练有未通过项时也会自动保留,方便排查)。

确认 MCP 服务器能起来 —— 会回一行带 serverInfo 的 JSON:

echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18"}}' | python scripts/tc_mcp.py

从 pip 装的版本没有 scripts/,把上面那条改成 ... | tc-mcp(或 python -m tc_mcp)就行。

环境变量

变量默认说明
TC_STORE<工作区>/.checkpoints存档目录
TC_WATCHon设成 off 关掉后台自动记录
TC_WATCH_INTERVAL15后台检查间隔(秒)
TC_DRIFT_MAX_WAIT60静默期上限(秒)
TC_GITon设成 off 就完全不建 refs/checkpoints/... 引用
TC_GIT_VERIFYon建引用前后对比 git 指纹,自证"没动过用户 git"。设成 off 跳过自证,每次 tc_save 少几趟 git 子进程;跳过后返回的 git.unchanged 是 null
TC_SHA_REUSEoffmtime+size 没变的文件不再重读、直接复用索引里的 sha。风险见"使用限制"

使用限制

敏感文件:黑名单,盖不全

敏感文件不存内容、连哈希都不存,只能看出 mtime 和 size 变了没有。判定按路径匹配,所以两头都会漏:

  • 漏判:名字无辜的凭据抓不到。config/database.yaml、docker-compose.yml、config.json 会被当普通文件明文存进 payload/。别把凭据放在被扫路径里;避不开时用 tc_init(exclude=[...]) 把整个目录排掉。
  • 误拦:被误判为敏感的源码永远拿不到内容副本,回退时会静默跳过(只出现在 plan.unrestorable 里)。名单分两层就是为压低误拦。

拦的范围:

  • 目录名(整个目录都不存) .ssh .aws .gnupg .docker .kube .env .envdir .secrets .tokens,或名字含 secret / credential / token 的目录。
  • 无歧义文件名
    • dotenv:.env .env.* *.env *.env.* .envrc
    • 私钥:*.pem *.key *.p12 *.pfx *.p8 *.jks *.keystore *.kdbx *.ppk *.ovpn *_rsa *_dsa *_ed25519 *_ecdsa *_key
    • 凭据:.netrc .git-credentials .npmrc .pypirc .pgpass .htpasswd .my.cnf my.cnf passwd shadow
    • 云与基础设施:kubeconfig *.kubeconfig *.tfstate terraform.tfvars *.tfvars *.jwt
    • 通配:credentials* creds* secret* secrets.json token token.json token.txt *.token *_token auth.json
    • 框架配置:settings.py local_settings.py settings.xml wp-config.php web.config wrangler.toml .dev.vars
  • 高歧义子串,只在文件名以配置类后缀结尾时才拦
    • 子串:*secret* *password* *passwd* *credential* *api_key* *apikey* *token* *auth_token*
    • 后缀:.json .yaml .yml .toml .ini .cfg .conf .config .properties .xml .txt .env .envrc .cnf .sh .ps1 .bat .cmd .sql .php
    • 所以 prod_credentials.json 拦;src/password_policy.py、src/tokenizer.py、docs/secrets.md 不拦。

exclude 的匹配方式和内置名单一致:按单个名字段做 glob(目录名,或路径的第一段)。所以 exclude=["config"] 会排掉任意层级的 config/ 目录,但不能只排某个具体文件(要排 config/database.yaml 就得连 config/ 一起排)。带 / 的模式会被直接拒绝,不会静默失效。

这条能力不构成隐私保护或合规保证。 存档目录的访问权限由你自己管;别把未排除的凭据、令牌、私钥、个人资料放进被扫路径。

时间与粒度
  • 静默期最长约 60 秒。文件一直在写时,中间那条记录标 partial: true。
  • 进程突然死掉后、下次 tc_save / tc_capture 之前,最后那段改动只在 tc_resume 的未落档路径里,还不是一条变更层记录。
变更层只看 mtime+size

tc_capture 和后台线程用 mtime+size 判断变化。内容改了但 mtime 和长度都没变时(cp -p、rsync -t、tar -x 会保留 mtime),它不会觉得文件变了。

任务层 tc_save 默认按内容算 sha,不受此限;但 TC_SHA_REUSE=on 会把任务层也拉到同一判据上 —— 见下面那条。

回退
  • 会一并还原文件权限位(POSIX 可执行位),不还原 mtime —— 把旧时间戳写回去会让 make 类工具误以为文件没变。注意:只改权限、内容没变时不会触发重写(回退只重写内容不同的文件),那种情况下权限位也回不去。
  • 不能还原的文件会被跳过(敏感文件、超过 100 MB 未存内容、payload 已丢),其余照退;跳过的列在返回的 plan.unrestorable 里。预览和实际执行用同一份清单,所以一个 .env 不会让整次回退失效。
  • 二进制能还原,但不能做行级 diff;不合并并发编辑。
大文件

不超过 100 MB 的文件原样按 sha 存进 payload/,相同内容只存一份;超过 100 MB 只记流式哈希和元数据,不保存内容,因而不能回退内容。

存档不会自动缩

旧变更层的内容会一直留着,用 tc_compress 手动回收。它的默认参数是保留 7 天,所以小工作区上默认调用往往是 converted: 0(什么都没回收)—— 返回值里带 keep_seconds / minimum / maximum / eligible / bytes_freed,看得出"为什么没回收"。想真的清就用小一点的 keep_seconds(步骤基线和 recovered 层永远不动)。

TC_SHA_REUSE=on 的风险(默认关的原因)

任务层默认每次都按内容算 sha,不信任 mtime,所以一次 save 会读完工作区里所有非敏感文件(不保留内容,内存占用与工作区大小无关)。

开了 TC_SHA_REUSE=on 之后,mtime+size 没变的文件不再重读、直接复用索引里的 sha。遇到 mtime 被还原(os.utime)、文件系统 mtime 粒度粗(FAT、部分网络盘)、或有工具保留 mtime(cp -p、rsync -t、tar -x、部分生成器)时,内容改动会被完全漏掉:不读盘、不存新内容,却把旧 sha 记进步骤,回退时静默给出旧内容。默认关闭时这条路径不存在。

tc_resume 和 tc_show 无论哪种模式都不读文件内容(只看 mtime+size),因此也可能漏掉"保留 mtime 的改动"。

参数与状态约束
  • tc_restore 必须且只能传 index 或 drift_id 其中一个;apply=true 不允许修改已关闭任务。
  • tc_save 传了 task_id(而且不是当前活动任务)时,会先把活动任务切过去(原任务置为 suspended)再存这一步;返回值里的 active_task_changed: true 就是告诉你这件事发生了,想切回去用 tc_switch。
  • tc_save 在已有基线且检测到未落档变化时,会先把该变化挂到本次 save 的 manifest 上,再写任务步骤。
  • tc_export 要求目标父目录已存在;tc_import 会校验任务 id 和工作区路径,拒绝重复任务、.. 穿越与符号链接目标;导入失败会撤销已写入的目标文件。
  • store 不得等于工作区根目录;自定义 store 位于工作区内时会被扫描器自动排除。
git 相关

在 git 仓库里每次 tc_save 会多花几百毫秒(建引用的 git 子进程开销)。不想付这笔开销就 TC_GIT=off 或 TC_GIT_VERIFY=off。

实现备注

只有改这份代码的人才需要关心:

  • 归档目录里的 .git/index 字节数会被 git 自己刷新(status / ls-files 会更新 stat cache),但 HEAD、分支、暂存内容都不会变 —— 自证就是拿 status / ls-files 的输出前后对比的。
  • refs/checkpoints/ 下已有同名引用时拒绝覆盖。
  • tc_show / tc_resume 只在读取状态快照时持有短锁;工作区扫描和文件读取不长期阻塞写入操作。
  • manifest 是增量链,每 20 份强制一个全量锚点。

存储

<工作区>/.checkpoints/
├── current.json          活动任务指针,按工作区 root 分键(同一个 store 可服务多个工作区)
├── state.lock            并发锁
├── server.log            日志(不会写到 stdout,stdout 只走 MCP 帧)
├── payload/<sha前两位>/  内容寻址的文件副本(多个任务/步骤共享,按 sha 去重)
└── tasks/<task_id>/
    ├── state.json
    ├── index.json            基线索引:每个文件的 mtime/size/sha256
    ├── steps/sNNNN.json      任务层:每一步的说明
    ├── drifts/dNNNN.json     变更层:文件变化
    └── manifest/mNNNN.json   一致性清单(增量链,每 20 份一个全量锚点)

活动指针和基线索引都按范围隔离:同一个 store 被几个工作区共用时,互不串味。

目录结构

.
├── README.md        本文件
├── SKILL.md         给 Agent 看的使用约束(功能的一部分,会随包一起安装)
├── LICENSE          MIT
├── pyproject.toml   打包配置,源码不改成包目录
├── MANIFEST.in      sdist 包含哪些文件
├── server.json      官方 MCP Registry 的发布元数据
├── glama.json       Glama 目录的所有权标记
├── scripts/
│   ├── tc.py        业务核心
│   └── tc_mcp.py    stdio MCP 适配层 + 给人用的命令行开关
├── tools/
│   └── drill.py     真机端到端演练探针(不进测试套件,手动跑)
├── npm/             npm 启动器包(只是壳,服务器本体不在这里)
├── tests/
│   ├── test_tc.py                       完整验收测试(回退安全、并发锁、git ref、返回字段、打包契约)
│   ├── test_tc_regressions.py           针对已修缺陷的定向回归
│   └── test_packaging_consistency.py    三处版本号 / 注册表元数据 / README 所有权标记的一致性
└── .github/workflows/ci.yml             CI:跑测试、构建、校验 server.json 与 wheel

构建产物不进仓库。发布走两条:PyPI 上的 task-checkpoint-mcp(pipx install task-checkpoint-mcp)是主渠道,wheel 和 sdist 同时挂在 GitHub Releases 上。

参与

欢迎提交 Issue 和 PR。动代码前先跑一遍测试(见上面“自检”,100 多个用例,本机 2.5~6 分钟)。

  • tests/test_tc.py 是完整验收套件:回退安全、并发锁、git ref 可达性、每个分支的返回字段、打包契约
  • tests/test_tc_regressions.py 是已修缺陷的定向回归 —— 新修一个 bug 就往这里加一条,别只改代码

有一条硬约束:只用标准库。所以不接受任何新增依赖,测试依赖也不行(测试用 unittest,不用 pytest)。

许可证

MIT,见 LICENSE。


Task Checkpoint MCP(英文)

为长期 Agent 任务提供检查点和续接:逐步保存每一步,在新会话中继续工作,并回滚到任意较早步骤。

一个用纯 Python 标准库编写的 stdio MCP 服务——无需第三方包。Python 3.10+。

快速开始 | 工具 | 客户端配置 | 限制

快速开始

1. 安装

pipx install task-checkpoint-mcp

2. 将其接入客户端(Claude Code、Codex、Cursor 等均使用同一配置块)

{
  "mcpServers": {
    "task-checkpoint": { "command": "tc-mcp", "args": [] }
  }
}

**3. 将 SKILL.md 安装到技能目录。**没有它,Agent 不会自行创建检查点。

mkdir -p ~/.claude/skills/task-checkpoint
curl -fsSL -o ~/.claude/skills/task-checkpoint/SKILL.md \
  https://raw.githubusercontent.com/qddfxp/task-checkpoint-mcp/main/SKILL.md

(不同客户端的技能目录有所不同——参见下文“将 SKILL.md 安装到 Agent 的技能目录”。)

**4. 让 Agent 使用它。**一个任务需要调用四次:

tc_init    start a task
tc_save    once per completed step (with conclusion and next)
tc_resume  first call in a new session, to pick up where you left off
tc_restore roll back (apply:false to preview, then apply:true)

5. 不必记住工具名称——直接描述需求即可。

使用 task-checkpoint 启动任务:目标是将用户模块拆分为服务层和仓储层。每完成一步都创建检查点,并说明结论和下一步计划。

它会调用 tc_init 创建任务,并在每一步之后调用 tc_save。切换会话,或第二天再回来,说“从上次停下的地方继续”,它就会调用 tc_resume,接着推进进度。

(可靠的“每一步之后都创建检查点”要求来自 SKILL.md——安装到技能目录后,它就是硬性规则。没有它,你每次都得提醒 Agent。)

任务中途被打断,第二天在另一个模型上恢复——只需在新会话中调用一次 tc_resume,即可得到:

任务:重构认证模块
目标:把 session 改成 JWT
当前步骤:3
下一步:把三个视图函数切到新入口,删旧函数
未落档:src/views/auth.py, src/views/user.py

这段文本就是 handoff 字段,可直接粘贴到新会话中。它还会列出已更改但尚未记录的文件。

为什么不用 git stash,或者直接提交?

方式缺少的功能
git stash一次性操作:没有名称,无法跨会话交接,也没有关于这一步做了什么或得出了什么结论的信息
快速提交污染真实历史;未完成的工作不一定能提交;还得记得先提交
手写进度笔记与文件状态脱节——回滚时需要手动对照时间线进行协调
此工具后台线程记录文件变更(漂移层);模型声明步骤语义(任务层)。它只添加 refs/checkpoints/...,绝不触碰你的 git 历史

适合安装的场景:可能被打断、需要可逆操作的多步骤编码或写作任务。不适合的场景:可以一气呵成完成,且不需要回滚或交接的改动。

安装前须知

  • Python 3.10 或更高版本,仅使用标准库。
  • 不会改动你的 git 历史记录:不会执行 commit、reset、clean、branch 或 HEAD 更改。只会添加 refs/checkpoints/... 引用。
  • 也可在 git 仓库之外运行——功能相同,只是不包含引用层。
  • 不会存储聊天记录——只存储工作区文件和模型声明的步骤说明。
  • 存储位置默认为 <workspace>/.checkpoints/。使用外部 store 时,工作区只会保留 .task-checkpoint-store.json 路径指针,不包含任何文件内容。
  • **敏感文件检测采用路径黑名单,无法覆盖所有情况。**请勿在扫描路径中放置凭据——参见限制。

安装

选项 1 — 从 PyPI 安装(推荐)
pipx install task-checkpoint-mcp
# or
pip install task-checkpoint-mcp

也可以直接从 git 安装,跟踪仓库并跳过 PyPI 版本管理:

pipx install "git+https://github.com/qddfxp/task-checkpoint-mcp"

然后将客户端指向 tc-mcp。此软件包提供两个功能相同的入口点——tc-mcp 和 task-checkpoint-mcp(后者适用于 uvx 等按软件包名称查找命令的运行器):

{
  "mcpServers": {
    "task-checkpoint": { "command": "tc-mcp", "args": [] }
  }
}
选项 2 — 从源代码运行(无需安装)
git clone https://github.com/qddfxp/task-checkpoint-mcp
{
  "mcpServers": {
    "task-checkpoint": {
      "command": "/absolute/path/to/python",
      "args": ["/absolute/path/to/task-checkpoint-mcp/scripts/tc_mcp.py"]
    }
  }
}

command 必须是解释器的绝对路径,不能只写 python——客户端可能无法解析你想要使用的解释器。安装后也可以使用 python -m tc_mcp。

选项 3 — 通过 npx 启动

npm 上有一个同名软件包,但它是启动器,不是服务端:

npx -y task-checkpoint-mcp

它只负责查找一个可导入 tc_mcp 的 Python 解释器,并将 stdio 转交给 python -m tc_mcp。因此,你仍需先安装 Python 软件包(选项 1 或 2)。如果没有安装,启动器会打印安装命令并以状态码 1 退出,而不会输出一长串 traceback。

当客户端只支持 npm 风格的启动命令时,可以使用它:

{
  "mcpServers": {
    "task-checkpoint": { "command": "npx", "args": ["-y", "task-checkpoint-mcp"] }
  }
}

npx -y task-checkpoint-mcp --version / --help 属于启动器,无需本地 Python。

配置文件的位置

mcpServers 块应放在客户端的配置文件中。以下是配置文件位置和顶层键:

客户端配置文件顶层键
Claude DesktopWindows %APPDATA%\Claude\claude_desktop_config.json;macOS ~/Library/Application Support/Claude/claude_desktop_config.jsonmcpServers
Claude Code项目根目录中的 .mcp.jsonmcpServers
Cursor全局配置 ~/.cursor/mcp.json;项目本地配置 .cursor/mcp.json 优先mcpServers
Windsurf~/.codeium/windsurf/mcp_config.jsonmcpServers
ZCode~/.zcode/cli/config.jsonmcpServers
VS Code / Copilot项目本地 .vscode/mcp.json;用户级 %APPDATA%\Code\User\mcp.jsonservers
Codex CLI~/.codex/config.tomlTOML [mcp_servers],而非 JSON

两个容易踩的坑:

**VS Code 使用的键是 servers,不是 mcpServers。**直接复制上面的 JSON 不会生效——请将键名改为:

{
  "servers": {
    "task-checkpoint": { "command": "tc-mcp", "args": [] }
  }
}

**Codex 使用 TOML。**对应的条目如下:

[mcp_servers.task-checkpoint]
command = "tc-mcp"
args = []

对于其他客户端,请参阅其自身文档。

用法

最重要的一条规则:后台线程会自动记录文件更改,但“这一步做了什么、得出了什么结论、接下来要做什么”只有在模型调用 tc_save 后才会留下记录。

因此,Agent 必须在每完成一步后创建检查点。这项约定写在 SKILL.md 中,你需要将它安装到 Agent 的技能目录(见下文)。没有它,你仍能获得文件回滚点,但没人知道你在做什么或接下来要做什么。

四条规则:

  1. 开始长任务前调用 tc_init,每个任务使用一个名称。已有的活动任务会被暂停,而不是关闭;使用 tc_switch 返回该任务。
  2. 每完成一步后调用 tc_save,并且务必填写 conclusion 和 next。否则,下一个会话只会看到一堆文件路径,除此之外一无所知。
  3. 在新会话中或中断后,先调用 tc_resume。不要从头猜测进度。
  4. 回滚前先预览:先设置 apply: false 查看列表,再设置 apply: true。

步骤粒度:一个可以描述为“已完成,结论是 X”的单元。粒度太细(每个文件一步)会淹没关键信息;粒度太粗(每个任务一步)则失去回滚的意义。

工具

共有 10 个工具。每个工具都将 root 作为第一个参数,即工作区目录(通常是项目的绝对路径)。

工具使用时机必填参数
tc_init开始长任务时。已有的活动任务会被暂停,而不是关闭root、name
tc_save每完成一步后root、title
tc_resume新会话开始时,或接手被中断的工作时(只读)root
tc_show检查步骤/漂移记录root
tc_restore回滚到某个步骤或漂移记录。应用前先预览root,以及 index 或 drift_id
tc_capture立即强制捕获文件更改,无需等待线程root
tc_switch返回先前暂停的任务root、task_id
tc_export将交接包导出到另一个目录/机器root、to
tc_import导入他人的交接包并在此继续工作root、package
tc_compress从旧漂移层中回收空间root

tc_save 字段:

  • title(必填)——用一行说明你做了什么,而不是更改了什么
  • conclusion——这一步得出的结论。最有价值的字段
  • next——接下来要做什么。让工作可以继续推进的关键
  • description——这么做的原因(以后没人记得的推理过程)
  • verified——你实际运行并确认的内容
  • open_questions——留给后续处理的未解决问题
  • close: true——结束任务。已关闭的任务仍可读取

回滚本身也会记录为一条漂移记录;返回的 recovered 是该记录的 drift_id,因此错误的回滚也可以回滚。

值得关注的响应字段
  • tc_resume.handoff——可直接粘贴到新会话中的现成交接文本;drift_paths 是磁盘上尚未记录的更改;health.errors 是存储本身的问题
  • tc_save.idempotent——重复保存相同步骤(标题、文件摘要、结论、下一步和已验证内容相同)不会产生重复记录
  • tc_save.active_task_changed——传入另一个任务的 task_id 会切换活动任务(旧任务会被暂停);此字段会告知你发生了切换
  • tc_restore.recovered——回滚自身的 drift_id
  • tc_restore.plan.unrestorable/skipped_paths——无法还原的文件;预览和执行使用相同的列表
  • tc_capture.waiting/partial——仍处于静默期内,以及尚未完成的中间记录
  • tc_init.exclude——回显你设置的排除模式
  • tc_export.path——交接包目录,其中包含供接手工作的人使用的 HANDOFF.md 提示词

将 SKILL.md 安装到 Agent 的技能目录

SKILL.md 是本项目的另一半,并非可有可无的文档:MCP 服务负责存储,SKILL.md 则让模型在每个步骤之后实际调用 tc_save。

将它复制到客户端会扫描的目录中;该目录名就是技能名称。

客户端路径
Claude Code~/.claude/skills/task-checkpoint/SKILL.md
Codex CLI~/.codex/skills/task-checkpoint/SKILL.md
ZCode~/.zcode/skills/task-checkpoint/SKILL.md
在多个客户端之间共享~/.agents/skills/task-checkpoint/SKILL.md

多个客户端共享 ~/.agents/skills/;如果同一技能名称同时存在于共享目录和客户端专属目录中,客户端专属目录优先。对于 OpenCode 和其他客户端,请使用该客户端文档中说明的技能目录——规则不变。

tc-mcp --install-skill ~/.claude/skills/task-checkpoint

SKILL.md 作为包数据包含在 wheel 中,因此 pipx install 用户既不需要仓库,也不需要网络访问。它不会覆盖已有文件——如果确实需要覆盖,请添加 --force。tc-mcp --print-skill 会打印文件内容。

如果使用克隆的仓库,cp SKILL.md <skill-dir>/ 效果相同。

在 Windows 上,路径如下:C:\Users\<you>\.claude\skills\task-checkpoint\SKILL.md。不同客户端可能会扫描不同目录——请查阅各自的文档。唯一的要求是文件位于 <skill-dir>/<skill-name>/SKILL.md。重启客户端以使其生效。

验证(可选)

最快的检查方式是确认入口正常运行,并查看所用版本:

tc-mcp --version        # version
tc-mcp --help           # all flags

以下所有操作都需要克隆的仓库——pip 安装包不包含 tests/ 或 tools/。

在克隆的仓库中运行回归测试套件:

python -m unittest discover -s tests -p "test_*.py" -v

最后一行应为 OK。完整测试套件(100 多个用例)所需时间完全取决于运行环境:

环境测得耗时
CI ubuntu runner4.7 s
CI windows runner39.8 s
本机,Windows(E: 驱动器)156–340 s

相同代码,耗时相差 70 倍。开销来自 git 子进程(refs/checkpoints/ 用例占了大头)和静默期等待,而且对磁盘速度和实时防病毒扫描极其敏感——因此,不要将这些数字视为保证,也不要据此比较不同机器。

仅使用标准库(unittest),不需要 pytest。它也可在 Python 3.10 上运行;读取 pyproject.toml 的用例会在该版本中跳过,因为 tomllib 需要 Python 3.11 或更高版本。

仓库还提供了一个针对真实工作区的端到端演练(启动真实的 MCP 子进程,在运行中途将其终止,构建一个约 190 MB 的大型工作区,并逐项验证“不会触碰你的 git”这一承诺):

python tools/drill.py

演练结束时会删除工作区;使用 TC_DRILL_KEEP=1 python tools/drill.py 可保留工作区(如果演练失败,也会自动保留,以便诊断)。

确认 MCP 服务能够启动——它会返回一行包含 serverInfo 的 JSON:

echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18"}}' | python scripts/tc_mcp.py

通过 pip 安装的副本没有 scripts/;请将最后一部分改为 ... | tc-mcp(或 python -m tc_mcp)。

环境变量

变量默认值含义
TC_STORE<workspace>/.checkpoints存储目录
TC_WATCHon设为 off 可禁用后台记录器
TC_WATCH_INTERVAL15后台轮询间隔(秒)
TC_DRIFT_MAX_WAIT60静默期上限(秒)
TC_GITon设为 off 可完全停止创建 refs/checkpoints/...
TC_GIT_VERIFYon前后检查 git 指纹,以证明未触碰你的仓库。设为 off 可让每次 tc_save 少运行几个 git 子进程;此时 git.unchanged 将返回 null
TC_SHA_REUSEoff当 mtime 和 size 未变化时,复用已索引的 sha,而不是重新读取。风险说明请参阅“限制”

限制

敏感文件:覆盖不全的黑名单

敏感文件既不存储内容,也不存储哈希——只记录 mtime 和大小是否发生变化。检测依据路径匹配,因此会出现两种漏判:

  • 假阴性:凭证文件名看起来很普通,因此不会被拦截。config/database.yaml、docker-compose.yml、config.json 会以明文形式存储在 payload/ 中。请勿将凭证放在扫描路径中;如果无法避免,请使用 tc_init(exclude=[...]) 排除整个目录。
  • 假阳性:被误判为敏感文件的源文件不会保存内容副本,因此回滚时会静默跳过这些文件(它们只会出现在 plan.unrestorable 中)。这就是名单分为两层的原因。

以下内容会被拦截:

  • 目录名(整个目录):.ssh .aws .gnupg .docker .kube .env .envdir .secrets .tokens,以及名称包含 secret / credential / token 的任何目录。
  • 明确的文件名:.env .env.* *.env *.envrc;*.pem *.key *.p12 *.pfx *.p8 *.jks *.keystore *.kdbx *.ppk *.ovpn *_rsa *_dsa *_ed25519 *_ecdsa *_key;.netrc .git-credentials .npmrc .pypirc .pgpass .htpasswd .my.cnf my.cnf passwd shadow;kubeconfig *.kubeconfig *.tfstate terraform.tfvars *.tfvars *.jwt;credentials* creds* secret* secrets.json token token.json token.txt *.token *_token auth.json;settings.py local_settings.py settings.xml wp-config.php web.config wrangler.toml .dev.vars。
  • 含义模糊的子串(*secret* *password* *passwd* *credential* *api_key* *apikey* *token* *auth_token*):仅当文件名以配置类型后缀结尾时才会被拦截——.json .yaml .yml .toml .ini .cfg .conf .config .properties .xml .txt .env .envrc .cnf .sh .ps1 .bat .cmd .sql .php。因此,prod_credentials.json 会被拦截,而 src/password_policy.py、src/tokenizer.py 和 docs/secrets.md 不会。

exclude 模式遵循相同规则:glob 模式匹配单个名称段(目录名,或路径的第一段)。exclude=["config"] 会排除任意深度下的 config/ 目录,但无法排除某个特定文件——排除 config/database.yaml 意味着排除整个 config/ 目录。包含 / 的模式会被直接拒绝,而不是静默忽略。

**这并不构成隐私保护或合规保证。**请自行管理存储的访问权限;不要将未排除的凭证、令牌、私钥或个人数据留在扫描路径中。

时间与粒度
  • 静默期最长约为 60 秒。在文件持续变化期间,中间记录会标记为 partial: true。
  • 如果进程突然退出,变更末尾部分只会出现在 tc_resume 的尚未记录路径中,直到下一次 tc_save / tc_capture。
漂移层仅检查 mtime+size

tc_capture 和后台线程通过 mtime+size 检测变化。如果内容发生变化,但 mtime 和长度未变(cp -p、rsync -t、tar -x 会保留 mtime),则检测不到变化。

tc_save 默认会对内容进行哈希处理,不受影响——但 TC_SHA_REUSE=on 时例外,此时任务层也会采用相同的检测方式。

回滚
  • 会恢复权限位(POSIX 可执行位),但不会恢复 mtime——写回旧时间戳会让类似 make 的工具认为文件没有变化。注意:内容相同、仅权限发生变化时不会触发重写,因此这种情况下权限位会保持原样。
  • 无法恢复的文件会被跳过(敏感文件、超过 100 MB 且未存储内容的文件、载荷丢失的文件),其余文件继续处理;被跳过的路径会出现在 plan.unrestorable 中。预览和执行使用相同的列表,因此单个 .env 不会导致整个回滚失败。
  • 二进制文件会恢复,但不会生成逐行差异。并发编辑不会合并。
大文件

大小不超过 100 MB 的文件会按原样存储在 payload/ 中,并根据内容去重。超过 100 MB 的文件只保留流式哈希和元数据——不保留内容,因此无法回滚内容。

存储不会自行缩小

旧的漂移内容会一直保留,直到你调用 tc_compress。其默认设置是保留 7 天,因此在较小的工作区中,默认调用通常会报告 converted: 0——响应中的 keep_seconds / minimum / maximum / eligible / bytes_freed 会说明原因。传入更小的 keep_seconds 才能真正回收空间。步骤基线和 recovered 层永远不会被触及。

使用 TC_SHA_REUSE=on 的风险(以及它为何默认关闭)

默认情况下,任务层会在每次保存时对内容进行哈希——它不信任 mtime——因此每次保存都会读取工作区中的每个非敏感文件(不保留内容,因此内存用量不会随工作区大小增长)。

使用 TC_SHA_REUSE=on 时,mtime+大小未变化的文件不会重新读取,而是复用已索引的 sha。如果 mtime 曾被还原(os.utime)、文件系统的 mtime 精度较低(FAT、某些网络驱动器),或工具会保留 mtime(cp -p、rsync -t、tar -x、某些生成器),内容编辑就会完全无法检测到:不会读取任何内容,也不会存储任何新内容,过期的 sha 会写入步骤记录,而回滚会悄无声息地返回旧内容。默认设置下不会出现这种情况。

在这两种模式下,tc_resume 和 tc_show 都不会读取文件内容(只检查 mtime+大小),因此也可能漏掉保留 mtime 的编辑。

参数和状态限制
  • tc_restore 必须且只能接收 index 或 drift_id 之一;apply=true 不会修改已关闭的任务。
  • 将另一个任务的 task_id 传给 tc_save 时,会先切换当前活动任务(原任务将变为挂起状态);active_task_changed: true 会告知你发生了切换。使用 tc_switch 可切回原任务。
  • 如果存在基线且检测到未记录的更改,tc_save 会在写入步骤前将这些更改附加到本次保存的清单中。
  • tc_export 要求目标的父目录已存在;tc_import 会验证任务 ID 和工作区路径,拒绝重复任务、.. 路径遍历和符号链接目标,并在失败时回滚已写入的文件。
  • store 不能等于工作区根目录;如果自定义的 store 位于工作区内,则会自动排除在扫描之外。
git

在 git 仓库中,每次 tc_save 都会额外耗费几百毫秒(用于创建引用的 git 子进程)。可通过 TC_GIT=off 或 TC_GIT_VERIFY=off 避免。

存储布局

<workspace>/.checkpoints/
├── current.json          active-task pointer, keyed by workspace root (one store can serve many)
├── state.lock            concurrency lock
├── server.log            logs (never stdout; stdout carries MCP frames only)
├── payload/<sha2>/       content-addressed file copies, deduped by sha across tasks
└── tasks/<task_id>/
    ├── state.json
    ├── index.json            baseline index: mtime/size/sha256 per file
    ├── steps/sNNNN.json      task layer: one record per step
    ├── drifts/dNNNN.json     drift layer: file changes
    └── manifest/mNNNN.json   consistency manifests (incremental chain, full anchor every 20)

活动指针和基线索引按工作区分别管理:多个工作区共用同一个 store 时,彼此的数据不会泄漏。

仓库布局

.
├── README.md        this file
├── SKILL.md         the agent-facing usage contract (part of the feature, ships with the package)
├── LICENSE          MIT
├── pyproject.toml   packaging; sources stay in scripts/, not a package dir
├── MANIFEST.in      what goes into the sdist
├── server.json      publish metadata for the official MCP Registry
├── glama.json       ownership marker for the Glama directory
├── scripts/
│   ├── tc.py        core
│   └── tc_mcp.py    stdio MCP adapter + the human-facing command-line flags
├── tools/
│   └── drill.py     end-to-end probe against a real workspace (not in the test suite, run by hand)
├── npm/             the npm launcher package (a shell; the server itself is not here)
├── tests/
│   ├── test_tc.py                       full acceptance suite (rollback safety, concurrency lock, git refs, return fields, packaging contract)
│   ├── test_tc_regressions.py           targeted regressions for fixed defects
│   └── test_packaging_consistency.py    the three version numbers / registry metadata / README ownership marker
└── .github/workflows/ci.yml             CI: run the tests, build, validate server.json and the wheel

构建产物不会放入仓库。有两个发布渠道:PyPI 上的 task-checkpoint-mcp(pipx install task-checkpoint-mcp)是主要渠道,wheel 和 sdist 也会附在 GitHub Releases 中。

参与贡献

欢迎提交问题和 PR。修改代码前请先运行测试(参见上文“验证”——这里有 100 多个用例,耗时 2.5–6 分钟)。

  • tests/test_tc.py 是完整的验收测试套件:回滚安全性、并发锁、git 引用可达性、每个分支的返回字段、打包约定
  • tests/test_tc_regressions.py 收录了针对已修复缺陷的回归测试——修复 bug 时,请在这里添加用例,而不只是修改代码

有一项硬性要求:只能使用标准库。不得添加新依赖,包括测试依赖(测试使用 unittest,而不是 pytest)。

许可证

MIT——参见 LICENSE。

供修改此代码的人员参考的实现说明(.git/index 字节计数、引用冲突行为、锁定策略、清单锚定)见上文的中文部分。

评论

支持 Markdown

第一次接触 MCP?

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

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