Claude Media
MCP Registryへのリモートサーバー公開手順

MCP Registryへのリモートサーバー公開手順

server.jsonのremotesプロパティでURLだけのMCPサーバーを公開する手順を、認証方式の選び方とmcp-publisher CLIの使い方まで解説します。

MCP RegistryはURLだけで動くリモートサーバーにも対応しています。パッケージを持たないstreamable-httpやsseのエンドポイントをserver.jsonのremotesプロパティに書きます。あとはmcp-publisherで認証・公開すれば完了です。npmやDockerのようなパッケージを先に公開する工程が要りません。MCP Registryは現在プレビュー段階で、一般提供の前に破壊的変更やデータのリセットが入る可能性があります。

公開前に必要な前提

対象は、すでに公開URLで動いているMCPサーバーをMCP Registryに登録する手順です。前提は次の3つです。

  • インターネットから誰でも到達できるURLでサーバーが動いていること(remotesのURLは公開アクセス可能でなければなりません)
  • GitHubアカウントか、サーバー名の名前空間に使う独自ドメインのどちらか
  • mcp-publisher CLIをインストールできる環境

パッケージ型のサーバーでは、package.jsonのmcpNameのような検証情報が要ります。詳しくはパッケージ形式ごとの所有権証明を参照してください。リモートサーバーにはその工程がなく、要点は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は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で既定値を与えたり、isSecretで秘密の値として扱ったりもできます。地域ごとにエンドポイントを分けるサーバーなら、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

認証方式は、サーバー名の名前空間で決まります。先に方式を選び、その形式に合わせてnameを書く順序です。

くらべる

認証方式と名前空間の対応

io.github.username/*

GitHub認証

io.github.username/*またはio.github.orgname/*で始まる名前に使います。mcp-publisher login githubがデバイス認証を始め、GitHubの認証画面でコードを入力すれば完了です。

com.example.*/*

DNS認証

独自ドメインの名前空間に使います。ドメインのTXTレコードに公開鍵を載せ、秘密鍵でmcp-publisher login dnsを実行します。TXTレコードの反映には数分かかることがあります。

