50% off your first year. Join before 2027. Claim →

How to publish an MCP server to the MCP Registry

To publish an MCP server to the official MCP Registry, you describe it in a server.json file, prove that you own its namespace, and push the file with the mcp-publisher CLI. There is no form and no review queue. This guide walks through every step with the exact commands from the official docs, for package-based and remote servers, and shows where MCP Tower helps: testing your server before you publish, and measuring the traffic that registry catalogs send you afterwards.

I highly recommend publishing. The registry is the upstream that Glama, PulseMCP and other catalogs pull from, so one publish reaches several listings. If you want the background first, read why the official MCP Registry is a new MCP growth channel.

The whole process, in order:

  1. Test your tools, sign-in and hostname in MCP Tower.
  2. Choose a namespace: GitHub or your own domain.
  3. Add an ownership marker to your package, or skip this for a remote-only server.
  4. Install mcp-publisher.
  5. Create and validate server.json.
  6. Log in to the registry.
  7. Run mcp-publisher publish.
  8. Check the listing through the registry API.
  9. Publish updates as new versions, and measure usage.

1. Prepare your MCP server before you publish

The registry checks your namespace and your package, not your tools. Catalogs downstream look closer: Glama’s methodology describes scoring tool definitions and watching tool descriptions for prompt-injection patterns. Clients that find you through a catalog will also connect and sign in the way ChatGPT and Claude do. Fix what they would trip on before the listing goes out.

  • Tools and descriptions. When you add your server to MCP Tower, its Inspect module validates every tool and its description and gives you recommendations. Fix them on your server and scan again, or change a tool’s title and description with an override, without waiting for your developers.
  • OAuth. If users sign in, run MCP Tower’s OAuth checks. There are 18 of them, and they sign in the way ChatGPT and Claude do and report the first place the flow breaks, with the fix.
  • The hostname. A published version cannot be edited, and the registry allows each remote URL for only one server name. Put MCP Tower in front of your server first (onboarding) and use its public hostname, for example https://mcp.example.com/, as the remote URL in server.json. That way the URL you publish is the one you keep, and every call through it is measured.

2. Choose your namespace: GitHub or your domain

Every server in the registry has a unique name in reverse-DNS form, and the authentication method you use decides which names you may publish:

