Typecho MCP Workbench 开发手记 03:把博客操作变成 AI Agent 能安全调用的工具

上一篇写到 SSH zero-touch:本地工作台通过 SSH 自动找到 Docker 里的 Typecho,部署一个极轻的 PHP agent,然后用 stdin/stdout 调用它。

这篇自然接上:远端 agent 只是执行器,真正的控制面在本地 MCP 和 local-ops。

如果说第二篇解决的是“怎么安全地够到远端”,那第三篇解决的是“够到之后,AI 到底被允许怎样操作博客”。

Typecho MCP Workbench 工具控制面

为什么 MCP 是主入口

最直接的做法,是把 SSH、数据库路径、Typecho API 或某个管理接口直接交给 AI。这样当然也能完成任务,甚至短期看起来更快。

但这条路的问题也很明显:它把能力暴露得太原始了。

AI 如果直接拿 SSH,它看到的是一台机器;如果直接拿数据库,它看到的是一堆表;如果直接拿远端 API,它看到的是一组远程写入口。这些接口都太接近底层状态,缺少“写作流程”本身应该有的约束。

我想要的是另一种边界:

AI Agent 只调用本地 MCP 工具
本地 MCP 工具表达编辑意图
local-ops 负责策略、快照、审计和缓存
远端 PHP agent 只执行很窄的原子操作

这样 AI 拿到的不是“服务器权限”,而是一组有名字、有语义、有确认策略、有审计记录的工具。它可以写文章,但不能绕开发布确认;它可以预览修改,但不能跳过快照;它可以请求回滚,但必须明确确认。

这就是 MCP 在这个项目里的定位:不是“多一种 API 封装”,而是给 AI Agent 设计的本地安全控制面。

工具名要贴近编辑流程

我不希望 MCP 工具长得像数据库函数,比如:

contents.insert
contents.update_status
metas.attach
relationships.delete

这些名字对机器很友好,但对真实工作流不友好。写博客不是在操作 contents 表,而是在经历一套编辑动作:

  • 先看站点和文章列表。
  • 打开一篇文章。
  • 创建草稿。
  • 预览这次修改会改变什么。
  • 保存前生成快照。
  • 发布前做检查。
  • 明确确认后发布。
  • 必要时从快照回滚。

所以现在的 MCP 工具更接近这个节奏:

typecho.posts.list
typecho.posts.get
typecho.posts.create_draft
typecho.posts.preview_update
typecho.posts.update
typecho.posts.prepare_publish
typecho.posts.publish
typecho.posts.rollback

媒体也一样,不是“写附件表”,而是:

typecho.media.list
typecho.media.upload
typecho.media.register_external_url

而围绕安全、诊断和可观测性的工具,则是另一组辅助控制面:

typecho.audit.list
typecho.cache.status
typecho.cache.clear
typecho.snapshots.list
typecho.snapshots.get

这些工具名的目标,是让 AI 在调用之前就能理解动作的风险。preview_update 听起来就是预览;prepare_publish 听起来就是发布前检查;publishrollback 则天然应该被策略系统盯住。

工具不是数据库函数,而是可审计工作流

一个好的 MCP 工具,不应该只是把远端方法暴露出来。它应该把一次操作拆进工作流。

比如更新文章,看起来只是改标题和正文,但实际链路应该是:

posts.preview_update
  -> 对比当前远端文章和目标修改

posts.update
  -> 强制读取远端最新状态
  -> 创建本地 snapshot
  -> 调用远端 agent 写入
  -> 写 audit log
  -> 失效相关缓存

发布文章也是:

posts.prepare_publish
  -> 检查标题、slug、正文、分类、标签、图片链接
  -> 给出 blockers / warnings

posts.publish(confirm=true)
  -> 检查 Operation Policy
  -> 创建 before_publish snapshot
  -> 调用远端 agent 发布
  -> 写 audit log

这就是“工具层”和“远端执行器”的差别。

远端 PHP agent 可以有 posts.update 这种原子能力;但本地 MCP 暴露给 AI 的,不应该只是一个裸写入口。它必须把快照、策略、审计、缓存失效这些事情纳入默认路径。

Policy、Cache、Snapshot Preview 工作台截图

发布和回滚必须有确认策略

发布和回滚是两个特别值得单独拎出来的动作。

发布会改变公开世界。草稿变成公开文章后,RSS、搜索引擎、订阅器、读者都会看到。它不是一个“普通状态字段更新”。

回滚则更微妙。它听起来像安全动作,但其实也是写操作:它会把当前远端文章恢复到某个历史快照。如果用户没有看清楚“当前版本”和“目标快照”之间的差异,回滚本身也可能造成内容丢失。

所以这个项目里,发布和回滚都不应该被 AI 静默执行。它们必须经过 Operation Policy,要求明确确认:

publish  -> confirm=true
rollback -> confirm=true

这不是形式主义。它让工具层可以区分“AI 准备好了一个发布建议”和“用户真的批准了发布”。未来评论删除、插件启停、主题切换、批量修改分类,也应该纳入同一套风险等级和确认系统。

Diff、Snapshot、Policy、Audit、Debug 合在一起才是边界

单独看这些能力,每一个都不复杂:

  • Diff Preview:保存前看看改了什么。
  • Snapshot Preview:回滚前看看要恢复什么。
  • Operation Policy:对高风险动作做确认和限制。
  • Audit Log:记录谁在什么时候做了什么。
  • Debug Bundle:出问题时导出诊断、日志、审计、缓存和环境摘要。

但它们合在一起,才构成真正的安全边界。

Diff Preview 解决“我将要改什么”。

Snapshot Preview 解决“我将要恢复什么”。

Operation Policy 解决“这个动作现在能不能做”。

Audit Log 解决“事后如何追踪”。

Debug Bundle 解决“出问题后如何把上下文交给人或 AI 继续排查”。

这也是我越来越明确的一点:AI 工具的安全感,不是靠一句“请谨慎操作”得到的,而是靠每一次危险动作都有可见前置、明确确认、可回滚依据和可追踪记录。

本地控制面也服务人类界面

虽然这一篇讲 MCP,但它并不只服务 AI。

最终的人类工作台会是一个独立桌面软件,应该更像 Obsidian 或 Typora,而不是一个临时 localhost 页面。但无论界面是什么形态,它都应该复用同一套本地控制面。

人类点击“保存”,底层也应该走 preview_updateupdate

人类点击“发布”,底层也应该走 prepare_publishpublish(confirm=true)

人类打开“诊断”,底层也应该拿 Debug Bundle。

这样 Web 原型、未来桌面端、CLI、MCP Agent 都不会各自发明一套博客写入逻辑。它们只是同一套 local-ops 的不同入口。

Typecho MCP Workbench 架构图

这一篇之后,项目更像一个工作台了

到第三篇,项目的轮廓已经比较清楚:

第一篇讲的是:为什么要做一个 local-first Typecho MCP Workbench。

第二篇讲的是:如何通过 SSH zero-touch 把远程 Typecho 接成本地可操作目标。

第三篇讲的是:为什么本地 MCP 工具层才是 AI 操作博客的主入口。

现在它不只是“能远程写文章”,而是开始有了工作台应有的秩序:先预览,再保存;先检查,再发布;先快照,再回滚;先记录,再排查。

下一篇我想写本地人类工作台:为什么当前 localhost Web UI 只是原型,最终目标会是一个独立桌面软件;以及编辑器、媒体、预览、发布报告、回滚面板和 AI 协作入口应该怎样组合在一个日常可用的写作空间里。