com.example.*/*

HTTP認証

同じく独自ドメイン向けで、TXTレコードの代わりに/.well-known/mcp-registry-authファイルをドメイン上に置きます。DNSの代わりに、ドメイン上で配信するファイルで所有権を示す方式です。

ドメイン側は、example.comを逆引きしたcom.exampleが名前の先頭になります。ステップ1のcom.example/acme-analyticsのような名前で公開するなら、DNS認証かHTTP認証が必要です。以下はGitHub認証での流れです。

mcp-publisher login github

端末にはhttps://github.com/login/deviceのURLとABCD-1234の形のコードが表示されます。ブラウザーでコードを入力すると、Successfully authenticated!と出て認証が終わります。続けてpublishで公開します。

mcp-publisher publish

成功すると✓ Successfully publishedと、公開されたサーバー名とバージョンが表示されます。公開できたかどうかは、Registry APIへの検索クエリで確かめます。

curl "https://registry.modelcontextprotocol.io/v0.1/servers?search=<server.jsonのname>"

実在するリモートサーバーの登録内容

同じ検索APIでNotionのリモートMCPサーバー(名前はcom.notion/mcp)を引くと、remotesだけを持つ登録の実物が返ります。以下はレスポンスから必要な部分を抜いたものです。

{
  "servers": [
    {
      "server": {
        "name": "com.notion/mcp",
        "description": "Official Notion MCP server",
        "version": "1.0.1",
        "remotes": [
          { "type": "streamable-http", "url": "https://mcp.notion.com/mcp" },
          { "type": "sse", "url": "https://mcp.notion.com/sse" }
        ]
      },
      "_meta": {
        "io.modelcontextprotocol.registry/official": {
          "status": "active",
          "isLatest": true
        }
      }
    }
  ],
  "metadata": { "count": 2 }
}

countが2なのは、同じ名前で1.0.0と1.0.1の2つのバージョンが並んでいるためです。古い1.0.0のisLatestはfalse、新しい1.0.1がtrueになっています。streamable-httpとsseを別々のURLで両方公開している点も、前節の説明どおりです。

packagesが無くremotesだけの登録なので、利用側が実行するのはサーバーのインストールではなく、このURLへの接続になります。

独自ドメインで認証したい場合の追加手順

会社のドメインをサーバー名の名前空間に使うときは、GitHubアカウントではなくドメインの所有権で認証します。DNS認証もHTTP認証も、公開鍵と秘密鍵のペアを作るところから始まります。

openssl genpkey -algorithm Ed25519 -out key.pem

DNS認証では、公開鍵から作ったTXTレコードをドメインのDNS設定に追加します。記録の形はexample.com. IN TXT "v=MCPv1; k=ed25519; p=<公開鍵>"です。反映後に、秘密鍵を渡してmcp-publisher login dns --domain example.com --private-key <秘密鍵>を実行します。

HTTP認証では、同じ内容のv=MCPv1; k=ed25519; p=<公開鍵>をmcp-registry-authファイルに書きます。置き場所はhttps://example.com/.well-known/mcp-registry-authです。ログインはmcp-publisher login http --domain example.com --private-key <秘密鍵>です。

鍵はEd25519のほかにECDSA P-384も選べます。その場合のTXTレコードはk=ecdsap384の形で、鍵はopenssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:secp384r1で作ります。

鍵ペアは、Google KMSやAzure Key Vaultの署名鍵に置き換えることもできます。この場合はlogin dns google-kmsやlogin http 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は、mcp.acme-corp.internalのような社内ネットワーク限定のサーバーを対象にしていません。特定の利用者だけが使えるプライベートサーバーを公開したい場合は、自前でレジストリを運用する構成が案内されています。

SSEを主にしてしまう: 新規サーバーはstreamable-httpを主にし、sseは既存クライアントのために追加します。

認証方式とサーバー名の不一致: 認証方式と名前の形式が合わないと、「You do not have permission to publish this server」と出ます。GitHub認証なら名前はio.github.あなたのユーザー名/で始めます。

トークンの期限切れ: 「Invalid or expired Registry JWT token」と出たら、mcp-publisher loginをもう一度実行します。GitHub Actionsの例も、毎回mcp-publisher loginを実行してからpublishする構成です。

公開後に消せない: 公開者が自分で削除・取り下げる機能は、FAQでは現状ありません。URLを変えたくなった場合は、新しいバージョンを公開し直します。

ヘッダーの宣言と実際の認証の混同: headersは接続時にクライアントへ送らせる値の宣言です。OAuthによる接続認証は別の仕組みで、リモートMCPのOAuth認証が扱っています。

GitHub Actionsで自動公開する

タグをpushするたびに公開する構成では、認証方式で必要なSecretsが変わります。

くらべる

自動公開の認証とSecrets

Secrets不要

GitHub OIDC

専用のSecretは要りません。ワークフローにid-token: write権限を付け、mcp-publisher login github-oidcを使います。

MCP_GITHUB_TOKEN

GitHub PAT

read:orgとread:userのスコープを持つPersonal Access Tokenを、MCP_GITHUB_TOKENとして登録します。ログインはlogin github --tokenです。

MCP_PRIVATE_KEY

DNS認証

Ed25519の秘密鍵そのものをMCP_PRIVATE_KEYに登録します。秘密鍵そのものをSecretに置く方式です。

ワークフローはv*形式のタグpushで動き始めます。テスト、ビルド、パッケージ公開、mcp-publisher login、mcp-publisher publishの順です。リモートのみのサーバーなら、パッケージ公開の工程は要りません。バージョン番号をserver.jsonへ流し込みたいときは、jqでタグ名からversionを書き換える任意のステップも用意されています。

git tag v1.0.0
git push origin v1.0.0

「Authentication failed」と出たときは、OIDCならid-token: write権限、それ以外ならSecretsの登録を見直します。

公開後に反映されるまでと、直すときのルール

手順

公開から利用者に届くまで

  1. 1

    Registry APIに載る

    mcp-publisher publishが成功すると、検索APIから引けるようになります。

  2. 2

    アグリゲーターが取り込む

    MCPサーバーのマーケットプレイスなどの下流サービスは、Registry APIを定期的に取りに来ます。想定されている間隔は1時間に1回程度です。公開直後にAPIでは見えるのに、特定のサービスの一覧には出ない場合は、この取り込み待ちの可能性があります。

  3. 3

    直すときは新バージョンで出し直す

    公開済みのバージョン文字列とメタデータは変更できません。修正は新しいバージョン文字列のserver.jsonをpublishして反映します。

バージョン文字列は、公開のたびに一意でなければなりません。^1.2.3や1.xのような範囲指定は禁止されています。セマンティックバージョニングに沿わない文字列は、常に「latest」として扱われます。リモートサーバーにAPIのバージョンがある場合は、サーバーのバージョンをAPIのバージョンに合わせる運用が推奨されています。

URLもAPIも変えずにメタデータだけ直したいときは、1.2.3-1のようなセマンティックバージョニングのプレリリース版を使います。ただしプレリリース版は通常版より前に並びます。1.2.3の公開後に1.2.3-1を出しても、「latest」の印は付きません。

_meta.io.modelcontextprotocol.registry/publisher-providedの下に独自メタデータを入れることもできます。上限は4KB(JSONで4096バイト)で、超えると公開に失敗します。バージョンの付け方の詳細はMCP Registryのバージョニングルールに書いています。

まとめ

リモートサーバーの公開は、remotesのURLを一般に到達できる状態にすることと、名前空間に合う認証方式を先に選ぶことの2点で決まります。社内限定で配りたいだけなら、公開レジストリを使わないセルフホスト環境での配布経路が向いています。

この記事を共有:XはてブLinkedIn
MCP をもっと見る →