布附加驗(yàn)證規(guī)則:server.json 在 registry 源碼中的落地實(shí)現(xiàn))
MCP 官方 Registry 發(fā)布附加驗(yàn)證規(guī)則server.json 在 registry 源碼中的落地實(shí)現(xiàn)【免費(fèi)下載鏈接】registryA community driven registry service for Model Context Protocol (MCP) servers.項(xiàng)目地址: https://gitcode.com/GitHub_Trending/registry43/registry本文基于官方 Registry 的server.json附加要求文檔完整講解發(fā)布到官方 MCP Registryregistry.modelcontextprotocol.io時(shí)在通用server.json規(guī)范之上額外施加的四類驗(yàn)證命名空間鑒權(quán)、包歸屬驗(yàn)證、受限的 Registry Base URL 白名單以及_meta命名空間限制。同時(shí)結(jié)合 registry 倉(cāng)庫(kù)源碼說(shuō)明每條規(guī)則在驗(yàn)證器與鑒權(quán)處理函數(shù)中的具體實(shí)現(xiàn)位置與錯(cuò)誤語(yǔ)義幫助你在發(fā)布前預(yù)檢問題、準(zhǔn)確理解發(fā)布失敗信息??傆[官方 Registry 在通用規(guī)范之上做了什么通用server.json格式見 server.json 格式規(guī)范定義了基礎(chǔ)字段與結(jié)構(gòu)校驗(yàn)而官方 Registry 在此基礎(chǔ)上追加了四類強(qiáng)制約束目的是保證命名空間鑒權(quán)Namespace authenticationServer 只能發(fā)布到發(fā)布者實(shí)際擁有的命名空間之下包歸屬驗(yàn)證Package ownership verification發(fā)布者必須能證明其確實(shí)擁有所引用的包防止冒名受限的 Registry Base URL包必須來(lái)自受信任的公共 Registry私有源與第三方鏡像不被允許_meta命名空間限制_meta對(duì)象中僅publisher相關(guān)鍵的數(shù)據(jù)會(huì)被保留其余鍵在發(fā)布時(shí)被靜默丟棄。從源碼結(jié)構(gòu)看這四類約束分別落在不同模塊server 名稱格式由 parseServerName 強(qiáng)制包歸屬與 Base URL 白名單由internal/validators/registries/下的各驗(yàn)證器執(zhí)行_meta大小限制由 validatePublisherExtensions 執(zhí)行命名空間所有權(quán)證明由internal/api/handlers/v0/auth/下的各類鑒權(quán)端點(diǎn)完成。命名空間鑒權(quán)證明你擁有該命名空間發(fā)布者必須證明其擁有對(duì)應(yīng)命名空間。例如要發(fā)布到com.example/server發(fā)布者必須證明其擁有example.com域名。從源碼可以確認(rèn) server 名稱的硬性格式name字段必須形如dns-namespace/name恰好包含一個(gè)/且匹配正則^[a-zA-Z0-9.-]/[a-zA-Z0-9._-]$長(zhǎng)度 3200定義在 ServerJSON 類型的 JSON Schema 標(biāo)簽與 parseServerName 中。命名空間部分只能以字母數(shù)字開頭和結(jié)尾、中間可含點(diǎn)與連字符name 部分額外允許下劃線。格式不合法時(shí)驗(yàn)證器會(huì)給出精確到是 namespace 還是 name 部分非法的錯(cuò)誤提示。Registry 提供了多種命名空間所有權(quán)證明途徑對(duì)應(yīng) 鑒權(quán)實(shí)現(xiàn)目錄 下的不同端點(diǎn)DNS 命名空間通過(guò)解析域名 TXT 記錄完成挑戰(zhàn)驗(yàn)證。DNSAuthHandler 通過(guò)DNSResolver.LookupTXT查詢 DNS TXT 記錄注冊(cè)了exchange-dns-token令牌交換端點(diǎn)GitHub 命名空間如io.github.user通過(guò) GitHub App 訪問令牌或 OIDC 流程證明倉(cāng)庫(kù)/組織歸屬對(duì)應(yīng) github_at.go 與 github_oidc.go此外還有基于 HTTP 挑戰(zhàn)http.go、OIDCoidc.go與無(wú)鑒權(quán)測(cè)試模式none.go等實(shí)現(xiàn)便于自建 Registry 時(shí)按環(huán)境選擇鑒權(quán)后端。具體的 GitHub 與域名命名空間的逐步認(rèn)證操作見 發(fā)布指南。包歸屬驗(yàn)證每種包類型都有明確的所有權(quán)憑證所有包都必須攜帶能證明發(fā)布者擁有它的元數(shù)據(jù)。這一機(jī)制防止有人把別人的包綁定到自己控制的 server 記錄上。上游項(xiàng)目對(duì)此的安全動(dòng)機(jī)在 registry 項(xiàng)目 issue #96 中有專門討論。各 Registry 類型的具體驗(yàn)證要求詳見 包類型文檔每種 registry 都有 Ownership Verification 一節(jié)。從本倉(cāng)庫(kù)源碼可以印證各類型的驗(yàn)證手段Registry 類型所有權(quán)憑證源碼位置NPM包的package.json元數(shù)據(jù)中必須有mcpName字段且取值與 server name 完全一致ValidateNPMPyPI包的 descriptionREADME中必須包含mcp-name: server-name令牌pypi.goNuGet包的 README 中必須包含mcp-name: server-name令牌nuget.goCargocrates.io 上該版本的渲染 README 中必須包含mcp-name: server-name令牌cargo.goOCI/Docker鏡像標(biāo)簽labelio.modelcontextprotocol.server.name必須等于 server nameValidateOCIMCPB僅允許 GitHub / GitLab Releases 下載鏈接mcpb.go幾個(gè)源碼層面的實(shí)用細(xì)節(jié)NPM 的mcpName必須精確匹配。validateNPMPackage 會(huì)請(qǐng)求{baseURL}/{identifier}/{version}元數(shù)據(jù)端點(diǎn)缺失mcpName時(shí)錯(cuò)誤信息會(huì)直接告訴你該往package.json加什么NPM package %s is missing required mcpName field. Add this to your package.json: \mcpName\: \%s\。取值不匹配時(shí)則報(bào)ownership validation failed. Expected mcpName ... got ...。NPM 對(duì) 404 做了精細(xì)區(qū)分。當(dāng)版本元數(shù)據(jù)返回 404 時(shí)npmVersion404Error 會(huì)用 HEAD 請(qǐng)求探測(cè)包級(jí)端點(diǎn)區(qū)分包不存在、包存在但版本尚未同步新發(fā)布可能有傳播延遲與上游瞬時(shí)故障429/5xx三種情況給出可操作的重試建議而不是籠統(tǒng)地報(bào)未找到。README 令牌采用邊界錨定匹配。PyPI/NuGet/Cargo 的mcp-name:令牌必須后接空格、換行或 HTML 標(biāo)簽等邊界如果令牌后面緊貼了其他字符比如mcp-name: foo與你要的mcp-name: food混淆錯(cuò)誤信息會(huì)明確指出請(qǐng)放到單獨(dú)一行并重新發(fā)布見 nuget.go、cargo.go。OCI 驗(yàn)證失敗是失敗關(guān)閉fail closed。由于io.modelcontextprotocol.server.name標(biāo)簽是官方 Registry 對(duì) OCI 包唯一的歸屬憑證ValidateOCI 在遇到 429 限流時(shí)不會(huì)放行而是返回可重試錯(cuò)誤私有鏡像401/403會(huì)明確提示僅支持公共鏡像。OCI 包的字段約束identifier必須是規(guī)范引用如docker.io/owner/image:1.0.0不允許再帶registryBaseUrl、version或fileSha256字段版本信息包含在identifier中tag 或sha256:digest 均可。包級(jí)驗(yàn)證在EnableRegistryValidation配置開啟時(shí)執(zhí)行入口是 ValidatePublishRequest它先做_meta擴(kuò)展校驗(yàn)再對(duì)packages數(shù)組逐包調(diào)用ValidatePackage任一包失敗即整體失敗錯(cuò)誤信息會(huì)帶上包序號(hào)與 identifier。受限的 Registry Base URL只允許受信任的公共源官方 Registry 只接受受信任的公共 Registry私有 Registry 與替代鏡像一律拒絕。支持的清單如下Registry 類型允許值NPM僅https://registry.npmjs.orgPyPI僅https://pypi.orgNuGet僅https://api.nuget.org/v3/index.jsonCargo僅https://crates.ioDocker/OCIDocker Hubdocker.io、GitHub Container Registryghcr.io、Quay.ioquay.io、Google Artifact Registry*.pkg.dev、Azure Container Registry*.azurecr.io、Microsoft Container Registrymcr.microsoft.comMCPB僅https://github.com與https://gitlab.com的 Releases 下載鏈接源碼層面的印證固定的 Base URL 常量集中定義在 pkg/model/constants.goRegistryURLNPM、RegistryURLPyPI、RegistryURLNuGet、RegistryURLCrates、RegistryURLGitHub、RegistryURLGitLab等。以 NPM 為例ValidateNPM 要求registryBaseUrl與https://registry.npmjs.org完全相等否則返回registry type and base URL do not match錯(cuò)誤該錯(cuò)誤定義于 constants.go。OCI 的白名單是唯一的域名集合型規(guī)則實(shí)現(xiàn)在 allowedOCIRegistries 與 isAllowedRegistry精確匹配docker.io、registry-1.docker.io、index.docker.ioDocker Hub 的 API 端點(diǎn)別名、ghcr.io、quay.io、mcr.microsoft.com外加兩個(gè)通配后綴*.pkg.devGoogle Artifact Registry與*.azurecr.ioAzure Container Registry。單元測(cè)試 oci_test.go 覆蓋了通配主機(jī)如myregistry.azurecr.io、us-west1-docker.pkg.dev/...與固定主機(jī)的放行行為。不在白名單內(nèi)的 registry 會(huì)返回unsupported OCI registry錯(cuò)誤。_meta命名空間限制只保留 publisher-provided 數(shù)據(jù)server.json中的_meta字段允許發(fā)布者攜帶自定義元數(shù)據(jù)但發(fā)布到官方 Registry 時(shí)有嚴(yán)格限制只有io.modelcontextprotocol.registry/publisher-provided鍵之下的數(shù)據(jù)會(huì)被保留_meta對(duì)象中的任何其他鍵都會(huì)在發(fā)布時(shí)被靜默丟棄——既不存儲(chǔ)也不會(huì)在 API 中返回。對(duì)應(yīng)地ServerMeta 類型 中_meta只有一個(gè)PublisherProvided字段JSON 標(biāo)簽即為io.modelcontextprotocol.registry/publisher-provided這從數(shù)據(jù)結(jié)構(gòu)層面保證了其他鍵根本無(wú)法進(jìn)入存儲(chǔ)。示例{ _meta: { io.modelcontextprotocol.registry/publisher-provided: { tool: ci-publisher, version: 1.0.0, custom_data: your data here }, some.other.key: { // 該鍵會(huì)被丟棄不會(huì)被保留 } } }大小限制publisher-provided 擴(kuò)展的序列化 JSON 上限為4KB4096 字節(jié)超限會(huì)導(dǎo)致發(fā)布失敗錯(cuò)誤信息中會(huì)給出實(shí)際字節(jié)數(shù)。該限制由 validatePublisherExtensions 實(shí)現(xiàn)錯(cuò)誤消息格式為_meta.io.modelcontextprotocol.registry/publisher-provided extension exceeds 4KB limit (%d bytes)推薦做法按反向域名做子命名空間當(dāng)publisher-provided元數(shù)據(jù)變大、或來(lái)自多個(gè)來(lái)源例如 GitHub 專屬提示加上自家 CI 工具的元數(shù)據(jù)時(shí)按反向 DNS 子鍵分組是避免鍵沖突的實(shí)用慣例{ _meta: { io.modelcontextprotocol.registry/publisher-provided: { com.github: { serverDisplayName: My Server }, io.example.ci-publisher: { tool: ci-publisher, version: 1.0.0 } } } }需要說(shuō)明的是該慣例不被強(qiáng)制。簡(jiǎn)單場(chǎng)景下扁平鍵完全可以倉(cāng)庫(kù)內(nèi)的既有示例也使用扁平形式只有當(dāng)元數(shù)據(jù)來(lái)自多個(gè)來(lái)源時(shí)才建議改用命名空間子鍵形式。注意區(qū)分server.json的_meta與 API 響應(yīng)中的_metaserver.json里的_meta與 Registry API 響應(yīng)返回的_meta是兩個(gè)不同的東西server.json中_meta包含發(fā)布者自定義元數(shù)據(jù)位于io.modelcontextprotocol.registry/publisher-provided之下API 響應(yīng)中_meta是響應(yīng)級(jí)別的獨(dú)立屬性不在server.json內(nèi)部承載 Registry 托管的元數(shù)據(jù)包括status生命周期狀態(tài)active、deprecated、deleted、publishedAt首次發(fā)布時(shí)間、updatedAt最近更新時(shí)間、isLatest是否為最新版本。你發(fā)布的內(nèi)容server.json{ name: io.github.example/my-server, version: 1.0.0, description: My MCP server, // ... 其他字段 ... _meta: { io.modelcontextprotocol.registry/publisher-provided: { tool: ci-publisher, version: 2.0.0 } } }Registry API 返回的內(nèi)容{ server: { name: io.github.example/my-server, version: 1.0.0, description: My MCP server, // ... 其他字段 ... _meta: { io.modelcontextprotocol.registry/publisher-provided: { tool: ci-publisher, version: 2.0.0 } } }, _meta: { // 響應(yīng)級(jí)別的 Registry 托管元數(shù)據(jù) status: active, publishedAt: 2024-01-15T10:30:00Z, updatedAt: 2024-01-15T10:30:00Z, isLatest: true } }可以看到 API 響應(yīng)中存在兩個(gè)_meta一個(gè)在server對(duì)象內(nèi)部從 server.json 原樣保留的發(fā)布者數(shù)據(jù)另一個(gè)在響應(yīng)級(jí)別Registry 自動(dòng)添加的托管元數(shù)據(jù)。Registry 托管元數(shù)據(jù)無(wú)法被發(fā)布者設(shè)置或覆蓋。從源碼可以確認(rèn)這一點(diǎn)ServerResponse 的結(jié)構(gòu)正是server內(nèi)含 ServerMeta加上響應(yīng)級(jí)Meta而后者實(shí)際包裝的是 RegistryExtensionsstatus/statusChangedAt/statusMessage/publishedAt/updatedAt/isLatestJSON 鍵為io.modelcontextprotocol.registry/official。完整的響應(yīng)結(jié)構(gòu)參見 官方 Registry API 文檔 與 OpenAPI 定義。如何在發(fā)布前自查結(jié)合上述規(guī)則發(fā)布前可以用倉(cāng)庫(kù)自帶工具鏈自查用 server.schema.json當(dāng)前版本日期為2025-12-11見 constants.go對(duì)server.json做結(jié)構(gòu)校驗(yàn)倉(cāng)庫(kù)提供了 validate-schemas.sh 等腳本用于校驗(yàn) schema 本身。檢查各包的所有權(quán)憑證是否就位NPM 包在package.json中加mcpNamePyPI/NuGet/Cargo 包在 README 中加獨(dú)立一行的mcp-name: server-name令牌OCI 鏡像在 Dockerfile 中加LABEL io.modelcontextprotocol.server.nameserver-name驗(yàn)證器在缺失時(shí)會(huì)在錯(cuò)誤信息中直接給出對(duì)應(yīng)的 LABEL 寫法。確認(rèn)registryBaseUrl在上表白名單內(nèi)、OCI 包未誤用registryBaseUrl/version字段??刂芲meta中publisher-provided的序列化體積在 4096 字節(jié)以內(nèi)。發(fā)布流程的命令行操作validate/publish等子命令見 發(fā)布指南 與 CLI 參考集成測(cè)試 tests/integration/main.go 中對(duì)publisher-provided元數(shù)據(jù)的逐鍵比對(duì)可作為發(fā)布后數(shù)據(jù)是否原樣保留的驗(yàn)收參考。小結(jié)官方 Registry 的附加驗(yàn)證可以概括為命名空間靠 DNS/GitHub 等所有權(quán)證明把關(guān)包靠各 Registry 的原生元數(shù)據(jù)憑證mcpName、README 中的mcp-name:令牌、OCI label綁定歸屬包源靠固定白名單收斂到受信任的公共 Registry_meta靠單一保留鍵加 4KB 上限控制體積。這些規(guī)則在 validators、registries 驗(yàn)證器 與 auth 處理函數(shù) 中均有可核對(duì)的實(shí)現(xiàn)遇到發(fā)布失敗時(shí)對(duì)照錯(cuò)誤信息中給出的具體字段與期望值如期望的mcpName、期望的 LABEL 寫法修正后重新發(fā)布即可?!久赓M(fèi)下載鏈接】registryA community driven registry service for Model Context Protocol (MCP) servers.項(xiàng)目地址: https://gitcode.com/GitHub_Trending/registry43/registry創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考