server.jsonの書き方 — MCP Registry公開用メタデータ形式
MCP Registryに公開するserver.jsonの必須項目・フィールドの制約・6種類のパッケージ形式・バージョン文字列のルールを、公式スキーマとサンプルで解説します。
server.jsonとは何を書くファイルか
server.json は、MCPの公式サーバーカタログであるMCP Registryにサーバーを登録するための標準メタデータファイルです。サーバーの一意な名前・説明・バージョン・実体の所在(npmパッケージなのかリモートURLなのか)・起動方法をこの1ファイルにまとめます。登録にはmcp-publisherというCLIツールを使います。
MCP Registryが持つのはメタデータだけで、パッケージ本体は預かりません。npmやPyPIなどへ先に本体を公開し、そこを指す server.json を後から登録する順番になります。
前提環境はシンプルです。必要なのは3つです。Node.js(TypeScript製サーバーの場合)、公開先のパッケージレジストリ(npmなど)のアカウント、MCP Registryへの認証手段(GitHubアカウントまたは所有ドメイン)です。認証方式の選び方はMCP Registryの認証方式3種で扱い、本記事は server.json の書き方に絞ります。
npmサーバーを公開するまでの流れ
- 1
package.json に mcpName を足す
値は
server.jsonのnameと同じにします。GitHub認証ならio.github.ユーザー名/で始めます。 - 2
パッケージを npm に公開する
npm publish --access publicなどで本体を先に出します。 - 3
mcp-publisher init で雛形を作る
プロジェクトの情報から
server.jsonが生成されるので、バージョンなどを自分の値に直します。 - 4
login して publish する
mcp-publisher login githubのあとmcp-publisher publishを実行します。
最小構成のserver.jsonを書く
mcp-publisher init を実行すると、プロジェクトの情報からテンプレートが生成されます。
mcp-publisher initクイックスタートが示す生成直後のテンプレートは次のとおりです。バージョンは 1.0.0 で、ダミーの環境変数 YOUR_API_KEY が入っています。
{
"$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.0",
"packages": [
{
"registryType": "npm",
"identifier": "@my-username/mcp-weather-server",
"version": "1.0.0",
"transport": {
"type": "stdio"
},
"environmentVariables": [
{
"description": "Your API key for the service",
"isRequired": true,
"format": "string",
"isSecret": true,
"name": "YOUR_API_KEY"
}
]
}
]
}このサーバーに環境変数が要らないなら environmentVariables ごと消します。バージョンも自分のパッケージに合わせて直します。クイックスタートでは package.json を 1.0.1 に上げているため、server.json 側の2か所も 1.0.1 に書き換えています。
先頭の $schema は、このファイルが準拠するスキーマのURLです。エディタや検証ツールがこの値を見て、フィールド名の綴りミスや型の不一致をその場で警告します。
必須フィールドと値の制約
スキーマ(2025-12-11版)で必須とされているのは、トップレベルでは name・description・version の3つです。packages と remotes はどちらも必須には指定されておらず、実体の所在を書くために実質どちらか(または両方)を置きます。値の制約は次のとおりです。
| フィールド | 制約 |
|---|---|
name | 制約逆引きDNS形式。スラッシュがちょうど1つで、前が名前空間、後ろがサーバー名。3〜200文字 |
description | 制約1〜100文字。実装の詳細でなく機能を書く |
version | 制約255文字まで。範囲指定は拒否される |
title | 制約任意。1〜100文字の表示名で、サブレジストリやクライアントが表示に使ってよい |
repository | 制約任意。書くなら url と source の両方が必須 |
name は、GitHub認証なら io.github.ユーザー名/ で始め、ドメイン認証なら所有ドメインを逆引きにした名前空間(com.example.*/ のような形)を使います。GitHub認証では、個人のユーザー名のほか組織名(io.github.組織名/)も名前空間にできます。認証方式と名前空間が食い違うと、公開時に権限エラーになります。
パッケージ側(packages の各要素)では、registryType・identifier・transport が必須です。version には具体的なバージョンを書き、latest という文字列は使えません。fileSha256 が必須になるのはMCPBだけです。
environmentVariables の各項目は、name・description・isRequired・isSecret・format を持てます。format に書けるのは string・number・boolean・filepath の4つで、既定は string です。isSecret: true を付けると、APIキーのような秘匿情報として扱う手がかりをクライアントに渡せます。
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: |
oci | 対応レジストリDocker Hub・GHCR・Google Artifact Registry・Azure Container Registry・Microsoft Container Registry | 所有権の確認方法io.modelcontextprotocol.server.name のアノテーション(Dockerfileでは LABEL) |
mcpb | 対応レジストリGitHub / GitLabのリリースに置いた成果物 | 所有権の確認方法配布URLに"mcp"の文字列を含む + fileSha256 の明記 |
cargo だけコメントに隠せない理由は、crates.ioがREADMEをHTMLに変換するときにHTMLコメントを除去するためです。PyPIやNuGetで通る <!-- mcp-name: ... --> の形を流用すると、検証側が見るHTMLに文字列が残りません。リンク集の箇条書きなど、見える文として書きます。
oci の例を見てみます。
{
"packages": [
{
"registryType": "oci",
"identifier": "docker.io/yourusername/kubernetes-manager-mcp:1.0.0",
"transport": {
"type": "stdio"
}
}
]
}identifier の形式は レジストリ/名前空間/リポジトリ:タグ です。タグの代わりにダイジェスト指定も使えます。
mcpb パッケージだけは他の種別と違い、MCP Registry自身がハッシュを検証しません。検証するのはMCPクライアント側で、インストール前に成果物が fileSha256 と一致するかを確かめます。公開者はこのハッシュを自分で用意します。
openssl dgst -sha256 image-processor.mcpbRustサーバーを作る場合は、配布方針で2つの道に分かれます。
Rustサーバーの配布経路
cargo
crates.io経由で、利用者が cargo install を実行します。利用者の環境にRustツールチェーンが必要です。
mcpb
GitHubやGitLabのリリースに置いたバイナリを使います。利用者にツールチェーンは要りません。
どちらも正式な対応経路で、優劣ではなく選択です。cargo にはnpmの npx やPyPIの uvx に当たる実行ごとのランナーがなく、インストールは一度きり、実行はバイナリ名で呼ぶ形になります。サンプルに runtimeHint が書かれていないのはそのためです。
Filesystem MCPサーバーは @modelcontextprotocol/server-filesystem としてnpm配布されています。ここまでの npm 形式の例とほぼ同じ構造です。一方、GitHub MCPサーバーは2通りで提供されています。GitHubがホストするリモートサーバー(https://api.githubcopilot.com/mcp/)と、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)です。sse を公開するのは既存クライアントを支えるときだけにして、新規なら streamable-http を選びます。両方式を別URLで同時提供することも可能です。リモートサーバーは、指定したURLで公開アクセス可能であることが必須です。
マルチテナントで提供するときは、URLに {変数名} 形式のテンプレート変数を埋め込み、同じ階層の variables で中身を定義します。
{
"type": "streamable-http",
"url": "https://{tenant_id}.analytics.example.com/mcp",
"variables": {
"tenant_id": {
"description": "Your tenant identifier (e.g., 'us-cell1', 'emea-cell1')",
"isRequired": true
}
}
}利用者がサーバーを追加するときに tenant_id を入力すると、URLが https://us-cell1.analytics.example.com/mcp のように解決されます。テナントごとに1エントリを書かずに済みます。変数には default・choices・isSecret も付けられ、リージョンのように選択肢が決まっているものは choices で絞ります。
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ホストアプリケーションがどちらの導入方法を使うかを選びます。
バージョン文字列のルールとよくあるつまずき
version フィールドには、公式が明記するルールがあります。
- 一意性が必須: 同じバージョン文字列で2回公開することはできません
- 公開後は不変: バージョン文字列を含むメタデータは、公開後に変更できません
- 範囲指定は禁止:
^1.2.3~1.2.3>=1.2.31.x1.2.*1 - 2のようなバージョン範囲に見える文字列は登録エラーになります
推奨はセマンティックバージョニングです。1.0.0 や 2.1.3-alpha のような形式なら、MCP Registryが解析して最新版(latest)の判定に使います。v1.0 や 2025-06-18 のような形式も許可されますが、解析に失敗した文字列は常に "latest" 扱いになります。
日付をバージョンにする運用には、公式の表が注意印を付けている落とし穴があります。2025.11.25 や 2025.6.18 はセマンティックバージョンとして解析できますが、ゼロ埋めした 2025.06.18 は非セマンティックな日付の扱いです。同じ日付でもゼロ埋めの有無で解析の結果が変わります。
つまずきやすいのが、セマンティックバージョンを使っていたサーバーが、途中で非準拠の文字列を公開した場合です。この場合、本来ならバージョン順で後方に並ぶはずの新バージョンでも "latest" として扱われてしまいます。バージョン形式を運用の途中で変えないことが、この事故を避ける最も簡単な方法です。
複数の配布先を1つの server.json にまとめるときは、直下の version を全体のリリースバージョンにします。各 packages の version は、配布先の実際のバージョンに合わせます。
{
"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" }
}
]
}ローカルパッケージが1つだけなら、直下の version と packages 内の version は同じ値に揃えるのが公式の推奨です。リモートサーバーでAPIバージョンがある場合は、server.json の version をそのAPIバージョンに揃えます。URLにバージョンを含むサーバー(https://api.myservice.com/mcp/v2.1 に対して 2.1.0)がその例です。
パッケージやリモートURLを変えず、メタデータだけを更新したいときは、1.2.3-1 のようなプレリリース形式を使います。この場合 packages 内の version は 1.2.3 のままです。ただし、正式版を先に公開してからプレリリース版を後追いで公開すると、セマンティックバージョニングの規則でプレリリース版のほうが古い扱いになり、"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つはドメイン所有権を鍵ペアで証明する仕組みです。GitHub認証では、端末に出るデバイスコードをブラウザーで入力して承認します。公開が成功すると、MCP RegistryのREST APIで検索できるようになります。
curl "https://registry.modelcontextprotocol.io/v0.1/servers?search=io.github.my-username/weather"repository は必須ではありませんが、スキーマは「透明性とセキュリティ検査のために推奨」としています。これを書かないと、利用者が起動コマンドの中身をソースコードで確かめる手がかりが server.json から消えます。url にリポジトリのURL、source に github のようなホスティング元を指定します。
公開直後によく出るエラーは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 | 原因と対処認証方式とサーバー名の名前空間が食い違っている |
3つ目は、GitHub認証を選んだのに name が io.github. で始まっていない、という組み合わせミスが典型例です。
まとめ
server.json は書き方よりも制約を先に押さえると手戻りが減ります。公開後に変えられないバージョンは、とくに形式を決めてから出す項目です。ファイルを書き終えたら、公開に使う認証方式(GitHub・DNS・HTTP)を選ぶ段階です。