技术实践

我给航栈做了一个 MCP,从能投稿到别人也能用

记录给航栈开发投稿 MCP 的实际过程,从复用网站 API、个人令牌权限和失败恢复,到 npm 发布、安装验证,以及上线后补全安装说明。

羊先生的头像
羊先生2026.10.26 · 15 分钟阅读 · 2 阅读
文章正文还需 15 分钟

给航栈加 MCP,是想在 Codex 里把文章、工具和讨论直接提交到网站。

正文已经在对话里整理好了,我想把保存草稿、投稿这几步也接起来。客户端拿着我的授权去操作,内容还归我的账号,之后照常在网站里查看和修改。

这次我继续用 Codex 读项目、改代码、跑检查。MCP 服务跑通以后,又接着做了个人令牌管理、npm 安装包和接入说明。花时间来回处理的,主要是权限和发布,还有别人第一次使用时会碰到的问题。

先接上网站原有的投稿流程

航栈已经有文章、工具和讨论的接口,也有草稿和审核流程。这些可以继续用。

我把 MCP 做成一个单独的 TypeScript 包,用官方 SDK 注册工具,用 Zod 约束输入。Codex 调用工具后,服务把参数整理好,再请求网站 API。

这版选了 stdio,运行过程大致是这样。

text 复制代码
Codex 等支持本地 MCP 的客户端
          ↓ stdio
本机启动的 @vipbic/mcp 进程
          ↓ HTTPS
航栈 API
          ↓
账号与权限校验、保存草稿、提交审核

客户端负责启动进程,网站继续处理账号、内容和审核。第一版先把这条流程做完,没有另外部署一个远程 MCP HTTP 服务。

工具也按投稿时的需要来分。先检查连接和账号,再查询分类;需要改旧内容,就先读取完整正文;要投稿,再调用文章、工具或讨论对应的工具。

参数不能只收一个标题和正文。工具条目还有官网、标签、适用方向,以及是否免费、是否开源。文章和工具的摘要也有长度要求。我把这些检查放进了工具输入和提交校验里,少让客户端发一些注定会失败的请求。

给别人用,得有专用令牌

调试时,可以沿用网站的登录会话。可一旦准备把 MCP 发出去,就得让别人有自己的授权方式。

让使用者打开浏览器开发者工具,翻出登录凭据,再粘进客户端,实在不方便。网站登录凭据能做的事情也太多了。

于是又加了个人 MCP 令牌。用户登录航栈、验证邮箱后,在个人中心创建一枚令牌,选择只读或者读写权限,再设置有效期。每个客户端可以单独用一枚,不用了就撤销。

完整令牌只在创建时显示一次,数据库保存它的 SHA-256 哈希。接口收到令牌后,会检查有效期、撤销状态、账号状态和本次操作需要的权限。

个人 MCP 令牌只操作创建者自己的内容。它可以读草稿、保存修改、提交审核,不能拿来改账号设置、管理用户或者操作管理员后台。

管理员账号创建的个人令牌,也按这个规则处理。

所以,这个 MCP 默认的投稿结果是 PENDING,网站审核通过后才公开。保存草稿则是 DRAFT。工具名字里虽然有 publish,普通用户通过它提交内容,仍然要走网站审核。

返回结果里也要区分保存成功和已经公开。用户拿到 PENDING,就能知道内容还在等审核,不用再去公开列表里找。

超时之后,先别再发一遍

写投稿功能时,有一种情况需要单独处理。网站已经保存了内容,客户端却因为超时没拿到结果。

这时候再自动创建一次,就可能多出两篇一样的文章。

这版没有给写入请求加自动重试。客户端遇到结果不确定的错误,先按标题查自己的内容;如果已经拿到内容 ID,就用这个 ID 读取实际状态,再决定下一步。

报错里也尽量保留能接着处理的信息,包括出错阶段、已经保存的内容 ID,以及是否还不能确认写入结果。只回一个请求失败,接下来的人就只能猜。

