关于 claude-checkpoint-mcp
为 Claude Code 等客户端保存本地会话检查点,便于在崩溃、清空上下文或达到上下文限制后恢复工作。每个会话单独存档,并通过文件哈希标记检查点之后发生变化的文件。
主要功能
- 01保存会话目标、进度与决策
- 02将检查点整理为恢复摘要
- 03列出项目中的会话检查点
- 04按会话分别保存文件
- 05检测检查点后的文件变化
- 06数据仅保存在本机
适用场景
- 01终端崩溃后恢复编码任务
- 02清空上下文后接续未完成工作
- 03查看检查点后哪些文件发生变化
MCP 相关
提供保存、加载和列出会话检查点的 MCP 工具,供 Claude Code 及其他 MCP 客户端使用。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y session-checkpoint-mcpCHECKPOINT_PROJECT_ROOTOptional. Absolute path of the default project to checkpoint, used when the client has no current project (e.g. Claude Desktop). A projectRoot argument on a tool call takes precedence.CLAUDE_CODE_SESSION_IDSet automatically by Claude Code; do not set it yourself. Selects the per-session checkpoint file (.claude-checkpoints/<session-id>.json). Without it the server mints a session id per conversation, or uses the shared .claude-checkpoint file with CHECKPOINT_SESSION_IDS=legacy.CHECKPOINT_SESSION_IDSOptional. Unset or mint: clients without a session id get their own checkpoint per conversation (the server mints an id on the first save and the agent passes it back). Set to legacy to have them share one .claude-checkpoint file, as before 1.0. No effect on Claude Code.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
3收录的工具列表 · 更新于 2 天前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| goal | string | 是 | 用一到两句话说明会话的主要目标。 |
| mode | enum | 否 | replace:覆盖检查点。merge:更新现有检查点,追加命令、决策和文件。replace | merge |
| tasks | array | 否 | 包含状态的子目标。在 merge 模式下,描述相同的任务会被更新。 |
| summary | string | 否 | 当前进展:哪些内容可用、哪些存在问题,以及正在处理的事项。 |
| decisions | array | 否 | 关键决策、约束以及应避免重复的死胡同。 |
| nextSteps | array | 否 | 供接手者按顺序执行的具体后续操作。 |
| projectRoot | string | 否 | 项目的绝对路径。默认使用客户端的工作区根目录或服务端的工作目录。 |
| modifiedFiles | array | 否 | 你修改过的文件,可附加备注。未提交的 git 更改会自动检测;在此列出文件可为其添加注释,或包含已提交的文件。 |
| recentCommands | array | 否 | 近期重要的终端命令(构建、测试、迁移),按时间从早到晚排列,并附上退出代码和简短结果说明。机密信息会自动脱敏。 |
详细介绍
session-checkpoint-mcp
在本地保存 Claude Code 会话状态,这样即使发生崩溃、执行 /clear 或达到上下文限制,Claude 也不必从头重建上下文。
session-checkpoint-mcp 是一个本地 Model Context Protocol 服务,提供三个工具:
save_session_checkpoint会将会话的工作状态写入项目中的一个小型 JSON 文件。load_session_checkpoint会将该文件转换为精简的恢复摘要。list_session_checkpoints会列出项目中的检查点,供你选择要恢复的会话。
每个 Claude Code 会话都有自己的检查点,因此多个会话可以共用一个目录,互不覆盖。
它完全在你的机器上运行,不会向任何地方发送数据。
本项目是 Tenzin 的 tenlean/claude-checkpoint-mcp 的分支。仓库保留了原名称。该服务以 session-checkpoint-mcp 发布,Claude Code 插件名为 session-checkpoint。
目录
原因:停止为相同的上下文重复付费
一段较长的 Claude Code 会话会积累大量上下文:
- 你要完成什么;
- 哪些方法已经失败;
- 哪些文件很重要;
- 哪个测试仍未通过。
以下情况可能会在任务中途清除这些内容:
- 终端崩溃、SSH 断开或笔记本电脑休眠;
- 上下文窗口用尽;
- 执行
/clear以获得一个全新的窗口。
下一次会话将从零开始。为了回到之前的状态,Claude 必须重建这些上下文:
- 重新阅读文件,弄清楚改了什么以及原因。每次读取文件都会消耗输入令牌。
- 重新探索:运行
grep、git diff、ls和测试,只为重新发现当前状态。 - 重新解释。 你要重新输入目标、约束和走不通的尝试,或者让 Claude 费力地重新发现这些死路。
每次这样的交互都会重新发送不断增长的对话作为输入,因此成本会不断叠加。
session-checkpoint-mcp 用一次简短、结构化的读取取代这番重建:
| 不使用检查点 | 使用 load_session_checkpoint | |
|---|---|---|
| 恢复目标和约束 | 你重新输入,或由 Claude 推断 | 简报中的一个章节 |
| 了解已完成和待处理的事项 | 从代码和 git 中重新推导 | 带状态的任务列表 |
| 了解哪些文件很重要 | 广泛地重新阅读 | 准确列出已修改的文件,并附上备注 |
| 了解之后发生了哪些变化 | 为确保万无一失而重新阅读所有内容 | 仅标记内容实际发生变化的文件 |
| 记住失败的尝试 | 往往会重复 | 记录在 决策与注意事项 下 |
典型会话的恢复简报约为 1.2 KB 的 Markdown,只有几百个令牌。下方示例是相同篇幅的实际输出。
最大的节省来自漂移检测。保存时,服务会为每个存在未提交更改的文件记录内容哈希。加载时,它会将这些哈希与工作树进行比较,并准确告知 Claude 检查点之后哪些文件发生了变化。简报中的其他内容都可以直接信任,因此 Claude 只需重新读取必要的文件。
工作原理
Session 1 Session 2 (after crash / /clear)
───────── ────────────────────────────────
Claude ──save_session_checkpoint──┐ ┌──load_session_checkpoint── Claude
goal, tasks, summary, │ │ compact markdown brief
next steps, decisions, ▼ │ + "changed since checkpoint"
files, commands ┌─────────────────────┐
│ <project>/ │
server adds: │ .claude-checkpoint │◀── git: branch, HEAD,
git branch/HEAD, │ .claude-checkpoint │ dirty files + hashes
dirty files + hashes, │ .prev (backup) │
redacts secrets └─────────────────────┘
- Claude 提供含义:目标、进度、决策、后续步骤,以及哪些命令发挥了作用。
- 服务提供事实:git 分支和 HEAD、每个未提交或未跟踪文件的内容哈希,以及时间戳。
- 服务说明会教 Claude 何时采取行动。 Claude 会收到指示,要求在会话开始时加载,并在达到里程碑、执行有风险的操作前,以及对话变长时保存。无需每次都提示它。
- 插件的会话启动钩子让恢复过程更加可靠。 Agent 在会话开始时很容易跳过服务指令。安装 Claude Code 插件后,SessionStart 钩子也会检查是否有检查点;如果有,就会提示 Claude 加载其中一个,并在采取行动前与你确认。
每个会话一个检查点
Claude Code 会将会话 ID(CLAUDE_CODE_SESSION_ID)传给每个 MCP 服务。服务会用它为每个会话创建独立文件 <project>/.claude-checkpoints/<session-id>.json,这样共享同一目录(/tmp,或运行 claude agents 的任何目录)的会话就不会互相覆盖或合并。
- 保存始终写入当前会话自己的文件。
- 加载会返回当前会话自己的检查点(如果有)。否则,如果存在其他检查点,则会返回一个列表(目标、上次保存时间、分支、所有任务是否已完成),并由 Claude 询问你要恢复哪一个。它绝不会替你选择,即使列表中只有一个检查点也一样。
- 恢复其他会话的检查点会加载该检查点,但保存仍会写入当前会话自己的文件。加载结果会告诉 Claude 在下次保存时将该检查点的选择器作为
resumedFrom传入。这样保存就会从恢复的检查点开始,并记录其来源。服务不会将此信息保存在内存中,因此即使服务期间重启也能正常工作。原始检查点永远不会被修改。 - 检查点会一直保留,直到你将其删除,因此之后可以恢复旧会话。
- 没有会话 ID 的客户端(例如 Claude Desktop)也会为每段对话创建一个检查点。首次保存会生成一个会话 ID,写入
.claude-checkpoints/<id>.json,并返回该 ID。Claude 会在该对话后续的每次调用中将它作为session传回。如果 Claude 丢失了该 ID(例如在压缩上下文后),它下一次保存时会创建一个新检查点;绝不会写入现有检查点。没有 ID 时加载会列出检查点供你选择,和新的 Claude Code 会话一样。在测试中(#42),Opus、Sonnet 和 Haiku 每次保存时都会传回该 ID,包括压缩上下文之后。 - 共享的
.claude-checkpoint文件是没有会话 ID 的客户端在 1.0 之前使用的文件。将CHECKPOINT_SESSION_IDS设为legacy即可保留这种行为:没有 ID 的每次保存都会写入该文件,而没有 ID 的加载会直接打开它。无论采用哪种方式,早期版本留下的.claude-checkpoint都会在列表中显示为legacy。此设置不会影响 Claude Code:它自己的会话 ID 始终优先。
任何客户端也可以显式传入 session。在 Claude Code 中,它必须与会话自己的 ID 匹配:如果不同则会报错,因为这几乎总是意味着检查点选择器被传入了错误的参数(读取检查点请使用 checkpoint,从检查点继续请使用 resumedFrom)。
MCP 服务看到的会话 ID,就是启动服务时使用的 ID:
| 你…… | 服务看到的内容 | 结果 |
|---|---|---|
启动一个新的 claude(例如崩溃后) | 一个新 ID | 显示列表,让你选择要恢复的检查点 |
运行 /clear | 与清除前相同的 ID | 直接加载清除前的检查点;之后的保存会继续更新它 |
运行 claude --resume <id> | 该 ID | 直接加载该会话的检查点 |
运行 claude --continue,或不带 ID 运行 --resume | 可能是不同的 ID | 显示列表 |
安装
要求:Node.js 20+ 和 git。Git 是可选的,但不使用它就无法检测漂移。
git clone https://github.com/daniel-munoz/claude-checkpoint-mcp.git
cd claude-checkpoint-mcp
npm install
npm run build
服务入口现在位于 dist/index.js。
从 npm 安装。 该服务也以 session-checkpoint-mcp 发布。在下方任意配置中,你都可以将 node /absolute/path/to/claude-checkpoint-mcp/dist/index.js 替换为 npx -y session-checkpoint-mcp:
claude mcp add --scope user checkpoint -- npx -y session-checkpoint-mcp
(npm 包 claude-checkpoint-mcp 是上游项目发布的 0.1.0 版本,并非此分支。)
配置
环境变量
| 变量 | 设置者 | 必需 | 默认值 | 作用 |
|---|---|---|---|---|
CHECKPOINT_PROJECT_ROOT | 你(可选) | 否 | 未设置:客户端的根目录,然后是服务端的工作目录 | 要创建检查点的默认项目的绝对路径。适用于没有当前项目的客户端,例如 Claude Desktop。工具调用中的 projectRoot 参数优先。 |
SESSION_CHECKPOINT_NUDGE | 你(可选) | 否 | 未设置:启用提示 | 设置为 off(或 0、false、no)以关闭插件的会话开始提示。由钩子读取,而非服务端。 |
CLAUDE_CODE_SESSION_ID | Claude Code,自动设置 | 否 | 未设置:每次对话都会生成一个会话 ID(参见 CHECKPOINT_SESSION_IDS) | 选择此会话的检查点文件 .claude-checkpoints/<session-id>.json。无需设置。参见每个会话一个检查点。 |
CHECKPOINT_SESSION_IDS | 你(可选) | 否 | 未设置(等同于 mint):没有会话 ID 的客户端每次对话都会获得自己的检查点 | 设置为 legacy,让没有会话 ID 的客户端共用一个 .claude-checkpoint 文件,与 1.0 之前的行为相同。其他值会回退到 mint,并显示警告。对 Claude Code 无效,因为 Claude Code 自带的会话 ID 优先。参见每个会话一个检查点。 |
Claude Code
作为插件(最简单)。 此仓库也是 Claude Code 插件市场。无需克隆或构建任何内容:
claude plugin marketplace add daniel-munoz/claude-checkpoint-mcp
claude plugin install session-checkpoint@daniel-munoz
重启 Claude Code,然后 /mcp 应会显示 plugin:session-checkpoint:session-checkpoint 已连接。
从 0.2.x 或更早版本升级? 在 0.3.0 中,插件从
claude-checkpoint-mcp更名为session-checkpoint,因为 Claude Code 保留了claude-前缀供自己的插件使用。请卸载旧插件并安装新插件:claude plugin uninstall claude-checkpoint-mcp@daniel-munoz claude plugin marketplace update daniel-munoz claude plugin install session-checkpoint@daniel-munoz完整工具名称从
mcp__plugin_claude-checkpoint-mcp_claude-checkpoint__*改为mcp__plugin_session-checkpoint_session-checkpoint__*。请更新settings.json、钩子或指令中使用旧名称的任何权限允许列表。save_session_checkpoint等短名称以及现有检查点文件不受影响。
手动设置。 如果你克隆了仓库,请为你的用户帐户注册一次服务端,这样它就能在每个项目中使用:
# Run from the claude-checkpoint-mcp directory
claude mcp add --scope user checkpoint -- node "$PWD/dist/index.js"
使用绝对路径。 用户级服务端会从你打开 Claude Code 的任意项目中启动。像
./dist/index.js这样的相对路径会相对于该项目解析,而不是此仓库。运行命令时,"$PWD/dist/index.js"会展开为绝对路径,并保存该路径。
检查是否已注册:
claude mcp list
在会话中,/mcp 应会显示 checkpoint 已连接。
项目级替代方案。 若要通过版本控制与团队共享服务端,请将其添加到项目的 .mcp.json:
{
"mcpServers": {
"checkpoint": {
"command": "node",
"args": ["/absolute/path/to/claude-checkpoint-mcp/dist/index.js"]
}
}
}
无论采用哪种方式,都请将检查点文件添加到项目的 .gitignore 或全局 gitignore 中:
.claude-checkpoint*
会话开始提示
此插件提供了一个 SessionStart 钩子(plugin/hooks/hooks.json,运行 node dist/hook.js)。会话开始、恢复、清除或压缩时都会运行此钩子。如果项目中有检查点,它会在 Claude 的上下文中添加一条提示:检查点的数量、最新检查点的保存时间,以及一条指示,要求调用 load_session_checkpoint,并在根据记录采取行动前与你确认。如果没有检查点,则不输出任何内容。它只需要 Node,而服务本身已经需要 Node,因此可在 macOS、Linux 和 Windows 上运行。
它会查找与服务相同的项目根目录(项目根目录的选择方式):如果钩子的环境中设置了 CHECKPOINT_PROJECT_ROOT,则使用该值;否则使用启动 Claude Code 时所在的目录。这不是 git 顶层目录,因此如果你在子目录中启动 Claude,它只会报告从该子目录保存的检查点,和直接调用 load_session_checkpoint 找到的内容完全一致。如果你只在 MCP 服务的配置中设置了 CHECKPOINT_PROJECT_ROOT,也要在 settings.json 的 env 中设置它,这样钩子才能读取到。
关闭提示。 在 settings.json 的 env 块中将 SESSION_CHECKPOINT_NUDGE 设为 off:
{ "env": { "SESSION_CHECKPOINT_NUDGE": "off" } }
手动设置(claude mcp add)不会安装此钩子。若要在不使用插件的情况下启用提示,请在 settings.json 中将 node /absolute/path/to/claude-checkpoint-mcp/dist/hook.js 注册为 SessionStart 命令钩子。
从 0.3.x 升级且使用了自己的提示钩子? 如果你将
checkpoint-nudge.sh钩子复制到了配置中(例如~/.claude/hooks/checkpoint-nudge.sh),现在会收到两次提示。请删除该脚本,并从settings.json中移除它的SessionStart条目。对你使用的每个配置目录都执行此操作,例如~/.claude以及任何CLAUDE_CONFIG_DIR配置文件。
子 Agent 保存保护
子 Agent 在父会话中运行,并共享其 MCP 服务,因此也共享其会话 ID。如果没有保护,调用 save_session_checkpoint 的子 Agent 会覆盖父会话的检查点;如果使用 mode: "replace",则只会留下子 Agent 自己范围较窄的子任务内容。
此插件为此提供了一个 PreToolUse 钩子(plugin/hooks/hooks.json,运行 node dist/guard.js,匹配 ^mcp__.+__save_session_checkpoint$)。如果调用来自子 Agent,钩子会拒绝保存,并告知子 Agent 应向父会话报告进度。主会话的保存操作以及所有加载和列表调用都会照常执行。对于不支持此钩子的客户端,服务说明和保存工具的描述也会说明这一点。
它通过 Claude Code 在子 Agent 内的钩子输入中添加的 agent_id 字段识别子 Agent(已在 Claude Code 2.1.322 上验证)。不会单独使用 agent_type,因为使用 --agent 启动的主会话也会有该字段。如果 Claude Code 版本不发送 agent_id,或钩子因任何原因失败,保存操作仍会继续,因此钩子不会阻止主会话。
手动设置(claude mcp add)不会安装此钩子。若要在不使用插件的情况下添加它,请在 settings.json 中将 node /absolute/path/to/claude-checkpoint-mcp/dist/guard.js 注册为带有该匹配器的 PreToolUse 命令钩子。
Claude Desktop(claude_desktop_config.json)
打开配置文件:
| OS | 路径 |
|---|---|
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
在 mcpServers 下添加服务,并使用本地构建的绝对路径:
{
"mcpServers": {
"checkpoint": {
"command": "node",
"args": ["/absolute/path/to/claude-checkpoint-mcp/dist/index.js"],
"env": {
"CHECKPOINT_PROJECT_ROOT": "/absolute/path/to/your/project"
}
}
}
}
保存文件后,重启 Claude Desktop。
Claude Desktop 没有“当前项目”的概念。使用
CHECKPOINT_PROJECT_ROOT设置默认项目,或者让 Claude 在每次调用时传入projectRoot(“为 /home/me/code/my-app 保存一个检查点”)。请参阅项目根目录解析。
其他 MCP 客户端
任何支持 stdio 传输的 MCP 客户端都可以运行此服务:
node /absolute/path/to/claude-checkpoint-mcp/dist/index.js
# or
npx -y session-checkpoint-mcp
用法
服务内置的指令会自动处理常见情况。你也可以直接询问 Claude。
保存:
- “保存当前进度。”
- “运行迁移之前保存一个检查点。”
- “更新检查点。把我们刚才完成的内容合并进去。”
恢复(在新会话中):
- “从上次停下的地方继续。”
- “加载检查点并继续。”
恢复简报示例
这是 load_session_checkpoint 的实际输出。在此场景中,保存后有一个文件原样提交了,随后一位队友编辑了 session.ts:
# Resuming: my-app (checkpoint saved 2m ago, 2026-10-08 02:23:55 UTC)
Branch `feat/github-oauth` @ b2ef1b591 (uncommitted changes)
## Goal
Add GitHub OAuth login with persistent sessions
## Tasks
- [x] OAuth callback route
- [~] Session cookie persistence
- [ ] Logout endpoint
## Where things stand
Callback exchanges the code and creates a session, but the cookie is dropped on reload. Suspect SameSite/secure flags in dev.
## Next steps
1. Set sameSite: 'lax' and secure only in production in src/auth/session.ts
2. Re-run npm test -- auth
3. Start the logout endpoint
## Decisions & gotchas
- Use iron-session, not express-session (needs edge runtime support)
- Don't mock the GitHub API in e2e tests; use the recorded fixtures in test/fixtures
## Files touched (3)
- src/auth/session.ts (M) — cookie options
- src/auth/callback.ts (M)
- src/auth/session.spec.ts (??)
## Recent commands (last 2, oldest first)
- ✓ `GITHUB_CLIENT_SECRET=«redacted» npm run dev`
- ✗ exit 1 `npm test -- auth` — 2 failing in session.spec.ts: cookie missing after reload
## Since this checkpoint
- 1 new commit(s) on HEAD
- ⚠ Changed after the checkpoint, re-read before editing: `src/auth/session.ts`
callback.ts 在保存后提交了,但其内容没有变化,因此没有被标记。只需重新读取 session.ts。
任务标记:[x] 已完成 · [~] 进行中 · [ ] 待处理 · [!] 已阻塞。
工具参考与示例
save_session_checkpoint
写入当前会话的检查点:<projectRoot>/.claude-checkpoints/<session-id>.json。没有会话 ID 的客户端会在首次保存时获得一个新 ID(或者在设置 CHECKPOINT_SESSION_IDS=legacy 时写入 <projectRoot>/.claude-checkpoint)。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
goal | string(≤ 500) | ✅ | 会话的主要目标 |
tasks | { description, status }[](≤ 30) | status:pending · in_progress · done · blocked | |
summary | string(≤ 4000) | 当前进展:哪些内容可用、哪些内容有问题,以及你正在处理什么 | |
nextSteps | string[](≤ 20) | 为后续恢复会话的人列出的有序后续操作 | |
decisions | string[](≤ 20) | 关键决策、约束条件,以及应避免的死路 | |
modifiedFiles | { path, note? }[](≤ 100) | 需要添加注释的文件,或要纳入的已提交文件。未提交的 git 更改会自动检测。项目内的绝对路径会以相对路径存储。 | |
recentCommands | { command, exitCode?, note? }[](≤ 50) | 重要命令,按时间从早到晚排列。机密信息会被脱敏。 | |
mode | "replace" | "merge" | 默认值为 replace。见下文。 | |
resumedFrom | string | 恢复此会话时所用检查点的选择器。从其他会话的检查点加载后首次保存时传入:使用 merge 保存会在其基础上构建,任一模式都会记录此值。会话拥有自己的检查点后,此参数将被忽略。格式错误的选择器会导致工具报错。对于不存在或无法读取的选择器,会发出警告,但保存仍会继续,不会使用该检查点。 | |
session | string | 此对话的会话 ID,由之前的保存操作返回。在 Claude Code 中省略此参数,因为 Claude Code 会自动提供;如果传入,则必须与其提供的 ID 匹配。此参数不能用于选择要读取的检查点:该参数是 checkpoint。 | |
projectRoot | string(绝对路径) | 覆盖根目录解析方式 |
完整保存:
{
"goal": "Add GitHub OAuth login with persistent sessions",
"tasks": [
{ "description": "OAuth callback route", "status": "done" },
{ "description": "Session cookie persistence", "status": "in_progress" },
{ "description": "Logout endpoint", "status": "pending" }
],
"summary": "Callback exchanges the code and creates a session, but the cookie is dropped on reload. Suspect SameSite/secure flags in dev.",
"nextSteps": [
"Set sameSite: 'lax' and secure only in production in src/auth/session.ts",
"Re-run npm test -- auth"
],
"decisions": ["Use iron-session, not express-session (needs edge runtime support)"],
"modifiedFiles": [{ "path": "src/auth/session.ts", "note": "cookie options" }],
"recentCommands": [
{ "command": "GITHUB_CLIENT_SECRET=gh_live_8f2a91 npm run dev", "exitCode": 0 },
{ "command": "npm test -- auth", "exitCode": 1, "note": "2 failing in session.spec.ts" }
]
}
响应(向模型显示的文本):
Checkpoint saved to /home/me/code/my-app/.claude-checkpoint (2202 bytes, replace).
3 task(s), 3 file(s), 2 command(s) on feat/github-oauth@b2ef1b591.
⚠ Redacted 1 secret-looking value(s).
使用 merge 进行增量更新:
{
"goal": "Add GitHub OAuth login with persistent sessions",
"mode": "merge",
"tasks": [
{ "description": "Session cookie persistence", "status": "done" },
{ "description": "Logout endpoint", "status": "in_progress" }
],
"recentCommands": [{ "command": "npm test -- auth", "exitCode": 0, "note": "all green" }]
}
| 字段 | replace | merge |
|---|---|---|
goal | 设置 | 设置 |
tasks | 设置 | 按 description 匹配并更新;新任务追加 |
summary、nextSteps | 设置 | 如果提供则替换,否则保留 |
decisions | 设置 | 追加(去重) |
recentCommands | 设置 | 追加;超过 50 条时删除最早的命令 |
modifiedFiles | 扫描当前 git 状态 + 提供的文件 | 扫描当前 git 状态 + 提供的文件 + 先前记录的文件 |
id、createdAt | 新建 | 保留 |
结构化输出(structuredContent):
{
"path": "/home/me/code/my-app/.claude-checkpoint",
"bytes": 2202,
"mode": "replace",
"counts": { "tasks": 3, "modifiedFiles": 3, "recentCommands": 2, "redactions": 1 },
"warnings": ["Redacted 1 secret-looking value(s)."]
}
保存使用会话 ID 时,输出还会包含 session(该 ID)和 sessionSource:env(Claude Code 的 CLAUDE_CODE_SESSION_ID)、argument(通过 session 传入)或 minted(新建,使用 CHECKPOINT_SESSION_IDS=mint)。对于 argument 和 minted,文本还会告知 Claude 在之后的每次调用中传回该 ID。如果保存写入的是 .claude-checkpoint,则会省略这两个字段。
load_session_checkpoint
只读。读取检查点、检查是否存在偏差,并返回摘要。
| 参数 | 类型 | 必填 | 描述 |
|---|---|---|---|
format | "brief" | "full" | 默认值为 brief(Markdown,见上文)。full 会返回完整的检查点 JSON 以及偏差信息。 | |
checkpoint | string | 要加载的检查点:list_session_checkpoints 返回的选择器(会话 ID 或 legacy)。省略时,加载当前会话自己的检查点。 | |
session | string | 此对话的会话 ID,由之前的保存操作返回。在 Claude Code 中省略即可,Claude Code 会提供该值;若在 Claude Code 中传入,则必须与其提供的值一致。此参数不能用于选择要读取的检查点;选择检查点请使用 checkpoint。 | |
projectRoot | string(绝对路径) | 覆盖根目录解析规则 |
示例:
{}
{ "format": "full", "projectRoot": "/home/me/code/my-app" }
结构化输出(structuredContent):
{
"found": true,
"path": "/home/me/code/my-app/.claude-checkpoint",
"fromBackup": false,
"updatedAt": "2026-10-08T02:23:55.477Z",
"drift": {
"branchChanged": false,
"currentBranch": "feat/github-oauth",
"commitsSince": 1,
"changedSince": ["src/auth/session.ts"]
},
"warnings": []
}
如果不存在检查点,工具会返回 found: false,并附上“没有可恢复内容”的消息。这不会被视为错误。
如果当前会话没有检查点,但存在其他检查点,工具会返回 found: false,并附上 candidates(与 list_session_checkpoints 返回的条目相同,按时间从新到旧排列,最多 10 条)、total、omitted,以及告知 Claude 询问你要恢复哪个检查点的 text。未知的 checkpoint 选择器会导致工具报错。
加载非当前会话自己的检查点时,会添加 resumeHint,它同时也是摘要的第一行,提示 Claude 在下次保存时传入 resumedFrom。
list_session_checkpoints
只读。列出项目的检查点,按时间从新到旧排列;无法读取的检查点会列在最后并附上警告,而不会被隐藏。
| 参数 | 类型 | 必填 | 描述 |
|---|---|---|---|
limit | integer ≥ 0 | 默认值为 10。0 表示返回全部检查点。 | |
session | string | 此对话的会话 ID,由之前的保存操作返回。在 Claude Code 中省略即可,Claude Code 会提供该值;若在 Claude Code 中传入,则必须与其提供的值一致。此参数不能用于选择要读取的检查点;选择检查点请使用 checkpoint。 | |
projectRoot | string(绝对路径) | 覆盖根目录解析规则 |
结构化输出(structuredContent,节选):
{
"path": "/home/me/scratch",
"entries": [
{
"selector": "8ce2c093-d512-42c2-a4d8-aa98280b55df",
"goal": "Investigate the flaky upload test",
"updatedAt": "2026-10-19T21:40:23.000Z",
"age": "2h ago",
"branch": null,
"allTasksDone": false,
"isCurrentSession": false,
"fromBackup": false
},
{ "selector": "legacy", "goal": "Quick CSV analysis", "...": "..." }
],
"total": 2,
"omitted": 0,
"warnings": [],
"text": "2 checkpoint(s) in /home/me/scratch, newest first: …"
}
项目根目录的选择方式
projectRoot参数CHECKPOINT_PROJECT_ROOT环境变量- 客户端的第一个
file://根目录(如果客户端支持 MCP 根目录) - 服务进程的工作目录
路径必须是绝对路径,且必须指向现有目录。符号链接会被解析。检查点始终写入该根目录下的固定位置:<root>/.claude-checkpoints/<session-id>.json,或者在设置 CHECKPOINT_SESSION_IDS=legacy 且没有会话 ID 时写入 <root>/.claude-checkpoint。
检查点文件
<project>/
├── .claude-checkpoint # legacy single checkpoint (0.x clients without a session id, CHECKPOINT_SESSION_IDS=legacy, or 0.1.x)
├── .claude-checkpoint.prev # its backup
└── .claude-checkpoints/ # one checkpoint per session or minted conversation (directory mode 0700)
├── <session-id>.json
└── <session-id>.json.prev # each with its own backup
所有文件都会以原子方式写入,权限模式为 0600。.claude-checkpoint* gitignore 模式可匹配所有这些文件。
每个文件都是纯文本、带版本号的 JSON,因此便于阅读、比较差异或手动编辑。真实示例:
{
"version": 1,
"id": "ee5507c0-855e-44a5-85c1-d97b767537c9",
"createdAt": "2026-10-08T02:23:55.477Z",
"updatedAt": "2026-10-08T02:23:55.477Z",
"generator": { "name": "session-checkpoint-mcp", "version": "1.0.0" },
"project": { "name": "my-app" },
"git": {
"branch": "feat/github-oauth",
"head": "b2ef1b5919ee5d456ea146c9362a7abc92b1e556",
"dirty": true
},
"goal": {
"primary": "Add GitHub OAuth login with persistent sessions",
"tasks": [
{ "description": "OAuth callback route", "status": "done" },
{ "description": "Session cookie persistence", "status": "in_progress" },
{ "description": "Logout endpoint", "status": "pending" }
]
},
"summary": "Callback exchanges the code and creates a session, but the cookie is dropped on reload. Suspect SameSite/secure flags in dev.",
"nextSteps": [
"Set sameSite: 'lax' and secure only in production in src/auth/session.ts",
"Re-run npm test -- auth",
"Start the logout endpoint"
],
"decisions": [
"Use iron-session, not express-session (needs edge runtime support)",
"Don't mock the GitHub API in e2e tests; use the recorded fixtures in test/fixtures"
],
"modifiedFiles": [
{ "path": "src/auth/session.ts", "status": "M", "source": "git", "note": "cookie options", "hash": "9ec893ef673dac860e7e2b6fcaad602983eeb0b1" },
{ "path": "src/auth/callback.ts", "status": "M", "source": "git", "hash": "f3ecc849c3875d4f11bb42ae0e5ab6c71931d7f1" },
{ "path": "src/auth/session.spec.ts", "status": "??", "source": "git", "hash": "9daeafb9864cf43055ae93beb0afd6c7d144bfa4" }
],
"recentCommands": [
{ "command": "GITHUB_CLIENT_SECRET=«redacted» npm run dev", "exitCode": 0, "at": "2026-10-08T02:23:55.477Z" },
{ "command": "npm test -- auth", "exitCode": 1, "note": "2 failing in session.spec.ts: cookie missing after reload", "at": "2026-10-08T02:23:55.477Z" }
],
"meta": { "redactions": 1, "truncated": false }
}
| 字段 | 说明 |
|---|---|
version | 架构版本。未知版本会被拒绝;未来版本会在加载时迁移旧文件。 |
id / createdAt | 在 merge 保存期间保持不变;使用 replace 时生成新值 |
sessionId | 拥有该检查点的 Claude Code 会话(旧版文件中不存在) |
resumedFrom | 此检查点启动时所基于的检查点选择器(如果有);后续保存时会保留 |
git | 不在 git 仓库中或仓库尚无首次提交时为 null |
modifiedFiles[].status | Git porcelain 状态码(M、A、D、R、??),或仅由 Claude 报告的文件对应的 M |
modifiedFiles[].source | git(检测所得)或 agent(由 Claude 报告,或从之前的合并中沿用) |
modifiedFiles[].hash | 保存时工作树内容的 Git blob 哈希;用于检测偏差 |
meta.truncated | 如果为 true,表示为满足列表或大小限制而丢弃了部分内容 |
路径始终相对于项目根目录。文件不会存储绝对路径。
兼容性
从 1.0.0 起,本项目遵循语义化版本。每个版本的变更记录见 CHANGELOG。
涵盖范围:1.x 版本绝不会破坏以下内容。
-
工具。 包括
save_session_checkpoint、load_session_checkpoint和list_session_checkpoints,以及:- 它们的输入字段及必填项
- 它们的输出字段(
structuredContent) - 它们的四个注解提示
test/contract.test.ts锁定了以上所有内容,确保客户端从tools/list收到的内容保持不变。 -
检查点文件。 也就是
version: 1JSON 格式以及文件存放位置:.claude-checkpoints/<session-id>.json、.prev备份,以及旧版.claude-checkpoint。1.x 版本会读取此前任何 1.x 版本写入的文件。 -
旧版文件。 在整个 1.x 系列中,
.claude-checkpoint始终可读,并会标记为legacy。只有设置CHECKPOINT_SESSION_IDS=legacy时才会写入该文件。 -
环境变量。 包括
CLAUDE_CODE_SESSION_ID、CHECKPOINT_PROJECT_ROOT、CHECKPOINT_SESSION_IDS和SESSION_CHECKPOINT_NUDGE,以及它们接受的值。 -
项目根目录的选择方式(详情)。
-
插件。 包括其名称(
session-checkpoint)、两个钩子(会话启动提示和子 Agent 保存保护),以及手动设置中注册的dist/脚本路径。
属于破坏性变更,只能在主版本中进行:
- 移除或重命名工具、输入或输出字段,或环境变量
- 将输入设为必填,或缩小其可接受值范围
- 更改现有字段的含义
- 写入此前 1.x 版本无法读取的检查点文件
次版本中允许的变更: 新增工具、新增可选输入,以及新增输出字段。也允许使用新的检查点格式版本,只要旧格式的文件仍可加载。
不在涵盖范围内:以下内容可在任何版本中变更。
- 恢复摘要、服务端说明、工具描述,以及消息和警告的措辞
- 时间戳相同的列表条目顺序
src/下的任何内容。npm 包是一个可运行的服务端,而不是供导入的库。
安全与隐私
-
仅限本地。 不会发起网络请求。服务端会读取 git 元数据和项目的检查点文件,并且只写入当前会话的检查点。
-
机密信息脱敏。 在任何内容写入磁盘前,以下内容都会在命令、备注、摘要、任务和决策中替换为
«redacted»:*_KEY=、*_TOKEN=、*_SECRET=、*PASSWORD=赋值,包括Header: value和 JSON 格式Authorization: Bearer …请求头- URL 中的凭据(
postgres://user:pass@…) --password/--token/--api-key/--secret标记- 单独出现的
sk-…、ghp_…、github_pat_…、AKIA…和xox?-…令牌
脱敏是一种安全措施,并非万无一失,因此请勿将该文件纳入版本控制。
-
仅所有者可读写入,且崩溃安全。 文件以模式
0600写入。每次保存都会写入临时文件、执行 fsync,然后将其重命名到目标位置,因此即使保存过程中崩溃,也不会留下写入一半的检查点。 -
自动备份。 上一个有效检查点会保留为
.claude-checkpoint.prev。如果主文件损坏,加载时会回退到备份并说明情况。损坏的文件绝不会覆盖有效备份。 -
大小受限。 每个字段都有长度上限,文件大小上限为 64 KB(最早的命令会优先丢弃),因此检查点不会膨胀成令牌黑洞。
-
不使用 shell。 Git 通过
execFile运行,超时时间为 3 秒,并设置GIT_OPTIONAL_LOCKS=0,因此不会与您自己的 git 命令争用资源。 -
不会修改您的配置。 如果检查点未被 git 忽略,保存响应会发出警告。它绝不会代您修改
.gitignore。 -
支持并行工具调用。 工具调用会在服务端内部串行执行,因此并发的
merge保存不会丢失更新。
故障排除
| 症状 | 修复方法 |
|---|---|
/mcp 中没有显示 checkpoint | 运行 claude mcp list,并检查路径是否为绝对路径,以及 dist/index.js 是否存在(npm run build)。 |
| 检查点写入了错误的目录 | 服务回退到了工作目录。调用时传入 projectRoot,或设置 CHECKPOINT_PROJECT_ROOT 环境变量。 |
projectRoot must be an absolute path | 使用完整路径,例如 /home/me/code/app,而不是 ./app。 |
| 摘要显示“Saved commit … is no longer reachable” | 保存后,分支被变基或重置了。无法根据历史记录计算偏移,因此应将标记的文件视为需要重新读取。 |
| 警告:“not git-ignored” | 将 .claude-checkpoint* 添加到 .gitignore。 |
| 会话开始时,Claude 被重复告知有检查点 | 你仍在使用自己的提示钩子和插件自带的钩子。移除自己的钩子(参见会话开始提示)。 |
| 会话开始时没有提示 | 该钩子仅随插件提供,且仅当会话的起始目录(或 CHECKPOINT_PROJECT_ROOT)中存在检查点时才会触发。检查 SESSION_CHECKPOINT_NUDGE 是否为 off,并运行 /hooks 确认钩子已注册。 |
session: "…" names a different one | 检查点选择器被传入了 session。使用 load_session_checkpoint 上的 checkpoint 读取另一个检查点,然后在下次保存时使用 resumedFrom,以从该检查点继续。 |
| 没有会话 ID 的客户端生成了许多小检查点 | Claude 没有传回 session ID,因此每次首次保存都会新建一个检查点。提醒它传回该 ID,或设置 CHECKPOINT_SESSION_IDS=legacy,改为共用一个 .claude-checkpoint 文件。 |
| 子 Agent 保存时被拒绝,并提示“Subagents must not save session checkpoints” | 这是预期行为:子 Agent 保存防护阻止它覆盖父级的检查点。让子 Agent 在最终回答中汇报进度,并从主会话进行保存。 |
| 没有“Since this checkpoint”部分 | 项目不是 git 仓库,或保存时还没有任何提交。 |
服务日志会输出到 stderr。Stdout 专用于 MCP 协议。
开发
npm run typecheck # strict TypeScript, src + tests
npm test # unit tests + in-memory MCP end-to-end tests (vitest)
npm run build # compile dist/index.js (server), dist/hook.js (nudge) and dist/guard.js (guard), and copy them to plugin/dist
npm run inspect # open the MCP Inspector against dist/index.js
plugin/dist/ 已提交,因为插件安装时会直接运行其中的内容。其 package.json("type": "module")会将打包文件标记为 ES 模块。已安装的插件位于此仓库之外,因此如果没有该文件,Node 会回退到其上方最近的无关 package.json:每次运行都会发出警告,而不支持模块语法检测的 Node 版本(例如 20.10)则完全无法加载这些打包文件。
src/
├── index.ts # entry point: stdio transport, signals, stderr logging
├── hook.ts # entry point of the plugin's SessionStart hook (dist/hook.js)
├── guard-hook.ts # entry point of the plugin's PreToolUse subagent guard (dist/guard.js)
├── guard.ts # subagent guard: denies saves from subagents
├── hookInput.ts # reads hook input from stdin (shared by both hooks)
├── nudge.ts # session-start nudge: finds checkpoint files without reading them
├── server.ts # McpServer construction + server instructions
├── tools.ts # save/load/list tool schemas and handlers
├── session.ts # session id validation
├── listing.ts # checkpoint listing for the "which one?" prompt
├── schema.ts # zod schema for the checkpoint file (v1) + migrations
├── paths.ts # project root resolution and checkpoint file names (no dependencies, shared with the hook)
├── store.ts # checkpoint paths, atomic I/O, backup/fallback
├── git.ts # branch/HEAD/status snapshot, blob hashing, drift detection
├── redact.ts # secret scrubbing
└── render.ts # checkpoint → markdown resume brief
发布
- 在分支上准备发布,并提交拉取请求。
- 更新
package.json、package-lock.json、server.json(两处)、plugin/.claude-plugin/plugin.json和.claude-plugin/marketplace.json中的版本号。如果这些文件中的版本号不一致,test/metadata.test.ts会报错。 - 在
CHANGELOG.md中,将变更移至新的版本标题下。 - 运行
npm ci和npm run build。将版本更新与重新构建的plugin/dist一起提交。
- 更新
- 合并拉取请求。
- 在
main上为合并提交打上标签vX.Y.Z。 可以创建包含新标签的 GitHub 发布(Releases → Draft a new release,发布说明取自 CHANGELOG 条目),也可以推送该标签。 - 检查 Publish 工作流。 工作流会在新标签上启动;如果标签与
package.json中的版本不匹配,则拒绝发布;并会将session-checkpoint-mcp发布到 npm,将server.json作为io.github.daniel-munoz/claude-checkpoint-mcp发布到 MCP 注册表。
如果发布过程中途失败,不要重新运行失败的作业。改为从 Actions → Publish → Run workflow 使用该标签再次运行工作流。已成功的步骤会跳过。
基于官方 @modelcontextprotocol/sdk 和 zod 构建。
许可证
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。