Repository navigation
v2.1.0
MCP:AI 写入护栏与回滚
MCP 从只读迈出第一步:现在可以写入你的笔记,但每一次写入都留痕、可预览、可回滚。
之前 MCP 只能读,是为了先把只读能力做扎实。现在只读已经稳定,该补上护栏了——
否则「AI 把笔记写坏了且无法回滚」这个风险会直接暴露给用户,而竞品
(SoloMD / Markra)都已经上了各自的护栏。
四个写入工具
| 工具 | 作用 | 写盘 |
|---|---|---|
preview_write |
给定路径与新内容,返回 unified diff | 否 |
write_note |
快照 → 写入 → 返回 diff 与快照 ID | 是 |
list_writes |
列出本库可回滚的写入 | 否 |
rollback_write |
回滚到指定快照 | 是 |
写入的硬约束
- 写入前强制快照:原内容存进
<库根>/.flymd/ai-guard/。
快照写不成功就中止写入——宁可写不进去,也不能留下没有回滚路径的改动 - 回滚可以再回滚:回滚本身也生成快照,来回切不会丢历史
- 单次写入上限 1 MB,一次只改一个文件
- 不得写入被排除的目录(排除目录是你划定的边界)
- 目标路径必须落在库根内,绝对路径、
..、指向库外的符号链接一律拒绝
护栏内核只有一份实现
快照存储与 diff 实现在 mcp-server 的 lib 目标里,桌面应用以路径依赖引用同一份代码——
不是两边各写一遍再对齐约定。这样:
- 快照格式的一致性由构造保证
- 应用内的 AI 写入与 MCP 客户端的写入落在同一个快照目录,互相可回滚
- 不给桌面应用新增任何依赖(lib 只依赖 serde / serde_json,两者本就有)
应用内:插件改写文档自动留快照
- 宿主层统一拦截插件的三个文档写入口(
setEditorValue/replaceRange/insertAtCursor),
一处覆盖所有插件 - AI 助手新增右键菜单项 「回滚上一次 AI 写入」
- 在应用里能回滚 MCP 的写入,在 MCP 里也能回滚应用的写入
安全加固
- 库根不可由插件指定:
ai_guard_*命令对插件禁用,改由宿主提供库根可信的入口。
否则恶意插件可传libraryRoot="/"让回滚写到库外任意路径 - WebDAV 同步默认排除
.flymd/ai-guard/:快照存的是写入前的旧内容,
同步出去等于泄露历史版本
修复
- CI:推主干此前不触发任何 CI(workflow 的 on.push 只配了 tags),
补上branches: [main] - CI:Tauri 侧 Rust 代码此前只在三平台 build job 里才编译(30 分钟后才知道编不过),
check 门禁新增cargo check --manifest-path src-tauri/Cargo.toml - CI:check job 补装 GTK/WebKit 开发包,让 cargo check 能跑起来
- 单测:
themeBgUnify放宽文件级超时——它的首个用例要 1.5s,贴着 vitest 默认 5s 上限,
高负载下随机失败挡住发版门禁 - 主题:专注模式侧栏背景的 50ms 延迟回调在环境销毁后触发会抛未捕获的
ReferenceError: window is not defined——单测断言全过却因此以退出码 1 失败
文档
- AI 写入护栏设计文档
- MCP 服务器使用指南 第 8 节
资产
| 平台 | 文件 |
|---|---|
| Windows x64 | flymd_2.1.0_x64-setup.exe、flymd_portable_x64.zip |
| macOS (Intel + Apple Silicon) | flymd_2.1.0_universal.dmg、flymd_universal.app.zip |
| Linux x64 | flymd_2.1.0_amd64.deb、flymd_2.1.0_amd64.AppImage |
| MCP 服务器(独立二进制) | flymd-mcp-windows-x64.exe、flymd-mcp-macos-universal、flymd-mcp-linux-x64 |
MCP 服务器是独立进程,不依赖桌面应用运行。
用 Claude Code 时:claude mcp add flymd -- /绝对路径/flymd-mcp