Login methodName formatExample
GitHub (OAuth or OIDC)io.github.username/* or io.github.orgname/*io.github.alice/weather-server
DNS or HTTP verificationcom.example/*com.example/weather

GitHub login is the quickest start. If your remote server runs on your own domain, consider the domain namespace: the registry checks the namespace, not the remote URL, so a com.example name next to an example.com URL shows users that both belong to the same publisher (ownership verification).

3. Add package ownership verification

The registry hosts metadata only, so the package must already be public on its own registry, and it must name your server. Each package type has its own marker, and the value must equal the name in server.json:

Package typeWhere the marker goes
npm"mcpName": "io.github.alice/weather" in package.json
PyPI, NuGetAn mcp-name: io.github.alice/weather line in the package README
CargoThe same mcp-name: line as visible text (crates.io strips comments)
Docker/OCILABEL io.modelcontextprotocol.server.name="io.github.alice/weather"
MCPBA URL containing “mcp” and a fileSha256 hash in server.json

For npm, the quickstart adds the field and publishes the package before anything else:

{
"name": "@alice/mcp-weather-server",
"version": "1.0.1",
"mcpName": "io.github.alice/weather"
}
Terminal window
npm publish --access public

On PyPI and NuGet the line can sit inside an HTML comment in the README. Leave a space or a line break after the server name: a period glued to it stops the match.

Remote-only servers skip this step. A server with only a remotes entry needs no package, so there is nothing to verify here.

4. Install the mcp-publisher CLI

Install mcp-publisher with Homebrew or a prebuilt binary from the releases page:

Terminal window
brew install mcp-publisher
mcp-publisher --help

The help lists six commands: init, login, logout, publish, status and validate.

5. Create and validate server.json

In your project directory, generate a template:

Terminal window
mcp-publisher init

For a package-based server, the result looks like this:

{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.alice/weather",
"description": "An MCP server for weather information.",
"repository": {
"url": "https://github.com/alice/mcp-weather-server",
"source": "github"
},
"version": "1.0.1",
"packages": [
{
"registryType": "npm",
"identifier": "@alice/mcp-weather-server",
"version": "1.0.1",
"transport": { "type": "stdio" }
}
]
}

For a remote server, init still writes a packages entry. Replace it with remotes, and use the Streamable HTTP transport, since the SSE transport is deprecated (remote servers):

{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "com.example/weather",
"title": "Weather",
"description": "Forecasts and alerts for any city.",
"version": "1.0.0",
"remotes": [
{
"type": "streamable-http",
"url": "https://mcp.example.com/"
}
]
}

Check three rules before you go on:

  • description is limited to 100 characters. Say what the server does and stop.
  • name must match the package marker from step 3, character for character.
  • The remote URL must be publicly reachable. Remotes can also declare URL variables (for example a {tenant_id} subdomain) and headers clients must send, such as an API key.

Then check the file. validate reports every issue at once, with the JSON path of each:

Terminal window
mcp-publisher validate

6. Log in to the MCP Registry

Use the login that matches your namespace from step 2.

GitHub

Terminal window
mcp-publisher login github

The CLI prints a code; open https://github.com/login/device, enter it and authorize. This grants your personal namespace, io.github.<your-username>/*. The docs warn that the interactive login cannot currently publish to an organization namespace (tracking issue #1468). For an organization, where you must be an Owner, use GitHub Actions with OIDC (mcp-publisher login github-oidc, with id-token: write permission) or a personal access token with read:org:

Terminal window
mcp-publisher login github --token "$GITHUB_TOKEN"

DNS

Generate an Ed25519 key pair and publish the public key as a TXT record on the apex of your domain, not under a selector such as _mcp-auth. On macOS, use OpenSSL 3 (brew install openssl@3), because the system LibreSSL cannot create Ed25519 keys:

Terminal window
MY_DOMAIN="example.com"
openssl genpkey -algorithm Ed25519 -out key.pem
PUBLIC_KEY="$(openssl pkey -in key.pem -pubout -outform DER | tail -c 32 | base64)"
echo "${MY_DOMAIN}. IN TXT \"v=MCPv1; k=ed25519; p=${PUBLIC_KEY}\""

Add the record at your DNS provider, wait for it to propagate, then log in:

Terminal window
PRIVATE_KEY="$(openssl pkey -in key.pem -noout -text | grep -A3 "priv:" | tail -n +2 | tr -d ' :\n')"
mcp-publisher login dns --domain "${MY_DOMAIN}" --private-key "${PRIVATE_KEY}"

Keep key.pem out of your repository; it proves you own the domain.

HTTP

Instead of DNS, you can serve the proof record v=MCPv1; k=ed25519; p=... at https://example.com/.well-known/mcp-registry-auth and run mcp-publisher login http with the same flags. The registry fetches the file from Google Cloud with User-Agent: mcp-registry/1.0, follows no redirects and gives up after 10 seconds. A WAF or bot rule that challenges non-browser clients makes the login fail with token exchange failed with status 401, even when the file opens fine in your browser. If you are not sure what your edge does to such requests, use DNS.

7. Publish your MCP server to the MCP Registry

Terminal window
mcp-publisher publish

The CLI validates the file, then the registry checks the package marker and your namespace and stores the version. A successful run ends with:

✓ Successfully published
✓ Server io.github.alice/weather version 1.0.1
ErrorWhat to fix
“Registry validation failed for package”The package marker from step 3 is missing or does not match
“Invalid or expired Registry JWT token”Run the login command again
“You do not have permission to publish this server”The name does not start with the namespace your login grants

8. Check your listing with the registry API

The registry has a public, read-only REST API. Search for your server:

Terminal window
curl "https://registry.modelcontextprotocol.io/v0.1/servers?search=io.github.alice/weather"

Or fetch the latest version directly. Path parameters must be URL-encoded, so / becomes %2F:

Terminal window
curl "https://registry.modelcontextprotocol.io/v0.1/servers/io.github.alice%2Fweather/versions/latest"

The response wraps your server.json with registry metadata under _meta["io.modelcontextprotocol.registry/official"]: status, publishedAt, updatedAt and isLatest. Catalogs that sync from the registry read the same record. The registry’s About page expects them to pull “on a regular but infrequent basis (for example, once per hour)”, and each one sets its own schedule, so your listing does not show up everywhere at the same moment.

9. Update, version and retire your listing

Published metadata is immutable. To change anything, even a typo in the description, publish a new server.json with a new, unique version (versioning):

  • Use semantic versions. The registry sorts them to decide which version is latest, and rejects ranges such as ^1.2.3 or 1.x.
  • Keep the server version equal to the package version, or to your API version for a remote server.
  • For a metadata-only change, the docs suggest a prerelease such as 1.2.3-1. Semver sorts it before 1.2.3, so a prerelease published after its regular version is not marked latest.

To take a version out of circulation, change its status. Nothing is ever deleted outright: a deleted server is hidden from default listings but kept on record.

Terminal window
mcp-publisher status --status deprecated --message "Please upgrade to 2.0.0" \
io.github.alice/weather 1.0.0

To publish on every release, the registry documents GitHub Actions workflows that log in with OIDC and run the same publish command.

After you publish: measure the traffic

The registry shows you none of the traffic it sends. Downstream catalogs may show their own numbers, each in its own place. This is the second place MCP Tower helps, as the first product built to show how AI agents use your MCP server.

If the remote URL you published is your MCP Tower hostname, MCP Tower records every call that passes through it: which agent made it and how far that label can be trusted, which tool it called, how long it took and what failed. It also tracks link clicks from tool results and interactions inside widgets, and checks your uptime even when nobody is calling. Compare the weeks before and after you publish to see what the registry and the catalogs pulling from it bring you, next to your ChatGPT and Claude traffic.

Where else to submit your MCP server

The registry feeds developer catalogs. The AI assistants have their own reviewed directories, each with a separate submission:

Summary

  1. Validate tools, test OAuth and put MCP Tower in front of your server before you publish.
  2. Pick a namespace: io.github.<you>/* with GitHub, or com.example/* with DNS or HTTP.
  3. Add the ownership marker to your package and publish the package, or use remotes only.
  4. Install mcp-publisher.
  5. Run mcp-publisher init, edit server.json, and run mcp-publisher validate.
  6. Log in with mcp-publisher login github, github-oidc, dns or http.
  7. Run mcp-publisher publish.
  8. Check the listing at registry.modelcontextprotocol.io/v0.1/servers.
  9. Publish every change as a new version, and measure what the listing brings.

Publishing to the official MCP Registry takes one config file and one CLI. Do it from behind MCP Tower so the URL you publish is tested, stays yours and is measured from the first call.

Open MCP Tower

Similar articles

ChatGPT plugin directory: a new growth channel

The ChatGPT plugin directory gives an MCP server something it never had before: a listing in front of ChatGPT users, reviewed by OpenAI and backed by a model that decides when to call it. I think this…

Read article: ChatGPT plugin directory: a new growth channel
Claude Marketplace: a new MCP growth channel

Claude Marketplace: a new MCP growth channel

The Claude Marketplace is where Claude users find connectors, and for a team that ships an MCP server it looks a lot like the early App Store: a catalog that lives inside the product people already…

Read article: Claude Marketplace: a new MCP growth channel

Gemini Connected Apps: a new MCP growth channel

Gemini Connected Apps let an MCP server work inside the Gemini app and Google Search, and on October 28, 2026 Google opened the program to more developers with the Connected Apps Platform. For a team…

Read article: Gemini Connected Apps: a new MCP growth channel

Grok Bot Marketplace: a new MCP growth channel

The Grok Bot Marketplace is xAI's new way to get a plugin or MCP server in front of Grok Bot and Cursor users, with Grok itself listed as coming soon. One form on xAI's site covers all three. In this…

Read article: Grok Bot Marketplace: a new MCP growth channel

Muse connectors: a new MCP growth channel

Muse connectors let Meta's personal AI agent use your product while it works on a user's task. If your team ships an MCP server, Meta's new Muse Connector Platform gives it one more place to be found…

Read article: Muse connectors: a new MCP growth channel

Official MCP Registry: a new MCP growth channel

The official MCP Registry is the one place where you publish your MCP server's metadata and let other catalogs pick it up. Before it existed, every directory had its own submission form, pull request…

Read article: Official MCP Registry: a new MCP growth channel

Perplexity connectors: a new MCP growth channel

Perplexity connectors let Perplexity search, read and act in other products on a user's behalf, and the remote ones run on the Model Context Protocol. For a team that ships an MCP server, that makes…

Read article: Perplexity connectors: a new MCP growth channel

How to submit an MCP to Gemini

To submit an app to Gemini, you register your remote MCP server as a Connected App in the Google Connected Console, test it with Gmail accounts, send it for review and then publish it yourself. This…

Read article: How to submit an MCP to Gemini

How to submit a connector to Claude

To submit a connector to Claude, you send your remote MCP server to Anthropic's Connectors Directory from the developer portal, answer a review, and then publish the approved listing yourself. This…

Read article: How to submit a connector to Claude

How to publish an MCP to Muse

To submit a connector to Muse, you sign in to Meta's Muse Connector Platform, describe your MCP server and your business, hand over credentials and a test account, and wait while Meta reviews every…

Read article: How to publish an MCP to Muse

How to publish an MCP in Perplexity

To submit a connector to Perplexity, you send a connector proposal through a Google Form, and Perplexity's Plugins marketplace team decides whether to take it further. The help center documents no…

Read article: How to publish an MCP in Perplexity

How to submit a plugin to ChatGPT

To submit a plugin to ChatGPT, you upload a ZIP bundle to OpenAI's plugin portal, connect a remote MCP server that anyone on the internet can reach, and wait for review. A first review takes months…

Read article: How to submit a plugin to ChatGPT

How to submit a plugin to Grok

To submit a plugin to Grok, you fill in one short form on xAI's site. It asks for your MCP server URL or a public GitHub repository, a description, testing instructions and the places you want to be…

Read article: How to submit a plugin to Grok