修改内容还有另一个容易忽略的地方。网站现有的更新接口接收完整编辑字段,会覆盖原记录。只传一个新标题,省略的标签、图片和工具卡片就可能回到默认值。

我把更新顺序也写进了说明,先读取完整内容,改好后带上原 ID 和完整字段提交。

在仓库里跑通,还要拿出去装一次

本地调试时,工作区里的依赖都在,包少声明一个依赖,也可能暂时看不出来。别人通过 npm 安装时,就没有这个条件了。

我给安装包设了文件白名单,只放编译后的 JavaScript、README 和 package.json。环境文件、个人配置、测试文件和开发脚本都不进包。

打包后,再把实际生成的 tgz 安装到仓库之外的临时目录,用真实的 stdio 客户端连接。这里要检查工具能否发现、账号状态能否读取、普通令牌能否投稿,以及个人令牌能不能绕到管理员发布操作。

后台的验证单独做。隔离数据库里会创建不同权限的账号和令牌,检查只读令牌写入是否返回 403,撤销后是否返回 401,以及三类内容有没有归到正确的用户下面。

正式上线后,还用临时普通账号走了一遍。文章、工具和讨论都先保存成私有草稿,再提交成待审核状态,验证完清理测试用户和内容。这样能检查生产环境里的实际接口,也不会往公开列表里塞测试文章。

npm 的 403,卡在了一枚令牌上

安装包准备好后,我登录 npm,发布 @vipbic/mcp@0.1.0,结果收到 403。

提示要求双重验证,或者使用启用了 Bypass 2FA 的 granular access token。这次我选了令牌方式。

创建令牌时又遇到一个表单提示,给了 Organizations 权限,却没有选组织。这个包发在个人账号的 scope 下,用不到组织管理权限,把那一项设成 No access 就可以继续。包本身的发布权限要在 Packages and scopes 里配置。

换上令牌再发,还是 403。

账号检查是对的,确实属于发布账号。我继续查令牌元数据,才看到新建的那枚令牌,bypass_2fa 仍然是 false。后来确认填错了令牌,换成正确的新令牌,这次发布才成功。

这次多跑一遍发布也没解决问题。账号能登录,发布权限还得另查。

发布后,我又用了空 npm 配置和全新缓存,从公共仓库匿名安装固定版本,核对包的校验值,再连接 stdio 服务。到这一步,才确认别人可以通过公开地址装到同一份包。

安装说明又补了一轮

网站已经有 MCP 接入页,我也放了 JSON 和 Codex TOML 配置。可入口藏在页脚,页面主要在讲令牌和配置,缺了一段从安装开始的说明,也没有显眼的 npm 链接。

我又问了 Codex,网站上怎么没有安装 MCP 的步骤,也找不到 npm 入口。

回头看,前面的检查盯着代码和工具调用,第一次使用的人会从哪里开始,反倒没照顾好。知道包名的人看一份配置大概能继续,刚接触 MCP 的人连 npm 要不要单独装都还不清楚。

于是又补了一轮页面。桌面顶部导航和手机菜单加上 MCP 安装,接入页首屏放安装入口和 npm 链接,正文从 Node.js 22 或以上的环境要求写起。

npm 和 npx 随 Node.js 安装。使用这个公开包,也不用注册 npm 账号或者提供 npm 发布令牌。终端里可以先运行下面这条命令。

sh 复制代码
npx -y @vipbic/mcp@0.1.0 --version

看到 0.1.0,就说明包已经能在这台电脑上运行。之后在航栈创建个人令牌,把完整配置加进客户端,由客户端启动 MCP 服务。检查版本用的 --version 不要放进服务启动参数。

这轮页面改完,我又看了桌面和手机显示,确认导航找得到、命令能复制,npm 链接也能点到对应的包。

现在,安装包在 npm,网站也有了 安装教程 和 个人令牌管理页。

接下来再整理一篇稿子时,就可以在 Codex 里先让它查询航栈分类,保存成草稿,等我看过全文,再提交审核。