MCP 工具(可选,需安装 MCP Server 插件)

插件可选地与 Halo MCP Server 集成,向 AI 助手贡献四个工具。未安装 MCP Server 时插件照常安装、启动与使用(依赖在 plugin.yaml 中以 mcp-server? 声明为可选),只是这四个工具不会出现。

工具(本地名)类型参数说明
wechat_sync_preview只读postName获取预览信息:按与同步一致的规则美化正文,返回美化后的正文 HTML(预览所需的样式已内联在元素上,不带 <style> 标签,图片与链接也是完整地址,因此可直接渲染、也可在客户端清洗或 AI 转述 HTML 时保持正确;正文里的相对地址已按站点「外部访问地址」补全为完整链接)、上传后实际使用的标题(64 字上限)、摘要(120 字)、作者(8 字)、原文链接(阅读原文)与留言设置,以及因超过微信长度上限被截断的字段名(长度按微信计字口径折算:汉字 / 全角字符计 1 字、半角字符计 0.5 字、emoji 计 2 字);不调用微信接口、不写任何数据,可反复调用
wechat_sync_submit写操作postName提交同步到微信:先做提交前预检(微信配置、封面图、文章是否正在同步中),通过后创建后台同步任务并立即返回;同步时封面与正文图片会自动转存到微信素材库、正文按公众号排版美化,完成后可在公众号草稿箱看到草稿(开启「重复同步更新草稿」时,同一篇文章重复提交会先校验上次写入的那份草稿是否还在——在则更新它、不在则新建,不会堆出重复草稿;关闭该开关则每次新建)。返回值不含「本次是更新还是新建」:提交时虽会实查上次那份草稿是否还在微信侧(draft/get),但那只是预判——执行阶段还可能回退为新建(草稿在执行前被删除,或更新被微信网关 / WAF 拒绝),回传该字段会让 AI 把预判当结果答复失真。本次到底是新建还是更新,请用 wechat_sync_status 的 draftAction 作答(工具描述与结果文本都写明了这一点)
wechat_sync_status只读postName查询同步状态:返回该文章最近一次同步的状态、说明与实际草稿动作——PENDING(已提交、正在后台执行)/ SUCCESS(已写入公众号草稿箱)/ FAILED(失败,message 为微信返回的失败原因)/ NONE(尚未同步过);SUCCESS 时必须按 draftAction 字段回答「新建还是更新」(工具描述里下了同样指令):update = 更新了该文章已有的那份草稿(草稿箱里没有多出一份),create = 新建了一份草稿(草稿箱里多出一份;原草稿被删除、或更新被微信侧拒绝后回退新建都记它),空串 = 尚未成功同步过;不要自行推断、也不要沿用提交时的预计;只读取任务记录,不调用微信接口、不写任何数据,提交同步后可用它轮询结果
wechat_cache_cleanup写操作无清理素材缓存:立即执行一次素材缓存清理(与每天 0 点的计划任务同一套规则),返回本次删除条数与生效的保留策略——deletedRecords(删除条数)、remainingRecords(剩余记录数)、retentionDays(生效的保留策略:保留天数,如 "30";「全部保留」时为 never)、cutoff(判定时间);只删除「超过保留期且最近未被使用」的记录,仍被复用的缓存不会误删,也不影响每天 0 点的自动清理

前三个工具只接收一个参数 postName(文章的 metadata.name),内部按与 Console 完全一致的规则取用文章字段(标题、摘要、封面、作者、原文链接、渲染后的正文),因此 MCP 调用的效果与在 Console 点「同步到微信公众号」相同;wechat_cache_cleanup 不需要参数。

启用方式

  1. 在 Halo 应用市场安装并启用 MCP Server 插件(mcp-server,>=1.0.0 & <2.0.0):商店页面 https://www.halo.run/store/apps/app-ybv96zol;
  2. 在「工具 → MCP 服务」的访问密钥中,把这四个工具(按需选择)勾选进该密钥可用的工具列表——新贡献的工具不会自动加入已有密钥,需管理员手动选择;
  3. 用该密钥在 MCP 客户端调用 tools/list / tools/call。

