MCP Server 写完了,怎么让别人一条命令用上?

假设你写了一个 MCP server,本地跑得挺好。同事想用,你发过去一段配置:

json 复制代码
{"command": "npx", "args": ["-y", "github:你的用户名/你的仓库"]}

能跑,但每次都要克隆整个仓库。仓库大一点,第一次启动要等十几秒。更麻烦的是,别人装的是哪一版说不清楚------你在 main 上改了东西,对方下次启动可能就拿到一个新行为。

这篇记录的是我把自己写的 MCP server 发到 npm 和 MCP 官方注册表的完整过程。中途踩了三个坑,都是「不遇到就不知道」的那种,写下来省你一遍。

先分清两个东西

npm 是包仓库,MCP Registry 是目录。

npm 存的是代码,npx 从这里下载并运行。MCP Registry 只存元数据------名字、描述、版本、包在哪里、用什么传输方式。它不存代码,也不保证你的 server 一定能跑。

两者都要发,但顺序固定:先发 npm,再发 Registry。Registry 里要填 npm 包的标识符,包不存在它验不过。

官方注册表的地址是 registry.modelcontextprotocol.io,可以用浏览器直接搜名字确认自己有没有发成功。

第一步:让包能被 npx 直接跑

package.json 里这四项是关键:

json 复制代码
{
  "name": "你的包名",
  "version": "1.2.1",
  "bin": { "你的包名": "dist/server.mjs" },
  "files": ["dist/server.mjs"]
}

bin 的键要和包名一致,用户才能直接 npx -y 你的包名。键名不同的话,npx 会找不到可执行文件。

files 决定哪些文件会被打包发出去。只列运行必需的产物,别把源码和测试一起推上去------包体积和安装速度都受影响。

发之前先看一眼包里有什么:

bash 复制代码
npm pack --dry-run

它会列出文件名和体积,不真的生成压缩包。我这次打出来是 231 kB 压缩、973 kB 解压、6 个文件。如果看到不该出现的目录,回去改 files。

第二步:发布,然后等

bash 复制代码
npm publish --access public

这里第一个坑。 终端会打印:

css 复制代码
+ 你的包名@1.2.1

看起来成功了。但如果你马上去 registry.npmjs.org 查,可能查不到,dist-tag 还指着别的版本。

原因是 npm 返回的是 202 Accepted,不是 200 OK------它接受了你的请求,不代表处理完了。本机实测从提交到可查大约 3 分钟。

判断标准不是终端那行输出,而是这两个命令:

bash 复制代码
npm view 你的包名 dist-tags
curl -s https://registry.npmjs.org/你的包名 | head -c 300

dist-tags 里的 latest 指向你刚发的版本,才算真的上线。

第二个坑,更迷惑。 新包第一次发布时,registry 里会先出现一个 0.0.0-stage。我第一次看到时以为包名被别人占了,去查了半天。

它其实是 npm 的分阶段发布机制------先占住包名,真版本随后出现。看到这个不用慌,等几分钟再看,1.2.1 会自己出现。

第三步:加 mcpName,否则 Registry 不认

这是第三个坑,也是最容易漏的一个。

MCP Registry 需要确认「这个 npm 包确实属于你声明的这个 GitHub 命名空间」。它的做法是:

  1. 你声明一个以 io.github.你的用户名/ 开头的名字
  2. 它去 npm 包里找 mcpName 字段
  3. 两个对得上,才允许发布

所以 package.json 里必须加这个字段:

json 复制代码
{
  "mcpName": "io.github.你的GitHub用户名/你的服务名"
}

关键点:这个字段要打进包里。 我第一版(1.2.0)没带它,Registry 那边验不过,只能改完重发一个 1.2.1。多花了一次 2FA 验证。

文件名和 mcpName 的路径可以不一样,但 io.github. 后面的用户名必须和你的 GitHub 账号对得上,否则认证过不去。

第四步:写 server.json

Registry 读的是仓库根目录的 server.json。最简版本长这样:

json 复制代码
{
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
  "name": "io.github.你的用户名/你的服务名",
  "title": "显示名",
  "description": "一句话说清这个 server 能做什么",
  "repository": {
    "url": "https://github.com/你的用户名/你的仓库",
    "source": "github"
  },
  "version": "1.2.1",
  "packages": [
    {
      "registryType": "npm",
      "identifier": "你的包名",
      "version": "1.2.1",
      "transport": { "type": "stdio" }
    }
  ]
}

写的时候会撞到一条限制:description 最多 100 字符 。我第一版写了三百多字,校验直接报 is too long。

100 字符大概是一句话加一个从句。与其硬塞功能列表,不如说清「这是什么、给谁用」。我的最终版本是 86 字符:

78 verified AI tools for engineering teams, with fit, limits, licence and open issues.

packages[].version 和顶层 version 要一致,都跟你刚发的 npm 版本对齐。

第五步:校验、登录、发布

官方给了命令行工具 mcp-publisher,从 registry 仓库的 releases 页下载对应平台的压缩包。

先校验,这一步不用登录:

bash 复制代码
mcp-publisher validate

输出 ✅ server.json is valid 才算过关。schema 错误、字段超长都会在这一步被拦下。

然后登录。它支持 GitHub 认证,有现成的 PAT 就能直接用:

bash 复制代码
mcp-publisher login github --token "$(gh auth token)"

最后发布:

bash 复制代码
mcp-publisher publish

成功会打印 ✓ Successfully published。之后用 API 或网页都能查到:

bash 复制代码
curl -s 'https://registry.modelcontextprotocol.io/v0.1/servers?search=你的服务名'

返回里会带 status: active 和一个 publishedAt 时间戳。

发布之后,别人怎么用

发布前用户的配置是这样(要克隆仓库):

json 复制代码
{"command": "npx", "args": ["-y", "github:你的用户名/你的仓库"]}

发布后:

json 复制代码
{"command": "npx", "args": ["-y", "你的包名"]}

差别不只是短。npm 有版本号,npx 你的包名 拿到的是一个确定的发布版本;github: 形式拿的是仓库当前状态,你在 main 上改了什么,对方下次启动就是什么。

这正是发布的意义:把「你本机能跑」变成「别人拿到的是哪一版说得清」。

三个坑的对照

现象 你以为的 实际的
registry 出现 0.0.0-stage 包名被人占了 npm 分阶段发布的占位版本
终端打印 + 包名@版本 但查不到 发布失败 返回 202,异步处理,等几分钟
mcp-publisher 验不过 mcpName server.json 写错了 包里的 mcpName 没打进去,要重发版本

三个都属于「知道就不难,不知道就卡住」。我这次全程花在排查上的时间,比写代码多。

要不要发,看两件事

如果你的 MCP server 只自己用 ,本地跑就行,不用折腾这些。mcp-publisher 和 server.json 是为了让别人能发现并安装。

如果你想让别人用上,npm + Registry 是目前最短的路径。Registry 是官方目录,一些 MCP 客户端会直接读它。

至于目录站和 awesome-list,那是另一条路。我同时在几个社区目录提交过,反馈周期长且结果不可控------有个 97k star 的目录,最近 30 个已关闭的 PR 合并数是我自己数的:零。所以我把精力放在官方注册表上,那里是自助发布,不用排队等 review。

发布命令和检查方式都在上面。如果你也在做 MCP server,可以先跑一次 npm pack --dry-run,看看包里到底有什么------这一步不花时间,但能省掉后面很多来回。

想看我按这套流程发出去的例子,可以直接查:

那个 server 做的事,是把 78 个团队 AI 工具的适用条件、限制和许可整理成可查询的条目。装了之后在 Claude Desktop 或 Cursor 里问「哪个自托管的记忆层适合我们」,它会带着 stars、许可和已知 issue 一起答。工具本身的说明在 ToolHive 详情页,可以作为「一个 MCP server 对外长什么样」的参考。

资料核对于 2026-11-13。文中命令均在本机实际运行,失败与成功的输出都来自当次日志。mcp-publisher 版本为 1.8.9。

相关推荐
梦醒江南1 小时前
Agent 调工具报 504 之后:测试如何设计网络抖动下的幂等与补偿验证?
后端·agent·ai编程
Captaincc1 小时前
转译:《软件工程师现在该怎么办》
前端·后端·ai编程
浪浪山_大橙子1 小时前
被1.4 MB的射击游戏震撼后,我认真拆了一遍Fable的实现
ai编程·游戏开发·three.js
AI入职记1 小时前
本地 266MB 模型,追平大模型 API,还快 0.66 秒
后端·ai编程
ZhengEnCi4 小时前
Trae 的 .trae 目录到底怎么用:rules、commands、skills 三层机制与一棵典型目录树的落地拆解
ai编程
ZhengEnCi4 小时前
Agent 查不出代码 Bug 怎么办:一份带时间戳的调试日志与读日志排查流程
python·ai编程
ZzT4 小时前
装了太多 Skill 后 AI 开始「装瞎」?实测 Claude Code 与 Codex 的技能清单预算机制
ai编程·claude
码间留白5 小时前
从怀疑到真香——AI 重构代码后,我不再追求“最合适”,而是做好这两件事:测试和优化
单元测试·ai编程·代码质量·工程效率·ai重构代码
ClouGence5 小时前
开挂级 AI 玩法:一键复刻同款,生成能自动发布,省去所有部署
aigc·ai编程