MCP Registry mcp-publisher CLI 完全参考:从 init、login 到 publish、status 的源码级解析
【免费下载链接】registryA community driven registry service for Model Context Protocol (MCP) servers.项目地址: https://gitcode.com/GitHub_Trending/registry43/registry
mcp-publisher是 Model Context Protocol(MCP)注册表(MCP Registry)官方提供的发布者命令行工具,用于生成server.json元数据、完成身份认证、将 MCP 服务器发布到注册表并管理其生命周期状态。本文基于仓库中的命令参考文档 commands.md 逐条展开每个子命令的用法与参数,并结合 cmd/publisher/main.go、cmd/publisher/commands/ 与 cmd/publisher/auth/ 的源码实现,补充令牌交换、DNS/HTTP 域名认证签名、OIDC 受众(audience)派生等底层机制,帮助你在本地与 CI/CD 两种场景下稳定完成发布。
安装与全局选项
通过 Homebrew 安装(macOS/Linux):
$ brew install mcp-publisher全局选项方面:
- 所有命令支持
--help/-h查看帮助。在 入口文件 中,main()先做子命令分发,--help/-h对已有内置帮助文本的命令(如login、status)会先截获输出,未登记的命令则落回正常分发流程自行处理; --version(或-v、version)打印版本信息,其中Version、BuildTime、GitCommit三个变量在构建时通过 goreleaser 的 ldflags 注入(见 cmd/publisher/main.go)。
一个容易踩坑的点:--registry只是login的 flag(默认值https://registry.modelcontextprotocol.io,定义于 cmd/publisher/commands/login.go 的DefaultRegistryURL常量)。publish、validate、status等其他命令的注册表地址一律从存储的登录令牌中读取,因此给publish传--registry会被误解析为server.json的路径参数。从源码看,cmd/publisher/commands/publish.go 中第一个不以-开头的参数直接当作 server.json 文件路径使用。
mcp-publisher init:生成 server.json 模板
mcp-publisher initinit在当前目录生成server.json,非交互、不接受任何 flag,会自动探测环境并尽量预填字段,无法确定的字段写入TODO:占位符。文档给出的典型输出:
{ "name": "io.github.username/server-name", "description": "TODO: Add server description", "version": "1.0.0", "packages": [ { "registryType": "npm", "identifier": "detected-package-name", "version": "1.0.0" } ] }实际生成的模板比文档示例更完整:cmd/publisher/commands/init.go 中的createServerJSON还会写入当前$schema(model.CurrentSchemaURL)、repository(含source与可选的subfolder)以及一个示例环境变量(YOUR_API_KEY,标记为required+secret+string格式)。文件以0600权限写盘。
从源码可以还原出完整的自动探测优先级:
| 字段 | 探测顺序(init.go) |
|---|---|
| 服务器名称 | ①package.json的mcpName字段(存在即视为权威名称)→ ② GitHub git remote(io.github.{owner}/{repo},位于仓库子目录时取子目录名)→ ③ npmname字段(@org/package转换为io.github.org/package)→ ④ 回退com.example/{目录名} |
| 描述 | package.json的description,否则写入占位文案 |
| 版本 | package.json的version,否则默认1.0.0 |
| 仓库地址 | git remote get-url origin(SSH 形式git@github.com:会转换为 HTTPS),否则读取package.json的repository字段;git+前缀会被剥除 |
| 包管理器 | package.json存在 →npm;pyproject.toml/setup.py存在 →pypi;Dockerfile存在 →oci;均无则默认npm |
| 包标识符 | npm 取package.json的name,或从io.github.x/y名称反推@x/y;PyPI 从pyproject.toml简单提取name=行;OCI 使用docker.io/{image}:{tag}规范引用格式 |
注意两点行为细节:当前目录已存在server.json时init直接报错退出(init.go);npm 与 PyPI 包在模板中默认附带stdio传输方式,而 OCI 包的版本嵌在规范引用中、不单独设version字段(init.go)。
mcp-publisher login <method>:五种认证方式
login是唯一定义--registry的命令。所有方法都实现了 auth.Provider 接口(Login执行认证流程、GetToken获取令牌),成功后将令牌写入~/.config/mcp-publisher/token.json,内容包含三个字段:
{ "token": "jwt-token-here", "method": "github", "registry": "https://registry.modelcontextprotocol.io" }写入逻辑见 cmd/publisher/commands/login.go:目录以0700创建,令牌文件以0600写入。
GitHub 交互式认证
mcp-publisher login github [--token=PAT] [--registry=URL]- 打开浏览器走 GitHub OAuth 流程;
- 认证通过后授予
io.github.{username}/*与io.github.{org}/*命名空间的发布权限; --token以 GitHub Personal Access Token 代替交互式流程,这也是从 GitHub Actions 发布时无浏览器环境的认证方式。从源码看,--tokenflag 只在 method 为github时注册(login.go),其他方法传入会直接报未知 flag。
GitHub OIDC(CI/CD 场景)
mcp-publisher login github-oidc [--registry=URL]- 自动使用 GitHub Actions 的 OIDC 令牌,无需浏览器交互;
- 要求 workflow 中声明
id-token: write权限。
从 github-oidc.go 的实现可以确认完整链路:CLI 读取 GitHub Actions 注入的ACTIONS_ID_TOKEN_REQUEST_TOKEN与ACTIONS_ID_TOKEN_REQUEST_URL环境变量(缺失时分别给出明确的排查提示),向该端点请求 OIDC 令牌,再POST {registry}/v0/auth/github-oidc兑换注册表 JWT。
一个关键的兼容性约束:OIDC 的aud声明由--registry派生(取 scheme + host,例如https://registry.modelcontextprotocol.io),即令牌被绑定到具体部署。自托管方必须在注册表侧把MCP_REGISTRY_GITHUB_OIDC_AUDIENCE设置为相同值,否则使用旧版mcp-publisher的发布者会收到invalid audience错误,需要升级 CLI。另见 从 GitHub Actions 发布的指南。
DNS 域名认证
mcp-publisher login dns --domain=example.com --private-key=HEX_KEY [--algorithm=ed25519|ecdsap384] [--registry=URL]- 通过 DNS TXT 记录验证域名所有权,认证成功后授予
com.example.*命名空间; - 支持 Ed25519 私钥(64 位十六进制)或 ECDSA P-384 私钥(96 位十六进制);
--algorithm默认ed25519。使用 ECDSA P-384 密钥必须显式传--algorithm ecdsap384,否则密钥长度校验失败,报错invalid seed length: expected 32 bytes, got 48。这与 cmd/publisher/auth/common.go 中的实现一一对应:InProcessSigner对 ed25519 要求 32 字节 seed,对 P-384 要求 48 字节。
认证原理(对 DNS 与 HTTP 方式通用,实现于 cmd/publisher/auth/common.go):CLI 生成 RFC3339 UTC 时间戳并用私钥签名,然后POST {registry}/v0/auth/dns(或/v0/auth/http),请求体包含domain、timestamp、signed_timestamp(hex 编码的签名),注册表验证签名与域名下的公钥匹配后返回 JWT。签名过程中 CLI 会打印Expected proof record(形如v=MCPv1; k=ed25519; p=BASE64_PUBKEY),提示你将其配到 DNS/HTTPS。
Ed25519 设置步骤(推荐):
# 生成密钥对 openssl genpkey -algorithm Ed25519 -out key.pem # 提取公钥用于 DNS 记录 openssl pkey -in key.pem -pubout -outform DER | tail -c 32 | base64 # 添加 DNS TXT 记录: # example.com. IN TXT "v=MCPv1; k=ed25519; p=PUBLIC_KEY" # 提取登录用的私钥 openssl pkey -in key.pem -noout -text | grep -A3 "priv:" | tail -n +2 | tr -d ' :\n'ECDSA P-384 设置步骤:
# 生成密钥对 openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:secp384r1 -out key.pem # 提取公钥用于 DNS 记录 openssl ec -in key.pem -text -noout -conv_form compressed | grep -A4 "pub:" | tail -n +2 | tr -d ' :\n' | xxd -r -p | base64 # 添加 DNS TXT 记录: # example.com. IN TXT "v=MCPv1; k=ecdsap384; p=PUBLIC_KEY" # 提取登录用的私钥 openssl ec -in <pem path> -noout -text | grep -A4 "priv:" | tail -n +2 | tr -d ' :\n' # 登录时显式指定 ECDSA P-384 算法 mcp-publisher login dns --algorithm ecdsap384 --domain=example.com --private-key=HEX_KEYGoogle KMS 云签名(私钥不落本地)
需要本机安装并登录 gcloud CLI。在 cmd/publisher/auth/googlekms/ 中实现了 KMS 签名器;注意云端提供者会从密钥自身推导算法,因此--algorithm对云签名不适用。
# 登录并设置默认项目 gcloud auth login gcloud config set project myproject # 创建 keyring gcloud kms keyrings create mykeyring --location global # 创建 Ed25519 签名密钥 gcloud kms keys create mykey --default-algorithm=ec-sign-ed25519 --purpose=asymmetric-signing --keyring=mykeyring --location=global # 启用 Application Default Credentials (ADC),让 publisher 可以签名 gcloud auth application-default login # 先执行登录以显示公钥 mcp-publisher login dns google-kms --domain=example.com --resource=projects/myproject/locations/global/keyRings/mykeyring/cryptoKeys/mykey/cryptoKeyVersions/1 # 复制 "Expected proof record" 并添加 TXT 记录 # example.com. IN TXT "v=MCPv1; k=ed25519; p=PUBLIC_KEY" # 记录生效后重新执行登录 mcp-publisher login dns google-kms --domain=example.com --resource=projects/myproject/locations/global/keyRings/mykeyring/cryptoKeys/mykey/cryptoKeyVersions/1Azure Key Vault 云签名
需要本机安装并登录 Azure CLI。签名器实现在 cmd/publisher/auth/azurekeyvault/。
# 登录并设置默认订阅 az login az account set --subscription "My Subscription (name or ID)" # 创建资源组 az group create --location westus --resource-group MyResourceGroup # 创建 Key Vault az keyvault create --name MyKeyVault --location westus --resource-group MyResourceGroup # 创建 ECDSA P-384 签名密钥 az keyvault key create --name MyKey --vault-name MyKeyVault --curve P-384 # 先执行登录以显示公钥 mcp-publisher login dns azure-key-vault --domain=example.com --vault MyKeyVault --key MyKey # 复制 "Expected proof record" 并添加 TXT 记录 # example.com. IN TXT "v=MCPv1; k=ecdsap384; p=PUBLIC_KEY" # 记录生效后重新执行登录 mcp-publisher login dns azure-key-vault --domain=example.com --vault MyKeyVault --key MyKey从 cmd/publisher/commands/login.go 的 flag 解析可以看出:dns/http方法的第二个位置参数(azure-key-vault、google-kms)决定签名器类型,云签名模式下不再注册--private-key/--algorithm,取而代之的是--vault/--key或--resource。
HTTP 域名认证
mcp-publisher login http --domain=example.com --private-key=HEX_KEY [--algorithm=ed25519|ecdsap384] [--registry=URL]- 通过 HTTPS 端点验证域名所有权,认证成功后授予
com.example.*命名空间; - 密钥要求与 DNS 方式完全相同(含 ECDSA P-384 必须显式传
--algorithm ecdsap384的限制); - 与 DNS 的差异在于公钥托管位置:需要把证明记录放在
https://example.com/.well-known/mcp-registry-auth,内容为v=MCPv1; k=ed25519; p=PUBLIC_KEY(P-384 则k=ecdsap384):
# 生成密钥对(同 DNS 方式) openssl genpkey -algorithm Ed25519 -out key.pem # 在以下地址托管公钥: # https://example.com/.well-known/mcp-registry-auth # 内容: v=MCPv1; k=ed25519; p=PUBLIC_KEYHTTP 认证同样支持云签名,做法与 DNS 相同——把位置参数dns换成http即可。
Anonymous(仅本地测试)
mcp-publisher login none [--registry=URL]不做任何身份验证,仅适用于本地 registry 实例的测试场景。
mcp-publisher validate:发布前穷举式校验
mcp-publisher validate [file]- 参数
file为 server.json 路径,默认./server.json; - 进行穷举式校验,一次性报告所有问题而不只报第一个错误。
从实现看(cmd/publisher/commands/validate.go),validate并不在本地跑规则,而是把规范化后的 JSONPOST {registry}/v0/validate(registry 地址同样取自令牌文件,未登录时回退默认官方地址),由服务端返回校验结果。本地先做 JSON 语法解析与 Unicode 检查,然后服务端完成:
- JSON 语法与 schema 合规性检查;
- 语义校验(业务规则);
- 废弃 schema 版本检测,并给出迁移指引(
schema-field-required、schema-version-deprecated等 reference 会附带迁移清单链接,见 validate.go); - 每个问题包含 JSON 路径(如
packages[0].transport.url)、问题类型(json / schema / semantic / linter)与严重级别(error / warning / info)。
输出示例:
$ mcp-publisher validate ✅ server.json is valid $ mcp-publisher validate custom-server.json ❌ Validation failed with 2 issue(s): 1. [error] repository.url (schema) '' has invalid format 'uri' Reference: #/definitions/Repository/properties/url/format from: [#/definitions/ServerDetail]/properties/repository/[#/definitions/Repository]/properties/url/format 2. [error] name (semantic) server name must be in format 'dns-namespace/name' Reference: invalid-server-namemcp-publisher publish:发布到注册表
发布流程的详细指引见发布指南。
mcp-publisher publish [PATH]- 参数
PATH为 server.json 路径,默认./server.json。
完整处理流程(客户端 → 服务端):
- 客户端:读取并解析
server.json,执行 Unicode 校验; - 客户端:从令牌文件取出 token 与 registry 地址,
POST {registry}/v0/publish,携带Authorization: Bearer <token>头(见 cmd/publisher/commands/publish.go); - 服务端:校验 server.json 是否符合 官方注册表要求,并验证包所有权(package ownership);
- 服务端:检查命名空间认证(你的身份是否有该命名空间的发布权限);
- 服务端:写入注册表并返回
201 Created。
一个重要的错误处理细节:当服务端返回422时,CLI 会自动再调用/v0/validate端点,把详细的问题列表(含 JSON 路径与 reference)格式化后打印出来,而不是只给一行 422 报错(publish.go)。
# 基本发布 mcp-publisher publish # 指定文件位置 mcp-publisher publish ./config/server.json成功时输出形如✓ Successfully published及服务器名称与版本。
mcp-publisher status:更新已发布服务器的生命周期状态
mcp-publisher status --status <active|deprecated|deleted> [flags] <server-name> [version]| 标志 | 说明 |
|---|---|
--status(必填) | 新状态:active、deprecated、deleted |
--message | 解释状态变更的可选消息;状态为active时不允许提供 |
--all-versions | 将该状态变更应用于此服务器的所有版本 |
--yes/-y | 跳过确认提示(仅--all-versions时生效) |
位置参数:server-name为完整服务器名(如io.github.user/my-server);version在未设置--all-versions时必填。
状态语义:active表示服务器正常、出现在默认列表中;deprecated表示已弃用但仍可见并附带警告消息;deleted表示从默认列表中隐藏。
# 弃用某个特定版本 mcp-publisher status --status deprecated --message "Please upgrade to 2.0.0" \ io.github.user/my-server 1.0.0 # 删除存在安全问题的版本 mcp-publisher status --status deleted --message "Critical security vulnerability" \ io.github.user/my-server 1.0.0 # 恢复某版本为 active mcp-publisher status --status active io.github.user/my-server 1.0.0 # 一次性弃用所有版本 mcp-publisher status --status deprecated --all-versions --message "Project archived" \ io.github.user/my-server权限要求:必须以对该服务器命名空间拥有publish或edit权限的身份登录。
从 cmd/publisher/commands/status.go 看,单版本更新走PATCH {registry}/v0/servers/{name}/versions/{version}/status,全版本更新走PATCH {registry}/v0/servers/{name}/status,请求体为{"status": "...", "statusMessage": "..."}(消息为空时省略)。CLI 在变更前还会先GET ...?include_deleted=true拉取当前状态,打印1.0.0: active → deprecated形式的变更预览;--all-versions时列出全部版本并要求交互式确认(输入 y/yes 才继续),此时--yes可跳过。
mcp-publisher logout:清理本地凭据
mcp-publisher logout行为(实现见 cmd/publisher/commands/logout.go):
- 删除
~/.config/mcp-publisher/token.json; - 同时清理遗留令牌文件:
~/.mcp_publisher_token,以及历史版本遗留的$HOME与当前目录下的.mcpregistry_github_token、.mcpregistry_registry_token; - 不会在服务端吊销令牌——它只是本地清理,服务端 JWT 在过期前仍然有效。
未登录时执行会输出Not logged in并正常返回。
令牌存储与配置
认证令牌以 JSON 形式存储在~/.config/mcp-publisher/token.json:
{ "token": "jwt-token-here", "method": "github", "registry": "https://registry.modelcontextprotocol.io" }三个字段各自的用途在源码中清晰可辨:token用于后续publish/status/validate请求的 Bearer 认证(validate端点本身不需要鉴权,但registry字段仍被读取以确定目标地址,见 validate.go);method记录认证方式;registry记录登录时使用的注册表地址,是其他命令定位服务端唯一依据。
升级提示:旧版本将令牌存放在
~/.mcp_publisher_token。升级后若遇到not authenticated报错并看到 "token storage moved to ~/.config/mcp-publisher/" 的提示,执行mcp-publisher logout再mcp-publisher login即可完成迁移。
小结:一次完整发布的最小路径
综合以上各命令,发布一个 MCP 服务器的标准流程为:
mcp-publisher init # 生成并补全 server.json mcp-publisher validate # 发布前穷举校验 mcp-publisher login github # 或 dns / http / github-oidc mcp-publisher publish # POST /v0/publish mcp-publisher status --status deprecated --message "..." io.github.user/my-server 2.0.0 # 生命周期管理 mcp-publisher logout # 清理本地凭据本地自测可将login none指向自部署实例;CI 场景优先login github-oidc(免浏览器、令牌与部署绑定)。所有命令的默认注册表地址为https://registry.modelcontextprotocol.io,自托管部署请在login时通过--registry指定,并在服务端正确配置 OIDC 受众等对应项。
关键源码索引:命令分发 cmd/publisher/main.go;模板生成 cmd/publisher/commands/init.go;登录与令牌存储 cmd/publisher/commands/login.go;发布 cmd/publisher/commands/publish.go;校验 cmd/publisher/commands/validate.go;状态更新 cmd/publisher/commands/status.go;签名与令牌交换 cmd/publisher/auth/common.go;OIDC cmd/publisher/auth/github-oidc.go;DNS/HTTP 提供者 cmd/publisher/auth/dns.go。相关文档:发布指南、GitHub Actions 发布、官方注册表要求、server.json 规范。
【免费下载链接】registryA community driven registry service for Model Context Protocol (MCP) servers.项目地址: https://gitcode.com/GitHub_Trending/registry43/registry
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考