MCP 发布测试
这是一篇由 Codex 通过 MCP 创建的测试文章。
- 发布时间:2026-04-30T18:03:30.512Z
- 目的:验证 create_post 与远端写入流程
如果你能在博客中看到这篇文章,说明发布链路工作正常。
这是一篇由 Codex 通过 MCP 创建的测试文章。
如果你能在博客中看到这篇文章,说明发布链路工作正常。
在开发基于Model Context Protocol (MCP)的博客管理工具时,遇到了一个典型的跨平台路径配置问题。本文详细记录了问题的发现、分析和解决过程,希望能帮助遇到类似问题的开发者。
MCP Server astro-blog-ssh 在启动时报错:
failed to initialize MCP client for astro-blog-ssh: MCP 服务启动失败: Error: Command failed: ssh -p 7122 -o BatchMode=yes -o StrictHostKeyChecking=accept-new -i /Users/mhl/.ssh/id_ed25519 mahongliang@111.228.52.26 mkdir -p '/home/mahongliang/workspace/astro-site/content/blog' && test -d '/home/mahongl...
首先确认SSH密钥文件权限正确(600),SSH连接本身能够正常建立:
ssh -p 7122 -o BatchMode=yes -o StrictHostKeyChecking=accept-new -i /Users/mhl/.ssh/id_ed25519 mahongliang@111.228.52.26 "echo 'SSH connection successful'"
执行完整的目录创建命令时发现问题:
ssh -p 7122 -o BatchMode=yes -o StrictHostKeyChecking=accept-new -i /Users/mhl/.ssh/id_ed25519 mahongliang@111.228.52.26 "mkdir -p '/home/mahongliang/workspace/astro-site/content/blog' && test -d '/home/mahongliang/workspace/astro-site/content/blog'"
返回错误:mkdir: /home/mahongliang: Operation not supported
通过查询远程服务器的用户主目录:
ssh -p 7122 -o BatchMode=yes -o StrictHostKeyChecking=accept-new -i /Users/mhl/.ssh/id_ed25519 mahongliang@111.228.52.26 "echo \$HOME"
发现返回结果是:/Users/mahongliang
这说明远程服务器实际上是macOS系统,而不是假设的Linux系统!
将MCP配置中的远程路径从Linux路径改为macOS路径:
错误配置:
"BLOG_REMOTE_POSTS_DIR": "/home/mahongliang/workspace/astro-site/content/blog"
正确配置:
"BLOG_REMOTE_POSTS_DIR": "/Users/mahongliang/workspace/astro-site/content/blog"
使用修正后的路径测试:
ssh -p 7122 -o BatchMode=yes -o StrictHostKeyChecking=accept-new -i /Users/mhl/.ssh/id_ed25519 mahongliang@111.228.52.26 "mkdir -p '/Users/mahongliang/workspace/astro-site/content/blog' && test -d '/Users/mahongliang/workspace/astro-site/content/blog' && echo 'Directory check successful'"
返回:Directory check successful
MCP Server成功启动:
Astro Blog SSH MCP Server 已启动 -> mahongliang@111.228.52.26:/Users/mahongliang/workspace/astro-site/content/blog
echo $HOME 命令获取远程用户的实际主目录路径这个问题虽然简单,但体现了开发中常见的"假设陷阱"。通过系统性的排查和验证,我们能够快速找到并解决问题。
这篇文章记录一次完整的实操:在 macOS 上安装 Blender 和 blender-mcp,把它接进 Codex,然后直接在 Blender 里做出一辆圆润卡通风格的儿童玩具小巴士。
这次不是停留在“装好就算完”,而是希望把整条链路跑通:
uv 和 blender-mcpaddon.py4.5.4 LTSuv 0.11.8astro-blog-ssh MCP 发布blender-mcp 的结构其实很直接:
addon.pyuvx blender-mcp 启动在这台机器上,最终采用的是下面这套方式:
uv把 uv 安装到用户目录下的 ~/bin,避免改系统环境。
注册成一个全局 MCP server,命令是:
uvx blender-mcp
同时额外加了:
DISABLE_TELEMETRY=true
从仓库下载 addon.py,再安装到 Blender 用户插件目录。最终插件实际位于 Blender 的用户脚本目录里。
这台机器一开始并没有 Blender,所以后面直接走了官方 DMG:
~/Applications/Blender.appBlender 4.5.4 LTS这样做的好处是不用碰系统级 /Applications 权限,整个安装对现有环境影响更小。
表面上看,插件已经安装并启用了,但 Blender 侧栏里一开始没有看到 BlenderMCP 面板。
排查后确认了几件事:
VIEW_3D > UI > BlenderMCP根因不是“没装上”,而是 Blender 界面和验证方式的问题。
更关键的问题出现在 MCP 调用阶段。
最开始为了方便验证,尝试让 Blender 用 --background 模式启动,再自动拉起 blendermcp 服务。这个方式虽然能把 9876 端口打开,但真实请求会一直超时。
后来定位到原因:
blender-mcp 内部依赖 Blender 主线程上的 bpy.app.timers 来执行请求,而后台模式不会正常处理这类回调,所以会出现:
这个点很关键。
最后换成真正的 GUI Blender 实例启动,并自动执行插件的 start_server 操作之后,链路才真正打通。
连通后,先做了最基础的一次读取:
Cube、Light、Camera接着做了第一个真正的操作:
直接通过 Blender MCP 执行代码,在默认立方体上方创建一个球体:
Sphere(0, 0, 2)这一步的意义不在于球体本身,而在于确认:
做到这里,才算是真的“可以直接控制了”。
接下来开始用自然语言一步步建一个玩具风模型。
用户最终定下来的方向是:
没有追求写实,而是走“基础几何体 + 圆角塑形”的路线:
这条路线的好处是非常适合儿童玩具感:
过程中也踩到了两个很典型的问题。
第一次建模时,代码里用了 shadow_method,但当前 Blender 版本对应的材质对象没有这个属性,导致直接报错。
处理方式很简单:
blend_method第一次把零件都 parent 到车身时,车身本身还带有非 1 的缩放,于是子对象在世界坐标里被放大错位,轮子和装饰位置都跑掉了。
根因定位后,采用了更稳妥的方式:
这样模型结构才恢复正常。
模型先做出基础版本,然后又做了两轮增强。
Cube 和 Sphere继续往“可爱”而不是“写实”方向走:
为了让它更像儿童玩具,而不只是一个低模小车,最后又补了正脸表情:
这样整个小巴士的气质就从“简化汽车模型”变成了更明显的“玩具角色车”。
如果只看结果,这篇文章像是在讲怎么做一个玩具车。但我觉得真正有价值的,是这几个经验:
最容易被误判的是:
但真实请求未必能执行。
一定要做至少一次真实读写验证,比如:
某些插件依赖主线程回调或 UI 循环,后台模式并不等价于真正的 Blender 运行状态。
这个问题如果不先定位,很容易误以为是:
实际上只是运行模式不对。
比起一上来就说“帮我做一个完整场景”,更稳妥的做法是:
这样每一步都知道链路在哪一层是通的。
最后得到的是一辆:
它不追求工业设计精度,而是更偏“儿童玩具模型”的方向,这恰好也是自然语言建模特别适合的场景。
这次最大的收获不是“装上了 Blender MCP”,而是把整条链路真正走通了:
如果只是把工具装上,最多算完成了 30%。
真正值得记录的是:它已经可以被稳定地拿来做事情了。
接下来如果继续往下走,很自然的方向会是:
比如:先让 AI 生成 3D 小道具,再把它们整理成博客里的可视化案例。这时候,MCP 就不只是“一个工具连接器”,而会变成整个创作工作流的一部分。
最近把博客的发布链路改成了一个很直接的 MCP:本地启动 astro-blog-ssh,再通过 SSH 直接把 Markdown 写到远端 Astro 博客的 content/blog 目录。
有了这条链路之后,一个很自然的下一步,就是让 Codex 不只是“能调用工具”,而是“知道什么时候应该把当前对话整理成文章并直接发布”。这次做的,就是把这套行为沉淀成一个可安装的 skill。
一开始最需要收窄的问题,不是怎么写 SKILL.md,而是这个 skill 到底要教 Codex 做什么。
这次明确的目标是:
也就是说,这个 skill 不是安装器,不是 MCP 教程,而是一个“从对话到公开文章”的行为规范。
为了避免把 skill 写成随意提示词,先在仓库里补了一份设计文档:
docs/superpowers/specs/2026-05-01-astro-blog-auto-publish-design.md这份 spec 主要固定了几件事:
接着又补了一份实现计划:
docs/superpowers/plans/2026-05-01-astro-blog-auto-publish.md这样后续生成的 skill 文件就有了清晰边界,既不容易超范围,也更方便以后继续维护。
这次只保留最小必要文件:
skills/astro-blog-auto-publish/SKILL.md
skills/astro-blog-auto-publish/agents/openai.yaml
SKILL.md 负责定义核心行为:
generate_slug 和 create_postagents/openai.yaml 则负责给 Codex 的技能列表和显式调用入口提供元数据,比如:
display_nameshort_descriptiondefault_prompt这个分层很重要。真正的工作规范应该放在 SKILL.md,而不是都挤进 description 里,不然模型很容易只读简短描述、不读完整 skill。
相比“写出一篇文章”,更重要的是“什么时候不该发”。
所以这次 skill 里最关键的约束有几条:
这几条基本决定了 skill 的可用性。如果没有这些边界,所谓“自动发布”很容易变成“自动制造垃圾文章”。
为了避免手写 agents/openai.yaml,我直接复用了现成 skill 自带的生成脚本。
第一次运行时,脚本报错了:缺少 yaml 模块。
根因不是脚本逻辑错误,而是它默认会读取 SKILL.md frontmatter,并使用 PyYAML 解析。本地当前 Python 环境没有这个依赖。
这时候最小改动不是去改环境,也不是去改脚本,而是直接使用它支持的 --name 参数,绕开 frontmatter 解析步骤。这样既不污染环境,也不偏离当前任务范围。
这个处理方式的好处很明显:
openai.yaml$skill-name 被 shell 吃掉了openai.yaml 里有个 default_prompt 字段,规范要求显式写出 $skill-name。
第一次生成后,结果从:
Use $astro-blog-auto-publish ...
变成了:
Use -blog-auto-publish ...
问题出在 shell 展开:$astro 被当成环境变量替换掉了,剩下后半截字符串。
根因明确之后,修复也很简单:不要怀疑 skill 内容本身,直接把生成后的 openai.yaml 用字面量修正为正确的 $astro-blog-auto-publish。
这个问题很小,但挺典型:
如果没有在最后做一次完整验证,很容易带着这个细小错误交付出去。
这次没有去验证“Codex 运行时一定会自动触发 skill”,因为那取决于实际的 skill 加载环境和 MCP 可用性。但本地已经做了这些可证实的检查:
SKILL.md frontmatter 合法,命名符合 hyphen-case。openai.yaml 已生成,字段和 skill 语义一致。default_prompt 中的 $astro-blog-auto-publish 已按字面量保留。这意味着“skill 包结构正确”这件事是可以确认的;至于“运行时是否自动发布成功”,则仍然依赖 Codex skill 加载能力和 astro-blog-ssh MCP 是否在线。
如果只是偶尔发一篇文章,直接手工整理也能做。
但当你已经有了 MCP 工具链,下一步最有价值的就不是重复调用工具,而是把“什么时候该调用、如何整理、什么情况下不能发”固化下来。
skill 的真正价值,不在于省掉几个命令,而在于让自动化行为有边界、有默认策略、也有失败回退路径。
这次的 astro-blog-auto-publish 就属于这种类型:它不是新能力,而是把已有能力变成了可重复复用的工作流。
这篇文章想解决一个很具体的问题:怎么把一套 WordPress 博客,从本地部署、到公网访问、再到接入 MCP / AI 工具做文章增删改查,完整打通,并整理成可以上传 Git、让其他电脑直接复用的方案。
如果你刚接触 WordPress、Docker、反向代理,或者还不熟悉 MCP,这篇文章会尽量按“现象 → 原因 → 处理方式 → 注意事项”的顺序讲清楚。文中的敏感信息已经做过脱敏处理,例如:
your-blog.exampleyour-server-ipyour-wordpress-usernamexxxx xxxx xxxx xxxx xxxx xxxx/path/to/projectold-host.example先看结果,再看过程。
这套链路最终不是“直接把本地 8016 端口暴露出去”,而是做了一层更稳定的收口:
your-blog.example
-> 服务器 Nginx / 反向代理
-> http://127.0.0.1:7412/
-> nps / npc 隧道
-> 本机 127.0.0.1:8016
-> WordPress 容器
这条链路的好处是:
本地 WordPress 使用 Docker 跑起来,最后固定在:
http://127.0.0.1:8016
为什么不用常见的 8080?原因很简单:开发环境里 8080 太常见,容易和已有服务、浏览器缓存、历史代理配置混在一起。换成一个明确的本地端口,可以减少排查成本。
这一步的核心原则有两个:
127.0.0.1:8016:80这是整个过程中最容易让人误以为“浏览器坏了”或者“反向代理配置错了”的问题。
https://your-blog.example,页面打不开https://your-blog.example:8080/ 或 :8016根因通常不在浏览器,而在 WordPress 自己认错了“站点地址”。
WordPress 有两个特别关键的概念:
WP_HOMEWP_SITEURL如果这两个值还保留着本地开发地址,比如 http://127.0.0.1:8016,那么用户虽然是通过正式域名进来的,WordPress 仍然会坚持把页面里的链接和重定向指回本地端口。
正式对外访问后,站点地址必须改成正式域名:
define('WP_HOME', 'https://your-blog.example');
define('WP_SITEURL', 'https://your-blog.example');
一旦改对,再去验证:
Link 是否已经变成正式域名这个问题一开始看起来像“WordPress 没起来”,但实际并不是。
127.0.0.1:8016 能访问http://127.0.0.1:7412/这个问题不能直接猜,要按链路一段一段排:
npc 当前转发目标是不是还是旧端口nps 暴露的端口到底是不是你想要的那个端口8080 切到了 8016npc 配置文件里仍然保留着旧目标old-host.example)在服务端冲突,导致 npc 重连时报错换句话说,问题不是只有一层,而是“旧端口残留”和“旧反代项冲突”叠在了一起。
127.0.0.1:8016npc 的 TCP 目标改成 127.0.0.1:80167412这一段是最容易让人误判成“代码有问题”的地方。
WordPress 写入接口最关键的不是普通账号密码,而是 Application Password。
这次排查里实际发现了两个问题:
不要一上来就测创建文章,先测:
/wp-json/wp/v2/users/me
只有当它返回 200,并且用户身份正确时,才说明这套凭据真的可以用于后续写操作。
为了让整套方案更稳定,我把能力拆成了两层:
这样做的好处是:
有,而且不是只做了“读一下列表”这种浅层验证,而是做了真正的闭环测试。
还额外写了一个独立测试脚本 test-mcp-client.mjs,通过 MCP 协议直接连接 wordpress-mcp.js,跑通了:
create_postget_postupdate_postdelete_post这说明问题真正的边界已经很清楚:
因为“自己电脑上能跑”不等于“这套东西可以长期复用”。如果后续要放到 Git,给别的电脑继续使用,必须把敏感信息和环境耦合清掉。
这次收尾主要做了这些事:
.env.example.env 就能跑npm run start:env 和 npm run test:mcp:env如果只是想先把工具跑起来,而不是一次性把所有细节都吃透,可以按下面这条最短路径走:
cd wordpress-ai-tools/mcp-server
cp .env.example .env
# 把 .env 里的站点地址、用户名、应用密码改成你自己的
npm install
npm run start:env
如果还想确认整条 MCP 链路真的能写文章,再执行:
npm run test:mcp:env
这次最大的价值,不是“我把 WordPress 跑起来了”,而是把它整理成了一条真正可重复、可迁移、可验证的工作流:本地部署可控、公网访问稳定、AI 工具可写、目录结构可复用。
如果后续继续扩展,这套基础还可以往媒体上传、页面管理、分类标签自动化、自动发布工作流继续延伸。对个人博客来说,这已经不只是一个站点,而是一套可以长期积累的内容工具链。