MCP Registryのパッケージ種別 — npm・PyPI・Docker対応の要件
MCP Registryが公式対応する6つのパッケージ形式と、種類ごとに異なる所有権証明の書き方をserver.jsonの実例で対比します。
MCP Registryは、公開されているMCPサーバーの所在情報を集約する公式リポジトリです。Rustで書いたサーバーの登録手順はRustでMCPサーバーを書く公式SDKの使い方にまとめています。対応するパッケージ形式はnpm・PyPI・NuGet・Cargo(Rust)・Docker/OCI・MCPBの6種類で、種類ごとにserver.jsonの書き方と所有権の証明方法が変わります。
この記事は、形式ごとの違いに加えて、証明文字列の書き方で起きる失敗と、server.jsonのスキーマが課している制約を扱います。
MCP Registryが担うのは配布ではなくメタデータ
MCP Registryは、npmやPyPIのようにコードそのものをホストしません。管理するのはメタデータだけです。Anthropic・GitHub・PulseMCP・Microsoftなど主要コントリビューターが支える、サーバーの所在情報を集めた台帳という位置付けです。
実体のコードは既存のパッケージレジストリに置いたまま、MCP Registryは「どのレジストリの、どのパッケージが、どのMCPサーバーに対応するか」という対応関係だけをserver.jsonという標準フォーマットで保持します。たとえばweather-mcpというnpmパッケージがあれば、MCP Registry側では「weather v1.2.0というサーバーはnpm:weather-mcpに対応する」という記録を持つだけです。コードの配布責任は元のレジストリ側に残ります。
MCP Registryはpreview段階にあり、一般提供(GA)前に破壊的変更やデータのリセットが起こりうると、各ドキュメントの冒頭に注記されています。登録した内容が消える可能性を織り込んで使う必要があります。
この構造のため、MCP Registryに公開する前に、実体のパッケージを既存レジストリ(npm・PyPI・crates.io等)へ先に公開しておく必要があります。クイックスタートも、npmへの公開をMCP Registryへの公開より前の手順に置いています。パッケージを持たず、URLだけで動くリモートサーバーの公開手順はリモートMCPサーバーをMCP Registryに公開する方法で扱っています。
公開できるのは、インストール方法が公開されているサーバー、または公開URLで到達できるリモートサーバーに限られます。社内ネットワーク限定のサーバーや、社内のプライベートレジストリ経由で配るパッケージは、MCP Registryの対象外です。
6つのパッケージ種別と対応レジストリの早見表
MCP Registryが対応するパッケージ種別は次の6つです。registryTypeの値ごとに、対応する実際のレジストリが決まっています。
| パッケージ種別 | registryType | 対応レジストリ | 所有権の証明方法 |
|---|---|---|---|
| npm | registryTypenpm | 対応レジストリregistry.npmjs.orgのみ | 所有権の証明方法package.jsonのmcpNameフィールド |
| PyPI | registryTypepypi | 対応レジストリpypi.orgのみ | 所有権の証明方法READMEに埋め込むmcp-name:文字列 |
| NuGet | registryTypenuget | 対応レジストリapi.nuget.orgのみ | 所有権の証明方法READMEに埋め込むmcp-name:文字列 |
| Cargo(Rust) | registryTypecargo | 対応レジストリcrates.ioのみ | 所有権の証明方法README内の可視なmcp-name:文字列 |
| Docker/OCI | registryTypeoci | 対応レジストリDocker Hub・ghcr.io・Google/Azure/Microsoftのコンテナレジストリ | 所有権の証明方法イメージの専用アノテーション |
| MCPB | registryTypemcpb | 対応レジストリGitHub/GitLabのリリースアセット | 所有権の証明方法URLへの"mcp"含有 + SHA-256ハッシュ明記 |
どの種別も、対応先は決まったレジストリに絞られています。npmならnpmjs.org以外のプライベートレジストリは対象外です。追加を望む場合は公式リポジトリでissueを起票する経路が案内されており、対応レジストリはコミュニティの需要に応じて今後増える可能性があると書かれています。
1つのサーバーに複数のパッケージを併記できます。packagesは配列で、バージョニングの解説にはnpmとNuGetを並べた例があります。このときサーバーのバージョンは全体のリリース番号として扱い、たとえばサーバー1.3.0がnpm 1.3.0とNuGet 1.0.0を束ねる形が許されます。複数レジストリを横断して検索する側の話はパッケージレジストリMCPサーバーが扱います。
公開は「パッケージ、証明、メタデータ」の順に進む
形式が違っても、公開の骨格は共通です。クイックスタートの手順を形式に依存しない部分だけ抜き出すと、次の流れになります。
MCP Registryへ公開するまでの流れ
- 1
パッケージを既存レジストリに公開する
npmなら
npm publish、PyPIならPyPIへのアップロードなど、元のレジストリの手順で先に公開します。 - 2
所有権の証明を埋め込む
形式ごとに埋め込み先が違います(次節以降)。
server.jsonのnameと完全に一致させます。 - 3
server.jsonを作る
mcp-publisher initで雛形を生成し、name・version・packagesを編集します。 - 4
認証して公開する
mcp-publisher login githubで認証し、mcp-publisher publishを実行します。
認証方式はサーバー名の形を決めます。GitHub認証ならio.github.ユーザー名/*、ドメイン認証なら自分のドメインを逆順にしたcom.example.*/*の形です。クイックスタートの切り分け表には、公開時の典型的な失敗が3つ載っています。
| 失敗時のメッセージ | 見る場所 |
|---|---|
| Registry validation failed for package | 見る場所パッケージ側の証明(mcpNameなど)が入っているか |
| Invalid or expired Registry JWT token | 見る場所mcp-publisher login githubで再認証 |
| You do not have permission to publish this server | 見る場所認証方式とサーバー名の形が合っているか |
1行目の失敗の多くは、形式ごとに証明の書き方が違うことから起きます。
npm・PyPI・NuGetの所有権証明は書き方が違う
3つとも「識別子をパッケージに埋め込む」方式ですが、埋め込み先と書式が異なります。
npmだけはpackage.jsonに専用フィールドを持ちます。
{
"name": "@username/email-integration-mcp",
"version": "1.0.0",
"mcpName": "io.github.username/email-integration-mcp"
}PyPIとNuGetにはpackage.jsonに相当する専用フィールドがありません。そのため、READMEにmcp-name: $SERVER_NAMEという文字列を埋め込みます。コメントの中に隠しても検証は通ります。
<!-- mcp-name: io.github.username/database-query-mcp -->この$SERVER_NAMEの部分は、server.jsonのnameフィールドと完全一致していなければなりません。PyPIでは、READMEがそのままパッケージの説明文になります。
Cargo対応で見落としやすい落とし穴
Cargoも同じmcp-name:方式を使いますが、挙動が1つだけ違います。crates.ioはMarkdown→HTML変換の過程でHTMLコメントを削除します。PyPIやNuGetで通用する<!-- mcp-name: ... -->という隠しコメントは、Cargoでは検証対象のHTMLに現れず、そのまま失敗します。
Cargo向けには、コメントではなく可視のMarkdownテキストとしてmcp-name:を書く必要があります。推奨されているのは、Linksセクションの箇条書きに含める書き方です。
- MCP Registry name: `mcp-name: io.github.username/widget-mcp`Cargoにはもう1つ特有の事情があります。cargo installはコンパイル済みバイナリを~/.cargo/binに配置する一度きりのインストール方式です。npmのnpx、PyPIのuvx、NuGetのdnx(.NET 10 SDK Preview 6以降)のような、実行のたびにレジストリへ取りに行く起動方式に相当するものがありません。インストールは1回、実行はバイナリ名指定という別モデルです。そのためCargo向けのserver.jsonサンプルにはruntimeHintを書きません。
スキーマ上、runtimeHintの例にはnpx・uvx・docker・dnxが並び、cargoは入っていません。
Rustの配布は、Cargoか、MCPBか
Rustで書いたサーバーには、どちらも正式な配布経路が2つあります。選ぶ基準は、利用者にRustツールチェーンを要求してよいかどうかです。
Rust製サーバーの2つの配布経路
Cargo
crates.io経由のソース配布で、利用者はcargo installのためにrustupが必要です。Rustの慣習に沿った出し方で、証明は可視のmcp-name:文字列です。
MCPB
GitHubやGitLabのリリースにビルド済みバイナリを置く方式です。利用者にツールチェーンは要りません。証明はURLとfileSha256で行います。
Cargoのネイティブ対応は、ソース配布を好むRust作者がMCPBのバイナリ梱包という回避策を強いられないために加えられたものです。どちらを選ぶかは作者に委ねられています。
Docker/OCIとMCPBの検証方法
Docker/OCIイメージは、対応レジストリの選択肢が5つに広がります。
- Docker Hub(
docker.io) - GitHub Container Registry(
ghcr.io) - Google Artifact Registry(
*.pkg.dev) - Azure Container Registry(
*.azurecr.io) - Microsoft Container Registry(
mcr.microsoft.com)
所有権の証明は、イメージのio.modelcontextprotocol.server.nameアノテーションにserver.jsonのnameと同じ値を入れる形です。Dockerfileでは次のラベル1行で書けます。
LABEL io.modelcontextprotocol.server.name="io.github.username/kubernetes-manager-mcp"OCI準拠のイメージなのでDockerに限らず、rootlessで動くPodman MCPサーバーの使い方からも同じイメージを起動できます。identifierの書式はレジストリ/名前空間/リポジトリ:タグで、タグの代わりにダイジェストを指定することもできます。
MCPBは他の5形式と性格が異なり、パッケージレジストリではなくGitHub・GitLabのリリースアセットとして配布します。手動で設定を書く従来の方法はClaude DesktopのMCP設定で扱っています。
検証は「URLに"mcp"の文字列を含む」ことと「fileSha256でSHA-256ハッシュを明記する」ことの2点です。URLの条件は、.mcpb拡張子でもリポジトリ名でも満たせます。MCPBの仕組みと拡張子の由来はDesktop Extensionsの解説記事で扱っています。
fileSha256は、コマンドの出力をそのまま貼れない
ハッシュはopensslで求められます。ところが出力をそのままserver.jsonに貼ると、スキーマの条件に合いません。server.jsonのスキーマでfileSha256は^[a-f0-9]{64}$という書式で、小文字16進の64文字だけが通ります。
OpenSSL 3.2.1で、ダミーのimage-processor.mcpbに対して実行した結果は次のとおりです。
openssl dgst -sha256 image-processor.mcpb
# SHA2-256(image-processor.mcpb)= af55c2be6c8c41d25e1ba032583aaa8d57bec87d3a51c4b8a4f567a2c56dc62b
shasum -a 256 image-processor.mcpb
# af55c2be6c8c41d25e1ba032583aaa8d57bec87d3a51c4b8a4f567a2c56dc62b image-processor.mcpbopenssl dgstの出力にはSHA2-256(ファイル名)= という接頭辞が付きます。この全体をfileSha256に入れると、スキーマの書式に合いません。必要なのは= より後ろの64文字だけです。接頭辞のないハッシュだけが欲しいときは、shasum -a 256の行頭の64文字を使う手もあります。
大文字で出力するツールの値を貼る場合も注意が要ります。スキーマの文字クラスはa-fの小文字のみなので、同じ値を大文字にすると書式に合いません。この正規表現に当てると、小文字の64文字だけが一致し、接頭辞付きの出力と大文字は不一致でした。
MCP Registryはこのハッシュの中身を検証しません。インストール時にMCPクライアント側がファイルの整合性を確認する仕組みです。スキーマの説明文も、正しいハッシュを生成する責任は書き手にあると述べています。
server.jsonのスキーマが決めている制約
所有権の証明以外にも、公開前に引っかかりやすい制約がスキーマに書かれています。2025-12-11版のスキーマから、読者の手元で効くものを拾います。
スキーマで先に確かめられる4点
サーバー名
形式は
名前空間/名前で、スラッシュはちょうど1つです。使える文字は英数字・ピリオド・ハイフンで、名前側にはアンダースコアも使えます。長さは3〜200文字です。description
必須項目で、最大100文字です。スキーマの注記は、実装の詳細ではなく機能を書くよう求めています。
パッケージのバージョン
versionを書く場合は具体的な版が必要で、latestと範囲指定(^1.2.3・1.xなど)は拒否されます。OCIとMCPBの公式例にはversionがありません。必須項目
サーバー側は
name・description・version、パッケージ側はregistryType・identifier・transportです。fileSha256はMCPBでのみ必須です。
registryTypeはスキーマ上は自由な文字列で、値の列挙は定義されていません。対応する種類はnpm・pypi・nuget・cargo・oci・mcpbの6つだけなので、綴りは自分で見直します。
サーバー名のpatternは^[a-zA-Z0-9.-]+/[a-zA-Z0-9._-]+$です。この式に当てると、io.github.username/email-integration-mcpは一致し、スラッシュが2つのio.github.username/a/bや、名前空間にアンダースコアを含むio.github.user_name/xは一致しません。
公開後に変えられないことを先に知っておく
公開してから直せるものは多くありません。バージョニングの解説とFAQの内容を、公開前に決めておくべき順に並べると次のとおりです。
- 同じバージョン文字列で2回は公開できず、公開済みのバージョンのメタデータは変更できません(npmと同様の扱い)。
- メタデータを直すには、新しい一意のバージョン文字列で
server.jsonを出し直します。 - 公開者が付けた独自メタデータ(
_meta配下のpublisher-provided)は保持されますが、上限は4KB(JSONで4096バイト)で、超えると公開に失敗します。 - 公開したサーバーの削除・非公開は、FAQで「現状では不可」とされ、議論が続いている段階です。
バージョン文字列は、セマンティックバージョニングが推奨されます。範囲指定に見える文字列(^1.2.3・~1.2.3・>=1.2.3・1.x・1.2.*など)は誤指定の防止策として禁止されています。一方、日付形式の2025-06-18やv1.0のような非セマンティックな文字列は許可されます。
許可されるとはいえ、落とし穴があります。セマンティックなバージョンで公開してきたサーバーが、あとから非セマンティックな文字列で公開すると、並び順にかかわらずその新しい方が「latest」と扱われます。バージョン文字列の解析に失敗した場合も、そのバージョンは常に「latest」として扱われます。日付形式では、2025.6.18がセマンティック、2025.06.18が非セマンティックの扱いで、どちらも解説では注意(Caution)付きです。
パッケージ側は変わらず、レジストリのメタデータだけ直したい場合は、プレリリースを使う方法が案内されています。たとえばパッケージが1.2.3のまま、サーバー側を1.2.3-1として出します。ただし、プレリリースはセマンティックバージョニングの規則で通常版より前に並びます。1.2.3を出したあとに1.2.3-1を出しても、後者は「latest」になりません。公開の順序を取り違えないようにします。詳しい運用はMCP Registryのバージョニングルールにあります。
タグとダイジェスト、どちらで固定するか
OCIイメージのidentifierはレジストリ/名前空間/リポジトリ:タグという書式ですが、タグ部分はダイジェスト(sha256ハッシュ)に置き換えられます。1.0.0のようなタグは、公開後に元のレジストリ側で別のイメージへ付け替えられる余地が残ります。再現性を優先するなら、ダイジェストで固定する選択肢があります。
ダイジェストは人間が読んで版数を判断できないため、タグとの対応は別の場所に控えておく運用が一般的です。
npmとPyPIのidentifierにも書式の違いがあります。npmはスコープ付きパッケージ名(@username/package-name)をそのまま使えます。PyPIにはスコープの概念がなく、パッケージ名がPyPI全体で1つの名前空間を共有します。
Anthropic Connectors Directoryとの違い
パッケージ種別を調べる過程で混同しやすいのが、Anthropicが運営するConnectors Directoryとの違いです。両者は別の窓口で、掲載の手順も別です。
MCP Registryは、MCPクライアントのアプリが直接読む想定ではありません。ドキュメントによれば、主な読み手は下流のアグリゲーター(MCPサーバーのマーケットプレイスなど)です。レジストリのメタデータは意図的に意見を持たない形で、評価の付与や選別はアグリゲーター側が担います。ホストアプリは、アグリゲーターが公開するREST API経由で参照する形が想定されています。
この違いから、MCP Registryへの登録は、下流のカタログに載るための元データを整える作業だと言えます。Claude製品内での掲載を目指す場合は、Connectors Directoryの手順を別に調べる必要があります。
6種類に分かれているのはなぜか
6種類はどれも、各レジストリの既存の配布経路を使う構成です。MCP Registryが持つのは、それらのパッケージを指すメタデータだけです。
セキュリティスキャンも、MCP Registry自身は実施しません。npmやPyPI・Docker Hubといった元のレジストリの検査機能と、下流のアグリゲーターに委ねています。MCP Registryが引き受けるのは、名前空間の認証とメタデータのホスティングです。
配布とセキュリティスキャンは既存のレジストリに任せ、名前空間の認証とメタデータの保持はMCP Registryが担う分担です。パッケージ側の所有権証明は、サーバー名が自分のパッケージに結びついていることを示す、名前空間の認証とは別の確認です。
まとめ
形式ごとの差で事故になりやすいのは、隠しコメントが通る形式と通らない形式があることと、ハッシュの書式が形式ごとに違うことの2点です。公開後は直せないため、最初のserver.jsonでnameとバージョンの方針を固めてから出す流れになります。パッケージを持たないリモートサーバーの公開は、前段で触れた記事で扱っています。