# Publish Your MCP Server
Complete guide to publishing an MCP server to the registry.
## What You'll Learn
By the end of this tutorial, you'll have:
- Created a server.json file for your MCP server
- Authenticated with the registry
- Successfully published your server
- Verified your server appears in the registry
## Prerequisites
- An MCP server you've already built ([follow this guide if you don't have one already](https://modelcontextprotocol.io/quickstart/server))
- Your server published to a package registry (npm, PyPI, Docker Hub, etc.)
## Step 1: Install the Publisher CLI
Download and build the MCP publisher tool:
```bash
# Clone the registry repository (requires Go 1.24+)
git clone https://github.com/modelcontextprotocol/registry
cd registry
make publisher
# The binary will be at cmd/publisher/bin/mcp-publisher
export PATH=$PATH:$(pwd)/cmd/publisher/bin
```
## Step 2: Initialize Your server.json
Navigate to your server's directory and create a template:
```bash
cd /path/to/your/mcp-server
mcp-publisher init
```
This creates a `server.json` with auto-detected values. You'll see something like:
```json
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json",
"name": "io.github.yourname/your-server",
"description": "A description of your MCP server",
"version_detail": {
"version": "1.0.0"
},
"packages": [
{
"registry_type": "npm",
"identifier": "your-package-name",
"version": "1.0.0"
}
]
}
```
## Step 3: Configure Your Server Details
Edit the generated `server.json`:
### Choose Your Namespace
The `name` field determines authentication requirements:
- **`io.github.yourname/*`** - Requires GitHub authentication
- **`com.yourcompany/*`** - Requires DNS or HTTP domain verification
### Add Package Validation
Your package must include validation metadata to prove ownership.
📦 NPM Packages
### Requirements
Add an `mcpName` field to your `package.json`:
```json
{
"name": "your-npm-package",
"version": "1.0.0",
"mcpName": "io.github.username/server-name"
}
```
### How It Works
- Registry fetches `https://registry.npmjs.org/your-npm-package`
- Checks that `mcpName` field matches your server name
- Fails if field is missing or doesn't match
### Example server.json
```json
{
"name": "io.github.username/server-name",
"packages": [
{
"registry_type": "npm",
"identifier": "your-npm-package",
"version": "1.0.0"
}
]
}
```
The official MCP registry currently only supports the NPM public registry (`https://registry.npmjs.org`).
🐍 PyPI Packages
### Requirements
Include your server name in your package README file using this format:
**MCP name format**: `mcp-name: io.github.username/server-name`
Add it to your README.md file (which becomes the package description on PyPI).
### How It Works
- Registry fetches `https://pypi.org/pypi/your-package/json`
- Passes if `mcp-name: server-name` is in the README content
### Example server.json
```json
{
"name": "io.github.username/server-name",
"packages": [
{
"registry_type": "pypi",
"identifier": "your-pypi-package",
"version": "1.0.0"
}
]
}
```
The official MCP registry currently only supports the official PyPI registry (`https://pypi.org`).
📋 NuGet Packages
### Requirements
Include your server name in your package's README using this format:
**MCP name format**: `mcp-name: io.github.username/server-name`
Add a README file to your NuGet package that includes the server name.
### How It Works
- Registry fetches README from `https://api.nuget.org/v3-flatcontainer/{id}/{version}/readme`
- Passes if `mcp-name: server-name` is found in the README content
### Example server.json
```json
{
"name": "io.github.username/server-name",
"packages": [
{
"registry_type": "nuget",
"identifier": "Your.NuGet.Package",
"version": "1.0.0"
}
]
}
```
The official MCP registry currently only supports the official NuGet registry (`https://api.nuget.org`).
🐳 Docker/OCI Images
### Requirements
Add an annotation to your Docker image:
```dockerfile
LABEL io.modelcontextprotocol.server.name="io.github.username/server-name"
```
### How It Works
- Registry authenticates with Docker Hub using public token
- Fetches image manifest using Docker Registry v2 API
- Checks that `io.modelcontextprotocol.server.name` annotation matches your server name
- Fails if annotation is missing or doesn't match
### Example server.json
```json
{
"name": "io.github.username/server-name",
"packages": [
{
"registry_type": "oci",
"identifier": "yourusername/your-mcp-server",
"version": "1.0.0"
}
]
}
```
The identifier is `namespace/repository`, and version is the tag and optionally digest.
The official MCP registry currently only supports the official Docker registry (`https://docker.io`).
📁 MCPB Packages
### Requirements
**MCP reference** - MCPB package URLs must contain "mcp" somewhere within them, to ensure the correct artifact has been uploaded. This may be with the `.mcpb` extension or in the name of your repository.
### Example server.json
```json
{
"name": "io.github.username/server-name",
"packages": [
{
"registry_type": "mcpb",
"identifier": "https://github.com/you/your-repo/releases/download/v1.0.0/server.mcpb"
}
]
}
```
The official MCP registry currently only supports artifacts hosted on GitHub or GitLab releases.
## Step 4: Authenticate
Choose your authentication method based on your namespace:
### GitHub Authentication (for io.github.* namespaces)
```bash
mcp-publisher login github
```
This opens your browser for OAuth authentication.
### DNS Authentication (for custom domains)
```bash
# Generate keypair
openssl genpkey -algorithm Ed25519 -out key.pem
# Get public key for DNS record
echo "_mcp-registry.yourcompany.com. IN TXT \"v=MCPv1; k=ed25519; p=$(openssl pkey -in key.pem -pubout -outform DER | tail -c 32 | base64)\""
# Add the TXT record to your DNS, then login
mcp-publisher login dns --domain yourcompany.com --private-key $(openssl pkey -in key.pem -noout -text | grep -A3 "priv:" | tail -n +2 | tr -d ' :\n')
```
## Step 5: Publish Your Server
With authentication complete, publish your server:
```bash
mcp-publisher publish
```
You'll see output like:
```
✓ Validating server.json
✓ Checking package ownership
✓ Publishing to registry
✓ Server published successfully!
Your server is now available at:
https://registry.modelcontextprotocol.io/servers/io.github.yourname/weather-server
```
## Step 6: Verify Publication
Check that your server appears in the registry:
```bash
curl https://registry.modelcontextprotocol.io/servers/io.github.yourname/weather-server
```
You should see your server metadata returned as JSON.
## Troubleshooting
**"Package validation failed"** - Ensure your package includes the required validation metadata (mcpName field, README mention, or Docker label).
**"Authentication failed"** - Verify you've correctly set up DNS records or are logged into the right GitHub account.
**"Namespace not authorized"** - Your authentication method doesn't match your chosen namespace format.
## Next Steps
- **Update your server**: Publish new versions with updated server.json files
- **Set up CI/CD**: Automate publishing with [GitHub Actions](github-actions.md)
- **Learn more**: Understand [server.json format](../../reference/server-json/generic-server-json.md) in depth
## What You've Accomplished
You've successfully published your first MCP server to the registry! Your server is now discoverable by MCP clients and can be installed by users worldwide.