MCP Registryへのリモートサーバー公開手順
server.jsonのremotesプロパティでURLだけのMCPサーバーを公開する手順を、認証方式の選び方とmcp-publisher CLIの使い方まで解説します。
MCP RegistryはURLだけで動くリモートサーバーにも対応しています。パッケージを持たないstreamable-httpやsseのエンドポイントをserver.jsonのremotesプロパティに書き、mcp-publisherで認証・公開すれば完了です。npmやDockerのようなパッケージ実体を用意する必要がなく、公開までの手順自体はローカルサーバーより短くなります。
何を学ぶか、何が前提か
本記事で扱うのは、既に公開URLで動いているMCPサーバーをMCP Registryに登録する手順です。前提となるのは次の3つです。
- インターネットから到達可能なURLでサーバーが動いていること(プライベートネットワーク限定のサーバーは対象外)
- GitHubアカウントか、サーバー名の名前空間に使う独自ドメインのどちらか
mcp-publisherCLIをインストールできる環境
パッケージの公開(npm publish等)を挟まない分、パッケージ形式ごとの所有権証明を気にする必要はありません。その代わり、URLの到達性とトランスポート種別の指定が要点になります。
ステップ1: server.jsonにremotesを書く
remotesプロパティに、URLとトランスポート種別を指定します。
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "com.example/acme-analytics",
"title": "ACME Analytics",
"description": "Real-time business intelligence and reporting platform",
"version": "2.0.0",
"remotes": [
{
"type": "streamable-http",
"url": "https://analytics.example.com/mcp"
}
]
}トランスポートはstreamable-httpが標準です。sseはプロトコル仕様上すでに非推奨のため、既存クライアントとの互換性が必要な場合だけ併記します。両方のURLを同時に公開し、クライアント側にどちらを使うか選ばせることもできます。
ステップ2: URLテンプレート変数を使う
SaaS型でテナントごとにエンドポイントが変わるサーバーは、{変数名}のプレースホルダーをURLに埋め込めます。
{
"remotes": [
{
"type": "streamable-http",
"url": "https://{tenant_id}.analytics.example.com/mcp",
"variables": {
"tenant_id": {
"description": "Your tenant identifier (e.g., 'us-cell1')",
"isRequired": true
}
}
}
]
}choicesで選択肢を列挙したり、defaultで既定値を与えたりもできます。地域ごとにエンドポイントを分けるサーバーなら、regionのようなキーでus-east-1 eu-west-1といった選択肢を用意する使い方になります。
ステップ3: 認証情報が要るならheadersで伝える
APIキーなど、接続時にHTTPヘッダーが必要なサーバーは、headersプロパティで必要なヘッダー名と説明を宣言します。
{
"remotes": [
{
"type": "streamable-http",
"url": "https://analytics.example.com/mcp",
"headers": [
{
"name": "X-API-Key",
"description": "API key for authentication",
"isRequired": true,
"isSecret": true
}
]
}
]
}isSecret: trueを付けると、クライアント側の実装で値がマスク表示の対象になります。これはMCPクライアントとサーバー間の認証であり、次のステップで扱う「公開者がMCP Registryに対して自分を証明する認証」とは別物です。両者を混同しないよう注意してください。
ステップ4: 認証してpublishする
server.jsonが書けたら、mcp-publisher CLIをインストールします。
brew install mcp-publisher認証方式は、サーバー名の名前空間に合わせて選びます。io.github.username/*形式ならGitHub認証、com.example.*/*のような逆引きドメイン形式ならDNS認証かHTTP認証です。GitHub認証がもっとも手早く済みます。
mcp-publisher login github表示されたコードでデバイス認証を済ませたら、publishコマンドで公開します。
mcp-publisher publish公開できたかどうかは、Registry APIへの検索クエリで確認できます。
curl "https://registry.modelcontextprotocol.io/v0.1/servers?search=com.example/acme-analytics"独自ドメインを名前空間に使いたい場合は、DNS認証(TXTレコード)かHTTP認証(/.well-known/mcp-registry-authファイル)のどちらかを選びます。DNS認証は反映まで数分かかることがあるため、公開作業を急ぐ日には避けたほうが安全です。
独自ドメインで認証したい場合の追加手順
会社のドメインをサーバー名の名前空間に使いたいときは、GitHubアカウントではなくドメイン所有権で認証します。手順はDNS認証とHTTP認証のどちらも共通で、まず公開鍵と秘密鍵のペアを作るところから始まります。
openssl genpkey -algorithm Ed25519 -out key.pemDNS認証では、生成した公開鍵をTXTレコードとしてドメインのDNS設定に追加します。レコードが反映されたら、秘密鍵を使ってmcp-publisher login dnsを実行します。HTTP認証では、TXTレコードの代わりにmcp-registry-authという名前のファイルをhttps://example.com/.well-known/mcp-registry-authに置きます。DNSの伝播を待てない場合はHTTP認証のほうが即時に反映される利点があります。
いずれの方式でも、生成した鍵ペアはGoogle KMSやAzure Key Vaultのようなクラウド側の鍵管理サービスに置き換えることもできます。秘密鍵をリポジトリやローカルファイルに平文で残したくない組織向けの選択肢です。
パッケージ版と併用する設計
remotesはpackagesと共存できます。同じサーバーをホスト型のリモート接続と、ローカル実行用のnpmパッケージの両方で提供したいときに使う構成です。
{
"name": "io.github.username/email-integration-mcp",
"remotes": [
{ "type": "streamable-http", "url": "https://email.example.com/mcp" }
],
"packages": [
{
"registryType": "npm",
"identifier": "@example/email-integration-mcp",
"version": "1.0.0",
"transport": { "type": "stdio" }
}
]
}MCPホストアプリケーション側は、この両方の選択肢からユーザーに合う方を選ばせられます。社内利用者にはリモート接続、ローカルで完結させたい利用者にはnpmパッケージ、という使い分けです。
よくあるつまずき
URLがプライベートネットワーク限定: MCP Registryは、社内ネットワーク限定のURL(例: mcp.acme-corp.internal)を想定していません。外部からアクセスできないサーバーを登録しようとすると、公開自体はできても実質的に誰も接続できない状態になります。社内限定で使いたい場合は、自前でMCP Registry互換のAPIを立てる選択肢が案内されています。
SSEをデフォルトにしてしまう: sseはプロトコル仕様上deprecated指定です。新規サーバーはstreamable-httpを主にし、sseは既存クライアントの延命目的でのみ追加します。
認証方式とサーバー名の不一致: GitHub認証を選んだのにserver.jsonのnameがcom.example/*形式になっていると、公開時に権限エラーになります。認証方式を決めてからnameを書く順番を守ってください。
トークンの期限切れ: mcp-publisher loginで得た認証情報には有効期限があります。しばらく時間を置いてからpublishを実行すると「Invalid or expired Registry JWT token」というエラーになることがあり、この場合は同じloginコマンドを再実行するだけで解消します。CIで自動化している場合も、ジョブの実行間隔が空くワークフローでは同様の再認証が必要になる点を想定しておくと安全です。
継続的に公開したい場合の自動化: バージョンタグをpushするたびに公開したい場合は、GitHub Actionsのワークフローにmcp-publisher publishを組み込む方法が公式に用意されています。手動運用から始めて、公開頻度が上がってから自動化を検討する順序で問題ありません。
GitHub Actionsで自動公開する
タグをpushするたびに自動公開したい場合、認証方式によって必要なSecretsが変わります。GitHub OIDC認証は追加のSecrets登録が不要で、ワークフロー側にid-token: write権限さえ付ければ済むため、最も運用の手間が少ない方式です。GitHubのPersonal Access Token(PAT)を使う方式ではread:orgとread:userスコープを持つトークンをSecretsに登録する必要があります。DNS認証を自動化する場合は、Ed25519の秘密鍵そのものをSecretsに登録することになるため、鍵の管理責任がリポジトリの権限設定に直結します。
ワークフローの骨格は共通です。v*形式のタグpushをトリガーに、npm等へのパッケージ公開ステップと、mcp-publisher login・mcp-publisher publishのステップを並べます。
git tag v1.0.0
git push origin v1.0.0このタグpushをきっかけに、テスト・ビルド・パッケージ公開・MCP Registryへの公開までが一気通貫で走ります。OIDC認証を使う場合、CI環境からの認証だけlogin github-oidcという専用サブコマンドに置き換わる点が、手元でのlogin githubと唯一違うところです。
なお、ここで扱う認証はMCP Registryに対する公開者の証明であり、MCPクライアントが実際にサーバーへ接続する際のOAuth認証とは別レイヤーです。接続時の認証周りはリモートMCPのOAuth認証で扱っています。
公開してからどれくらいで見つかるようになるか
mcp-publisher publishが成功すれば、Registry API自体には即座に反映されます。ただし、Claude Desktopの拡張機能一覧やサードパーティのMCPマーケットプレイスといったダウンストリームのアグリゲーターは、Registry APIを定期的に(公式の想定では概ね1時間に1回程度)ポーリングして新規メタデータを取り込む設計です。公開直後にRegistry APIの検索では見つかるのに、特定のクライアントアプリの一覧にまだ出てこないという状態は、この取り込み間隔によるものであり、公開自体の失敗ではありません。
メタデータを修正したい場合は、同じバージョン文字列のまま上書きすることはできません。新しいバージョン文字列でserver.jsonを作り直し、再度publishする必要があります。バージョン文字列の付け方と、この不変性がもたらす実務上の影響はMCP Registryのバージョニングルールにまとめています。
まとめ
リモートサーバーの公開は、server.jsonにremotesを書き、URLの到達性を確認し、サーバー名の名前空間に合った認証方式でmcp-publisherから公開する4ステップです。パッケージ形式の公開手順やバージョン管理の詳細は、前段でリンクした記事を参照してください。社内向けにMCPサーバーを配りたいだけなら、公開レジストリを使わないセルフホスト環境での配布経路も選択肢に入ります。