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/registrymcp-publisher是 Model Context ProtocolMCP注册表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还会写入当前$schemamodel.CurrentSchemaURL、repository含source与可选的subfolder以及一个示例环境变量YOUR_API_KEY标记为requiredsecretstring格式。文件以0600权限写盘。从源码可以还原出完整的自动探测优先级字段探测顺序init.go服务器名称①package.json的mcpName字段存在即视为权威名称→ ② GitHub git remoteio.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 originSSH 形式gitgithub.com:会转换为 HTTPS否则读取package.json的repository字段git前缀会被剥除包管理器package.json存在 →npmpyproject.toml/setup.py存在 →pypiDockerfile存在 →oci均无则默认npm包标识符npm 取package.json的name或从io.github.x/y名称反推x/yPyPI 从pyproject.toml简单提取name行OCI 使用docker.io/{image}:{tag}规范引用格式注意两点行为细节当前目录已存在server.json时init直接报错退出init.gonpm 与 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 [--tokenPAT] [--registryURL]打开浏览器走 GitHub OAuth 流程认证通过后授予io.github.{username}/*与io.github.{org}/*命名空间的发布权限--token以 GitHub Personal Access Token 代替交互式流程这也是从 GitHub Actions 发布时无浏览器环境的认证方式。从源码看--tokenflag 只在 method 为github时注册login.go其他方法传入会直接报未知 flag。GitHub OIDCCI/CD 场景mcp-publisher login github-oidc [--registryURL]自动使用 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 --domainexample.com --private-keyHEX_KEY [--algorithmed25519|ecdsap384] [--registryURL]通过 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.goCLI 生成 RFC3339 UTC 时间戳并用私钥签名然后POST {registry}/v0/auth/dns或/v0/auth/http请求体包含domain、timestamp、signed_timestamphex 编码的签名注册表验证签名与域名下的公钥匹配后返回 JWT。签名过程中 CLI 会打印Expected proof record形如vMCPv1; ked25519; pBASE64_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 vMCPv1; ked25519; pPUBLIC_KEY # 提取登录用的私钥 openssl pkey -in key.pem -noout -text | grep -A3 priv: | tail -n 2 | tr -d :\nECDSA 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 vMCPv1; kecdsap384; pPUBLIC_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 --domainexample.com --private-keyHEX_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-algorithmec-sign-ed25519 --purposeasymmetric-signing --keyringmykeyring --locationglobal # 启用 Application Default Credentials (ADC)让 publisher 可以签名 gcloud auth application-default login # 先执行登录以显示公钥 mcp-publisher login dns google-kms --domainexample.com --resourceprojects/myproject/locations/global/keyRings/mykeyring/cryptoKeys/mykey/cryptoKeyVersions/1 # 复制 Expected proof record 并添加 TXT 记录 # example.com. IN TXT vMCPv1; ked25519; pPUBLIC_KEY # 记录生效后重新执行登录 mcp-publisher login dns google-kms --domainexample.com --resourceprojects/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 --domainexample.com --vault MyKeyVault --key MyKey # 复制 Expected proof record 并添加 TXT 记录 # example.com. IN TXT vMCPv1; kecdsap384; pPUBLIC_KEY # 记录生效后重新执行登录 mcp-publisher login dns azure-key-vault --domainexample.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 --domainexample.com --private-keyHEX_KEY [--algorithmed25519|ecdsap384] [--registryURL]通过 HTTPS 端点验证域名所有权认证成功后授予com.example.*命名空间密钥要求与 DNS 方式完全相同含 ECDSA P-384 必须显式传--algorithm ecdsap384的限制与 DNS 的差异在于公钥托管位置需要把证明记录放在https://example.com/.well-known/mcp-registry-auth内容为vMCPv1; ked25519; pPUBLIC_KEYP-384 则kecdsap384# 生成密钥对同 DNS 方式 openssl genpkey -algorithm Ed25519 -out key.pem # 在以下地址托管公钥 # https://example.com/.well-known/mcp-registry-auth # 内容: vMCPv1; ked25519; pPUBLIC_KEYHTTP 认证同样支持云签名做法与 DNS 相同——把位置参数dns换成http即可。Anonymous仅本地测试mcp-publisher login none [--registryURL]不做任何身份验证仅适用于本地 registry 实例的测试场景。mcp-publisher validate发布前穷举式校验mcp-publisher validate [file]参数file为 server.json 路径默认./server.json进行穷举式校验一次性报告所有问题而不只报第一个错误。从实现看cmd/publisher/commands/validate.govalidate并不在本地跑规则而是把规范化后的 JSONPOST {registry}/v0/validateregistry 地址同样取自令牌文件未登录时回退默认官方地址由服务端返回校验结果。本地先做 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-serverversion在未设置--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_deletedtrue拉取当前状态打印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.gomethod记录认证方式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.goOIDC cmd/publisher/auth/github-oidc.goDNS/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),仅供参考