news 2026/9/16 21:43:00

MCP Registry mcp-publisher CLI 完全参考:从 init、login 到 publish、status 的源码级解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MCP Registry mcp-publisher CLI 完全参考:从 init、login 到 publish、status 的源码级解析

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对已有内置帮助文本的命令(如loginstatus)会先截获输出,未登记的命令则落回正常分发流程自行处理;
  • --version(或-vversion)打印版本信息,其中VersionBuildTimeGitCommit三个变量在构建时通过 goreleaser 的 ldflags 注入(见 cmd/publisher/main.go)。

一个容易踩坑的点:--registry只是login的 flag(默认值https://registry.modelcontextprotocol.io,定义于 cmd/publisher/commands/login.go 的DefaultRegistryURL常量)。publishvalidatestatus等其他命令的注册表地址一律从存储的登录令牌中读取,因此给publish--registry会被误解析为server.json的路径参数。从源码看,cmd/publisher/commands/publish.go 中第一个不以-开头的参数直接当作 server.json 文件路径使用。

mcp-publisher init:生成 server.json 模板

mcp-publisher init

init在当前目录生成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,标记为required+secret+string格式)。文件以0600权限写盘。

从源码可以还原出完整的自动探测优先级:

字段探测顺序(init.go)
服务器名称package.jsonmcpName字段(存在即视为权威名称)→ ② GitHub git remote(io.github.{owner}/{repo},位于仓库子目录时取子目录名)→ ③ npmname字段(@org/package转换为io.github.org/package)→ ④ 回退com.example/{目录名}
描述package.jsondescription,否则写入占位文案
版本package.jsonversion,否则默认1.0.0
仓库地址git remote get-url origin(SSH 形式git@github.com:会转换为 HTTPS),否则读取package.jsonrepository字段;git+前缀会被剥除
包管理器package.json存在 →npmpyproject.toml/setup.py存在 →pypiDockerfile存在 →oci;均无则默认npm
包标识符npm 取package.jsonname,或从io.github.x/y名称反推@x/y;PyPI 从pyproject.toml简单提取name=行;OCI 使用docker.io/{image}:{tag}规范引用格式

注意两点行为细节:当前目录已存在server.jsoninit直接报错退出(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_TOKENACTIONS_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),请求体包含domaintimestampsigned_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_KEY

Google 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/1

Azure 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-vaultgoogle-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_KEY

HTTP 认证同样支持云签名,做法与 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-requiredschema-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-name

mcp-publisher publish:发布到注册表

发布流程的详细指引见发布指南。

mcp-publisher publish [PATH]
  • 参数PATH为 server.json 路径,默认./server.json

完整处理流程(客户端 → 服务端):

  1. 客户端:读取并解析server.json,执行 Unicode 校验;
  2. 客户端:从令牌文件取出 token 与 registry 地址,POST {registry}/v0/publish,携带Authorization: Bearer <token>头(见 cmd/publisher/commands/publish.go);
  3. 服务端:校验 server.json 是否符合 官方注册表要求,并验证包所有权(package ownership);
  4. 服务端:检查命名空间认证(你的身份是否有该命名空间的发布权限);
  5. 服务端:写入注册表并返回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(必填)新状态:activedeprecateddeleted
--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

权限要求:必须以对该服务器命名空间拥有publishedit权限的身份登录。

从 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 logoutmcp-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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 21:41:06

PentAGI:本地部署个人AGI任务执行框架,实现多智能体与沙箱自动化

几个月前我在翻开源社区的时候&#xff0c;偶然看到 "PentAGI" 这个词。当时第一反应是&#xff0c;这又是个蹭 AGI 热度的玩具项目吧?但仔细扒了一下仓库和文档之后&#xff0c;我发现自己判断错了。PentAGI 不是那种套个壳、接个 API 就能聊天的 Demo&#xff0c;…

作者头像 李华
网站建设 2026/9/16 21:39:21

从零搭建RDMA网络通信架构:原理拆解与AI推理实战

我刚开始接触RDMA的时候&#xff0c;说实话&#xff0c;和大多数人的反应一样&#xff1a;这东西不就是个网卡嘛&#xff0c;能有啥了不起的&#xff1f;直到我真正上手&#xff0c;才意识到传统TCP/IP协议栈在高性能场景下的瓶颈有多明显。当我在AI推理集群里用RDMA把文本嵌入…

作者头像 李华
网站建设 2026/9/16 21:38:49

AI大模型时代职业机遇与转型指南

1. AI大模型时代的职业机遇解析2023年被称为AI大模型爆发元年&#xff0c;ChatGPT的横空出世彻底改变了技术行业的就业版图。我身边不少传统IT开发岗的朋友&#xff0c;通过系统学习大模型相关技能&#xff0c;半年内薪资涨幅普遍达到30%-50%。这个领域最显著的特征是&#xff…

作者头像 李华
网站建设 2026/9/16 21:38:41

网络隔离网闸配置实战:从原理到数据库同步的完整指南

说实话&#xff0c;第一次拿到网闸的时候&#xff0c;我自己也是愣了一下的。这设备和交换机、路由器完全不是一个画风&#xff0c;正面板上一排排网口有的标着“内”&#xff0c;有的标着“外”&#xff0c;中间还夹着一台像独立小主机的东西。后来才搞明白&#xff0c;网闸本…

作者头像 李华
网站建设 2026/9/16 21:37:37

Windows下Nmap安装与实战:从扫描到揪出陌生设备

那个周末下午&#xff0c;我在朋友家蹭饭&#xff0c;他忽然抱怨家里WiFi最近一到晚上就卡成PPT。我顺手打开笔记本&#xff0c;装了Nmap后对着他的网段扫了一圈&#xff0c;设备列表里赫然多了一台陌生的摄像头——家里压根没买过摄像头。用nmap -sV识别了一下&#xff0c;确认…

作者头像 李华