server.jsonの書き方 — MCP Registry公開用メタデータ形式
MCP Registryに公開するserver.jsonの必須項目・6種類のパッケージ形式・バージョン文字列のルールを、公式スキーマとサンプルで解説します。
server.jsonとは何を書くファイルか
server.json は、MCPの公式サーバーカタログであるMCP Registryにサーバーを登録するための標準メタデータファイルです。サーバーの一意な名前・説明・バージョン・実体の所在(npmパッケージなのかリモートURLなのか)・起動方法をこの1ファイルにまとめ、mcp-publisher というCLIツールで登録します。
前提環境はシンプルです。Node.js(TypeScript製サーバーの場合)、公開先のパッケージレジストリ(npmなど)のアカウント、そしてMCP Registryへの認証手段(GitHubアカウントまたは所有ドメイン)の3つがあれば始められます。認証方式の選び方はMCP Registryの認証方式3種で扱い、本記事は server.json の書き方に絞ります。
最小構成のserver.jsonを書く
mcp-publisher init コマンドを実行すると、プロジェクトの情報からテンプレートを自動生成できます。
mcp-publisher init生成される最小構成は次のような形です。
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.my-username/weather",
"description": "An MCP server for weather information.",
"repository": {
"url": "https://github.com/my-username/mcp-weather-server",
"source": "github"
},
"version": "1.0.1",
"packages": [
{
"registryType": "npm",
"identifier": "@my-username/mcp-weather-server",
"version": "1.0.1",
"transport": {
"type": "stdio"
}
}
]
}先頭の $schema フィールドは、このファイルがどのバージョンのスキーマに準拠しているかを示す識別子です。エディタや検証ツールがこの値を見て、フィールド名の綴りミスや型の不一致をその場で警告してくれます。書き忘れても公開自体は通ることがありますが、書いておいたほうが編集中のミスに早く気づけます。
必須フィールドは name(サーバーの一意名)・description(説明文)・version(サーバーのバージョン)・packages または remotes(実体の所在)の4系統です。name はGitHub認証を使うなら io.github.username/*、ドメイン認証を使うなら自分のドメインの逆引きDNS形式(com.example.*/*)で始める必要があります。この命名ルールと認証方式の対応は、公開前に必ず確認しておく価値があります。
name のほかに、人間が読む表示名として title フィールドを分けて持たせることもできます。name は名前空間を含む一意識別子(io.github.username/weather のような形)で変更できませんが、title は「Weather」のような自由な表示名にでき、後から変更しても構いません。検索結果やマーケットプレイスの一覧に出る名前は、多くの場合この title です。
環境変数が必要なサーバーは、packages 配下の environmentVariables に列挙します。各項目は name(変数名)・description(説明)・isRequired(必須かどうか)・isSecret(APIキーのような秘匿情報かどうか)・format(文字列かどうかの型情報)の5つを持てます。isSecret: true を付けておくと、ダウンストリームのマーケットプレイスがインストール時に入力欄をマスク表示するなど、値の扱いを変える手がかりになります。
npmパッケージとして配布する場合は、package.json 側にも mcpName プロパティを追加します。この値は server.json の name と完全に一致していなければなりません。
{
"name": "@my-username/mcp-weather-server",
"version": "1.0.1",
+ "mcpName": "io.github.my-username/weather",
"main": "index.js",パッケージ種別ごとに書き方が変わる
MCP Registryは6種類のパッケージ形式に対応しています。registryType の値と、所有権の確認方法がそれぞれ違います。
| registryType | 対応レジストリ | 所有権の確認方法 |
|---|---|---|
npm | 対応レジストリnpm公式レジストリのみ | 所有権の確認方法package.json の mcpName プロパティ |
pypi | 対応レジストリPyPI公式のみ | 所有権の確認方法READMEに mcp-name: $SERVER_NAME の文字列 |
nuget | 対応レジストリNuGet公式のみ | 所有権の確認方法READMEに mcp-name: $SERVER_NAME の文字列 |
cargo | 対応レジストリcrates.io | 所有権の確認方法READMEに可視なMarkdownテキストで mcp-name: (HTMLコメントはcrates.ioがレンダリング時に除去するため不可) |
oci | 対応レジストリDocker Hub / GHCR / 主要クラウドのコンテナレジストリ | 所有権の確認方法Dockerfileの io.modelcontextprotocol.server.name ラベル |
mcpb | 対応レジストリGitHub / GitLabリリース経由の実行バイナリ | 所有権の確認方法配布URLに"mcp"の文字列を含む + fileSha256 によるハッシュ明記 |
oci の例を見てみます。
{
"packages": [
{
"registryType": "oci",
"identifier": "docker.io/yourusername/kubernetes-manager-mcp:1.0.0",
"transport": {
"type": "stdio"
}
}
]
}identifier の形式は レジストリ/名前空間/リポジトリ:タグ です。タグの代わりにダイジェスト指定も使えます。
mcpb パッケージだけは他の5種と違い、MCP Registry自身がハッシュを検証しません。検証するのはMCPクライアント側です。公開者は openssl dgst -sha256 で算出したSHA-256ハッシュを fileSha256 に必ず含める必要があります。ここを省略すると、登録自体は通ってもクライアント側でのインストール時に失敗します。
Rustサーバーを作る場合、cargo(ソース配布・利用者にRustツールチェーンが必要)と mcpb(ビルド済みバイナリ配布・ツールチェーン不要)という2つの選択肢があります。どちらもファーストクラスの対応で、優劣ではなく配布方針の違いです。
Filesystem MCPサーバーのように @modelcontextprotocol/server-filesystem としてnpm配布されているサーバーは、ここまでの npm 形式の例とほぼ同じ構造を持っています。一方、GitHub MCPサーバーはnpm配布ではなく、GitHubホストのリモートサーバーとDockerイメージ(ghcr.io/github/github-mcp-server)で提供されており、後述の remotes または oci の書き方に該当します。配布形態はサーバーごとに異なるため、自分のサーバーがどの形式に当たるかをまず確認してください。
リモートサーバーの場合はpackagesでなくremotesを使う
ローカルで実行するサーバーではなく、HTTPエンドポイントとして提供するリモートサーバーの場合は、packages の代わりに remotes フィールドを使います。
{
"name": "com.example/acme-analytics",
"version": "2.0.0",
"remotes": [
{
"type": "streamable-http",
"url": "https://analytics.example.com/mcp"
}
]
}type には streamable-http または sse を指定します。SSE(Server-Sent Events)方式は非推奨(deprecated)のため、既存クライアントとの互換性維持が目的でない限り streamable-http を選びます。両方式を別URLで同時提供することも可能です。リモートサーバーは、指定したURLで公開アクセス可能であることが必須です。社内限定のエンドポイントは登録できません。
リモートサーバーをマルチテナントで提供する場合、URLに {変数名} 形式のテンプレート変数を埋め込めます。たとえばテナントごとに異なるサブドメインを割り当てているSaaSなら、https://{tenant}.example.com/mcp のような形でURLを1つのエントリにまとめられます。利用者はサーバーを追加する際に、この変数部分を自分のテナント名で埋めて接続します。1テナントにつき1エントリを書く必要がなくなる分、server.json の見通しがよくなります。
APIキーなどの認証情報をMCPクライアント側に送らせたい場合は、remotes エントリに headers プロパティを追加します。name(ヘッダー名)・description・isRequired・isSecret を項目ごとに指定でき、isSecret: true を付けた項目はクライアント側で入力欄がマスク表示の対象になります。
{
"remotes": [
{
"type": "streamable-http",
"url": "https://analytics.example.com/mcp",
"headers": [
{
"name": "X-API-Key",
"description": "API key for authentication",
"isRequired": true,
"isSecret": true
}
]
}
]
}packages と remotes は同時に持たせることもできます。ローカル実行版とホスト型のリモート版を両方提供しているサーバーが典型例です。この場合、利用者はMCPクライアント側の設定に応じて、ローカルパッケージとリモートURLのどちらを使うかを選べます。同じサーバーをnpmとNuGetの両方で配布したい、というように packages を複数並べる書き方も可能です。
バージョン文字列のルールとよくあるつまずき
version フィールドには文字列を書けますが、いくつか公式が明記するルールがあります。
- 一意性が必須: 同じバージョン文字列で2回公開することはできません
- 公開後は不変: バージョン文字列を含むメタデータは、公開後に変更できません
- 範囲指定は禁止:
^1.2.3~1.2.3>=1.2.31.xのようなバージョン範囲を表す文字列は登録エラーになります
推奨はセマンティックバージョニングです。1.0.0 や 2.1.3-alpha のような形式ならMCP Registryが自動でパースし、最新版(latest)の判定に使います。パースに失敗する形式(独自ルールの文字列)は常に "latest" 扱いになる点には注意が必要です。
つまずきやすいのが、セマンティックバージョンを使っていたサーバーが、途中で非準拠の文字列を公開した場合です。この場合、本来ならバージョン順で後方に並ぶはずの新バージョンでも "latest" として扱われてしまいます。バージョン形式を運用の途中で変えないことが、この事故を避ける最も簡単な方法です。
複数の配布先(npmとNuGetなど)を1つの server.json にまとめる場合は、server.json 直下の version を全体のリリースバージョンとして扱い、各 packages エントリの version は各配布先の実際のパッケージバージョンに合わせます。ローカルパッケージが1つだけなら、server.json 直下の version と packages 内の version は同じ値に揃えるのが公式の推奨です。リモートサーバーでAPIバージョンがある場合は、server.json の version をそのAPIバージョンに揃える運用が案内されています。メタデータだけを更新したい(パッケージ自体は変えない)場合は、1.2.3-1 のようなプレリリース形式を使う手があります。ただし、正式版を先に公開してからプレリリース版を後追いで公開すると、セマンティックバージョニングの規則上プレリリース版のほうが古い扱いになり、"latest" にならない点は覚えておく必要があります。
mcp-publisherで公開する
server.json を書いたら、mcp-publisher CLIで公開します。
mcp-publisher login github
mcp-publisher publishlogin の部分は選んだ認証方式によってサブコマンドが変わります。GitHub認証(login github)・DNS認証(login dns)・HTTP認証(login http)の3方式があり、後者2つはドメイン所有権を鍵ペアで証明する仕組みです。公開が成功すると、MCP RegistryのREST APIで検索できるようになります。
curl "https://registry.modelcontextprotocol.io/v0.1/servers?search=io.github.my-username/weather"repository フィールドも実務では欠かせません。url にリポジトリのURL、source に github のようなホスティング元を指定します。必須フィールドではありませんが、これを書いておかないと、利用者が起動コマンドの中身をソースコードで確認する手段が server.json からは得られなくなります。見知らぬサーバーを実行するかどうかを判断する材料として、repository を書いておくと利用者側の安心材料が1つ増えます。
公開直後によく出るエラーは3つです。「Registry validation failed for package」はパッケージ側の検証情報(mcpName など)の不備、「Invalid or expired Registry JWT token」は認証切れによる再ログインが必要な状態、「You do not have permission to publish this server」は認証方式とサーバー名の名前空間が食い違っている状態を示します。3つ目は、GitHub認証を選んだのに name が io.github. で始まっていない、という組み合わせミスが典型例です。
複数の配布形式を1つのserver.jsonにまとめる
packages は配列なので、複数のエントリを並べて書けます。npmとNuGetの両方で配布したい場合の例です。
{
"version": "1.3.0",
"packages": [
{
"registryType": "npm",
"identifier": "@my-username/my-server",
"version": "1.3.0",
"transport": { "type": "stdio" }
},
{
"registryType": "nuget",
"identifier": "MyUsername.MyServer",
"version": "1.0.0",
"transport": { "type": "stdio" }
}
]
}まとめ
server.json は、名前・説明・バージョンと、実体の所在(packages か remotes)を書く標準フォーマットです。パッケージ種別ごとに所有権の確認方法が違う点、バージョン文字列に範囲指定を書けない点、公開後は変更できない点の3つが、初回公開でつまずきやすいポイントです。最小構成なら数分で書き終えられる一方、パッケージ種別やバージョン運用のルールを把握していないと、公開直前のエラーで手戻りが発生します。ファイル自体を書き終えたら、公開に必要な認証方式(GitHub・DNS・HTTP)のどれを選ぶかが次の分かれ道になります。