说明

  • 工具名由 MCP Server 按插件归属自动拼接为协议名,调用时以 tools/list 返回的名称为准:编码后的插件 ID + __ + 本地工具名,例如 plugin-wechat-official-sync__wechat_sync_preview。其中 __ 是 MCP Server 的固定分隔符(双下划线),与本地工具名里的单下划线(wechat_sync_preview 的 _)是两回事——插件 ID 里的 - 属白名单字符会原样保留,其余字符(下划线、点、中文等)会被转义成 _hhhhhh,因此 __ 在协议名中不会产生歧义;
  • 四个工具都声明了 inputSchema 与 outputSchema:MCP Server 会在调用前校验参数、在成功返回后按 outputSchema 校验结构化结果(失败结果不参与该校验),因此工具的输出字段是稳定契约;
  • wechat_sync_preview 返回的 content 把预览所需的样式内联在元素上(微信原生代码块的行号列与代码行排版、分栏卡片/画廊重建出的布局表格标记)——MCP 客户端(AI 对话界面等)没有 Console 预览的宿主页面样式,而这些内容靠样式表才能立起来(代码块行号原本由 CSS 计数器生成)。不下发 <style> 样式块是有意的:客户端做 HTML 清洗、或 AI 转述时,<style> 标签最容易被丢掉,一丢预览就散架;内联后「元素 + 自身的行内样式」即可正确渲染,代码块行号也改写成了字面数字(不再依赖 CSS 计数器)。这些样式只用于预览渲染,提交到微信的草稿仍是纯行内样式的正文。此外,content 里的图片、链接等相对地址已按站点「外部访问地址」补全为完整链接——Console 预览渲染在站点页面内,相对地址由页面自动解析,而 MCP 客户端拿到的是脱离站点的 HTML 片段,补全后图片才能正常显示(只改预览返回的内容,提交到微信的草稿不受影响);内容已自带全部样式,MCP 客户端(AI 助手)只需原样输出:不要改写、精简、重新排版或另加样式(工具描述、content 字段说明与工具结果说明三处都写明了这一点),否则渲染结果会与 Console 后台预览、最终草稿不一致;
  • wechat_sync_preview 返回的 title / digest / author 就是最终写入草稿的值;完整规则写在工具描述里(预览与提交两个工具都写了:长度按微信计字口径折算——汉字 / 全角字符计 1 字、半角字符计 0.5 字、emoji 等增补字符计 2 字,按整字符取舍,超过上限的部分自动截断),各字段的说明里也带上自己的上限(标题 64 字、作者 8 字、摘要 120 字)与缩短后的同一口径,因此单看字段说明即可解释「为什么预览里的值比文章里的短」,被截断的字段名在 truncatedFields 中列出;
  • 权限回调要求调用方已认证(MCP 访问密钥归属某个 Halo 用户),匿名调用会被拒绝;更细的授权通过「角色 - 微信公众号同步 - 发布到微信公众号」与访问密钥的工具白名单控制(读取 AppSecret 等仍只发生在插件服务端内部);
  • wechat_sync_submit 是异步的:返回 PENDING 表示任务已落库并在后台执行,用 wechat_sync_status 轮询即可拿到最终结果(与文章列表状态列同源);同一篇文章在「同步中」时重复提交会被拒绝(错误码 CONFLICT),预检不通过时返回 PRECONDITION_FAILED 且不会产生任务记录;
  • wechat_sync_submit 不返回草稿动作:为免「任务记录里还留着草稿 media_id、但草稿其实已在公众号后台被删除」这类误判,服务端在提交时会实查该文章上次写入的那份草稿是否还在微信侧(只读的 draft/get;该文章还没有草稿、或关闭了「重复同步更新草稿」时不做这次查询),结论只作为说明文案里的「预计更新 / 预计新建」——执行阶段还会再校验一次(其间草稿仍可能被删除),且更新被微信侧拒绝(网关 / WAF 拦截、封面素材失效 40007)时会改为新建,把它当结论回答就会失真。实际动作由 wechat_sync_status 的 draftAction 给出(update 更新既有草稿 / create 新建一份草稿,含回退新建),AI 助手不需要理解配置项,照这个字段说「本次新建了草稿 / 本次更新了草稿」即可,不要笼统回一句「已同步成功」;为此状态工具的描述里就下了指令(「必须按 draftAction 明说本次是新建还是更新,不要自行推断」),字段说明与结果文本同样写明——MCP 里 outputSchema 的字段说明主要用于结果校验,多数客户端不会把字段描述放进模型的上下文;若客户端又只把工具结果的文本(content)喂给模型、不传 structuredContent,模型连字段都看不到。因此状态查询的结果文本直接带上状态、实际动作(「请告诉用户:本次新建草稿 / 本次更新既有草稿(以 draftAction 为准,不要自行推断)」)与说明,模型照抄即可;字段本身仍照常返回,供结构化消费的客户端使用;
  • wechat_cache_cleanup 与「缓存清理计划任务」共用同一套清理逻辑:「缓存保留天数」在每次执行时读取(与插件设置一致,改完无需重启),把它留空、填 0 或负数(即「全部保留」)时不做删除(返回 deletedRecords: 0、retentionDays: "never"、cutoff: "");
  • 返回给 MCP 客户端的错误使用稳定错误码:INVALID_ARGUMENT(参数不合法)、NOT_FOUND(文章不存在)、CONFLICT(正在同步中)、PRECONDITION_FAILED(预检未通过)、INTERNAL_ERROR(其它异常,详情见服务端日志)。