写博客时,我经常在编辑器、终端和 Typecho 后台之间切换:整理资料、写 Markdown、复制到后台、调整分类,再检查发布结果。既然 agent 已经能够协助写作,能不能让它直接操作博客,把这套流程连起来?
为此,我做了 AgentBridge:一个直接运行在 Typecho 中的 MCP 插件。它让 Codex 等支持 Streamable HTTP 和 Bearer Token 的 MCP 客户端查询、创建、修改、发布和删除博客内容,不需要额外部署 Node.js 或 Python 服务。
项目现在以 GPL-2.0-or-later 开源,首个公开版本为 v1.0.2。
它能做什么
AgentBridge 提供 20 个工具,客户端实际看到的工具会根据绑定用户和权限开关过滤。
| 内容 | 支持的操作 |
|---|---|
| 文章 | 查询、读取、创建草稿、局部修改、发布、放弃修订、永久删除 |
| 独立页面 | 查询、读取、创建草稿、修改、发布、放弃修订、永久删除 |
| 分类和标签 | 查询分类、查询标签、创建分类 |
| 图片 | 上传 JPEG、PNG、GIF、WebP 小图片,可关联文章或页面 |
| 操作结果 | 根据 request_id 查询写操作状态,处理重复请求和超时 |
它的分工很明确:agent 负责写作、整理和检查,插件负责校验参数、执行权限检查,并调用 Typecho 原生内容组件。
目前没有评论管理、分类删除、大文件上传和自动定时发布功能;也不允许通过工具任意修改作者、可见性、模板或自定义字段。
为什么直接做成 MCP
连接链路是:
Codex / MCP 客户端
↓ HTTPS + Bearer Token
Typecho 中的 AgentBridge
↓ 权限、版本与参数检查
Typecho 原生内容组件和插件钩子对于已经运行 PHP 的 Typecho 站点,安装插件就能提供远程工具入口,维护起来比较直接。客户端通过 MCP 发现工具和参数,不必再为一套自定义 REST API 单独写适配器。
当前实现使用无状态 Streamable HTTP,返回 JSON;支持的协议版本为 2025-06-18 和 2025-03-26。第一版使用静态 Token,没有 OAuth 登录、旧版 HTTP+SSE 或 stdio 服务端。
第一步:检查环境并安装
需要以下环境:
- Typecho:已实测 1.2.1、1.3.0。
- PHP:8.1 或更高,并启用
mbstring、fileinfo和对应数据库驱动。 - 数据库账号具有建表权限:启用插件会新增一张请求记录表。
- 一个能正常访问的 HTTPS 博客地址。
如果博客运行在 Docker Compose 中,要检查的是 PHP 容器内的版本。例如 PHP 服务名为 php 时:
docker compose exec php php -v
docker compose exec php php -mTypecho 已升级到 1.3.0,并不意味着 PHP 容器也升级了。升级 PHP 前应备份网站和数据库,并在副本上验证主题与其他插件。
从 Releases 下载 AgentBridge-1.0.2.zip,解压后将整个 AgentBridge 目录上传到:
Typecho 根目录/usr/plugins/AgentBridge/目录中应该直接包含 Plugin.php、vendor/、Mcp/ 等文件和目录。不要多套一层同名文件夹,也不要漏传 vendor/。
安装请使用 Release 附件,而不是 GitHub 自动生成的 Source code 压缩包。 Release 已包含运行依赖,服务器不需要安装 Composer;源码压缩包不含 vendor。
第二步:配置权限和 Token
进入 Typecho 后台的「控制台 → 插件」,启用 AgentBridge,再打开设置。
- 选择绑定用户。需要发布和管理页面时,绑定编辑或管理员用户。
- 保留「强制 HTTPS」。只在隔离的本机 HTTP 测试环境中关闭它。
- 根据用途开启发布、删除等权限。插件默认允许写草稿,默认不允许发布和永久删除。
- 首次配置选择「保存时生成新 Token」,保存后立即复制 Token。明文只显示一次,服务器保存的是哈希。
- 复制设置页显示的 MCP 地址,通常类似:
https://blog.example.com/index.php/action/agent-mcp绑定专用编辑用户后,如果要读取或修改其他作者的旧文章,需要分别开启跨作者读取和写入。写入开关依赖读取开关,角色权限仍然生效。
Token 可以在后台轮换,轮换会撤销旧 Token。Typecho 的原生停用流程会删除插件配置,重新启用后需要重新配置 Token。
第三步:连接 Codex
在 ~/.codex/config.toml 中加入下面的配置,把域名替换为自己的博客:
[mcp_servers.typecho]
url = "https://blog.example.com/index.php/action/agent-mcp"
bearer_token_env_var = "TYPECHO_MCP_TOKEN"然后让 Token 存在于启动 Codex 的进程环境中。例如在 macOS 默认的 zsh 中,可以隐藏输入 Token,再启动 CLI:
read -rs 'TYPECHO_MCP_TOKEN?请输入 Token:'
export TYPECHO_MCP_TOKEN
codex使用 Codex 桌面版时,同样要确保桌面应用启动时能读取这个环境变量。在一个终端里执行 export,不会把变量自动传给已经打开的桌面应用。
配置依据是 OpenAI 官方 MCP 文档。AgentBridge 不提供 OAuth,因此不需要为它执行 codex mcp login。
其他客户端只要支持相应的 HTTP MCP 传输和 Header 配置,就可以使用同一个地址,并发送:
Authorization: Bearer <你的 Token>我已经用 Codex app-server 和官方 Python MCP SDK 做过实际联调;其他客户端需要按各自的配置方式验证。
第四步:跑通一次完整写作流程
连接完成后,先让 agent 确认站点:
使用 typecho 获取站点信息,确认连接的是我的测试博客,并列出可以使用的工具。
接着创建一篇草稿:
写一篇《我的第一篇 MCP 博客》,正文用 Markdown,保存为草稿,暂不发布。告诉我文章 ID。
检查标题、正文和分类后,再明确要求发布:
读取刚才那篇草稿,检查内容,然后正式发布,并返回文章链接。
对应的主要工具是 create_draft、get_post 和 publish_post。通常不需要自己填写每个参数,agent 会根据工具定义组织调用。
修改已发布文章
可以继续说:
把刚才文章的第二节补充一个示例,先保存修订草稿,不要立即上线。
update_post 只修改提交的字段,省略的字段保持不变。对于已发布文章,修改会先形成修订草稿,线上仍显示原来的版本。
检查后有两种选择:
读取最新修订,确认无误后发布。
或者:
放弃这次修订,保留当前线上文章。
前者调用 publish_post,后者调用 discard_draft。放弃修订不会删除正式文章,也不能用来删除一篇独立草稿。
删除文章
开启删除权限后,可以明确指定文章 ID:
永久删除文章 123,并确认它已不存在。
delete_post 会永久删除文章、评论和修订草稿,没有回收站。关联附件会解除关联,但保留附件文件。独立页面有对应的 delete_page 工具。
实际使用时,先让 agent 读取标题和 ID,再下达删除指令,能更容易确认操作对象。
避免覆盖和重复操作
每次读取内容都会返回一个 revision。修改、发布、删除和放弃修订都需要携带 expected_revision;如果期间内容发生变化,插件返回 REVISION_CONFLICT,要求重新读取和合并。
每个写操作还需要一个 UUID request_id。如果遇到网络超时,应沿用原来的 ID,先调用 get_operation 查询结果:
succeeded:已经成功,重复请求可以返回保存的历史结果。running:仍在处理中,稍后再查。outcome_unknown:可能已发生写入,需要检查文章或后台,不能换一个新 ID 盲目重试。
这套机制降低重复创建和误覆盖的风险,但不承诺全局事务或恰好执行一次。插件的写锁针对单主机 MCP 操作;Typecho 原生后台和其他服务器实例不参与这个锁。
图片、反向代理与常见问题
图片通过 Base64 上传,解码后最大 512 KiB,支持 JPEG、PNG、GIF、WebP。远程 MCP 服务器不能直接读取你电脑上的图片路径;大图更适合先放到自己的图床或 CDN,再在正文中引用 URL。
使用 Nginx、Cloudflare 或其他反向代理时,需要确认三件事:MCP 地址正确到达 index.php,Authorization 被转发给 PHP,可信代理的 HTTPS 状态被正确传递。不要直接复制别人的内网 IP,也不要无条件信任客户端传入的转发 Header。
| 现象 | 优先检查 |
|---|---|
| 401 | Token 是否正确,Authorization 是否被转发 |
| 403 | HTTPS 识别、Origin、绑定用户或权限;同时区分是否被 CDN/WAF 拦截 |
| 404 或返回 HTML | 插件是否启用,地址是否正确,Nginx 重写是否覆盖了接口 |
| 503 | 插件尚未生成或保存 Token |
| 429 / RATE_LIMITED | 请求频率超限,等待窗口后保持原 request_id 重试 |
| REVISION_CONFLICT | 重新读取内容并合并修改 |
第三方插件也需要一起测试,因为保存、发布和删除会触发原生钩子。本站部署时就遇到了 Handsome 在可选关系表缺失、内容尚未进入搜索索引时的删除问题。相关修复属于本站 Handsome 适配,不包含在 AgentBridge 安装包中,也不代表所有主题插件都已验证兼容。
测试范围与后续反馈
公开版本已验证 Typecho 1.2.1、1.3.0,覆盖 PHP 8.1 + SQLite、PHP 8.5 + SQLite、PHP 8.5 + MySQL 的六个组合,每个组合 17 项集成测试通过。本站另在 Docker 中运行 PHP 8.5.10,完成了公网 MCP 联调。
完整的版本号、测试项目和当前限制见 验收报告。这些结果代表实际测试过的组合,不是对所有 PHP 版本、存储插件或多机部署的兼容保证。
如果你也使用 Typecho,欢迎从 Releases 安装体验,或到 Issues 提交问题。反馈时请附上 Typecho、PHP、数据库以及主题和相关插件版本,去掉 Token、数据库凭证和私密正文。
这篇介绍与教程也通过 AgentBridge 写入并正式发布到博客。
1 条评论
这个思路很实用:直接把 MCP 插件跑在 Typecho 里面,不用额外部署 Node.js 或 Python 服务,对已经在跑 PHP 的个人博客来说维护成本很低。我比较欣赏的是分工设计,agent 负责写作和检查,插件负责参数校验和权限检查,而且默认只建草稿,发布和删除要显式开启,安全上考虑得很周到。想请教一下,request_id 查询写操作状态这个设计,是在实际使用中遇到过重复提交或超时的问题才加上的吗?