Complete command reference for the mcp-publisher CLI tool.
See the publishing guide for a walkthrough of using the CLI to publish a server.
Install via Homebrew (macOS/Linux):
$ brew install mcp-publisherAll commands support:
--help,-h- Show command help
--registry is a flag on login only (default: https://registry.modelcontextprotocol.io). The
other commands read the registry URL from the stored login token, so passing --registry to
publish would be interpreted as the server.json path.
Generate a server.json template with automatic detection.
Usage:
mcp-publisher initBehavior:
- Creates
server.jsonin current directory - Auto-detects package managers (
package.json,setup.py, etc.) - Pre-fills fields where possible
- Writes
TODO:placeholders for fields it cannot detect — it is non-interactive and takes no flags
Example output:
{
"name": "io.github.username/server-name",
"description": "TODO: Add server description",
"version": "1.0.0",
"packages": [
{
"registryType": "npm",
"identifier": "detected-package-name",
"version": "1.0.0"
}
]
}Authenticate with the registry.
Authentication Methods:
mcp-publisher login github [--token=PAT] [--registry=URL]- Opens browser for GitHub OAuth flow
- Grants access to
io.github.{username}/*andio.github.{org}/*namespaces --tokensupplies a GitHub Personal Access Token instead of the interactive flow, which is how publishing from GitHub Actions authenticates without a browser. This flag is accepted bylogin githubonly.
Interactive login handles retryable OAuth errors in both HTTP 200 and HTTP 400 responses.
Access denial, expired codes, and unrecognized OAuth errors still stop polling; an
incorrect_device_code error receives at most two additional attempts per login.
mcp-publisher login github-oidc [--registry=URL]- Uses GitHub Actions OIDC tokens automatically
- Requires
id-token: writepermission in workflow - No browser interaction needed
The CLI derives the OIDC aud claim from --registry (scheme + host, e.g.
https://registry.modelcontextprotocol.io) so tokens are bound to the specific
deployment they were minted for. Self-hosters must set
MCP_REGISTRY_GITHUB_OIDC_AUDIENCE on the registry to the matching value;
publishers running an older mcp-publisher will fail with invalid audience
and need to upgrade.
Also see the guide to publishing from GitHub Actions.
mcp-publisher login dns --domain=example.com --private-key=HEX_KEY [--algorithm=ed25519|ecdsap384] [--registry=URL]- Verifies domain ownership via DNS TXT record
- Grants access to
com.example.*namespaces - Requires Ed25519 private key (64-character hex) or ECDSA P-384 private key (96-character hex)
--algorithmdefaults toed25519. For an ECDSA P-384 key you must pass--algorithm ecdsap384, otherwise the key is rejected withinvalid seed length: expected 32 bytes, got 48.- The private key can be stored in a cloud signing provider like Google KMS or Azure Key Vault. Cloud providers derive the algorithm from the key itself, so
--algorithmdoes not apply to them.
Setup: (for Ed25519, recommended)
# Generate keypair
openssl genpkey -algorithm Ed25519 -out key.pem
# Get public key for DNS record
openssl pkey -in key.pem -pubout -outform DER | tail -c 32 | base64
# Add DNS TXT record:
# example.com. IN TXT "v=MCPv1; k=ed25519; p=PUBLIC_KEY"
# Extract private key for login
openssl pkey -in key.pem -noout -text | grep -A3 "priv:" | tail -n +2 | tr -d ' :\n'Setup: (for ECDSA P-384)
# Generate keypair
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:secp384r1 -out key.pem
# Get public key for DNS record
openssl ec -in key.pem -text -noout -conv_form compressed | grep -A4 "pub:" | tail -n +2 | tr -d ' :\n' | xxd -r -p | base64
# Add DNS TXT record:
# example.com. IN TXT "v=MCPv1; k=ecdsap384; p=PUBLIC_KEY"
# Extract private key for login
openssl ec -in <pem path> -noout -text | grep -A4 "priv:" | tail -n +2 | tr -d ' :\n'
# Log in, selecting the ECDSA P-384 algorithm explicitly
mcp-publisher login dns --algorithm ecdsap384 --domain=example.com --private-key=HEX_KEYSetup: (for Google KMS signing)
This requires the gcloud CLI.
# log in and set default project
gcloud auth login
gcloud config set project myproject
# Create a keyring in your project
gcloud kms keyrings create mykeyring --location global
# Create an Ed25519 signing key
gcloud kms keys create mykey --default-algorithm=ec-sign-ed25519 --purpose=asymmetric-signing --keyring=mykeyring --location=global
# Enable Application Default Credentials (ADC) so the publisher tool can sign
gcloud auth application-default login
# Attempt login to show the public key
mcp-publisher login dns google-kms --domain=example.com --resource=projects/myproject/locations/global/keyRings/mykeyring/cryptoKeys/mykey/cryptoKeyVersions/1
# Copy the "Expected proof record" and add the TXT record
# example.com. IN TXT "v=MCPv1; k=ed25519; p=PUBLIC_KEY"
# Re-run the login command
mcp-publisher login dns google-kms --domain=example.com --resource=projects/myproject/locations/global/keyRings/mykeyring/cryptoKeys/mykey/cryptoKeyVersions/1Setup: (for Azure Key Vault signing)
This requires the Azure CLI.
# log in and set default subscription
az login
az account set --subscription "My Subscription (name or ID)"
# Create a resource group
az group create --location westus --resource-group MyResourceGroup
# Create a Key Vault
az keyvault create --name MyKeyVault --location westus --resource-group MyResourceGroup
# Create an ECDSA P-384 signing key
az keyvault key create --name MyKey --vault-name MyKeyVault --curve P-384
# Attempt login to show the public key
mcp-publisher login dns azure-key-vault --domain=example.com --vault MyKeyVault --key MyKey
# Copy the "Expected proof record" and add the TXT record
# example.com. IN TXT "v=MCPv1; k=ecdsap384; p=PUBLIC_KEY"
# Re-run the login command
mcp-publisher login dns azure-key-vault --domain=example.com --vault MyKeyVault --key MyKeymcp-publisher login http --domain=example.com --private-key=HEX_KEY [--algorithm=ed25519|ecdsap384] [--registry=URL]- Verifies domain ownership via HTTPS endpoint
- Grants access to
com.example.*namespaces - Requires Ed25519 private key (64-character hex) or ECDSA P-384 private key (96-character hex)
--algorithmdefaults toed25519. For an ECDSA P-384 key you must pass--algorithm ecdsap384.- The private key can be stored in a cloud signing provider like Google KMS or Azure Key Vault. Cloud providers derive the algorithm from the key itself, so
--algorithmdoes not apply to them.
Setup: (for Ed25519, recommended)
# Generate keypair (same as DNS)
openssl genpkey -algorithm Ed25519 -out key.pem
# Host public key at:
# https://example.com/.well-known/mcp-registry-auth
# Content: v=MCPv1; k=ed25519; p=PUBLIC_KEYSetup: (for ECDSA P-384)
# Generate keypair (same as DNS)
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:secp384r1 -out key.pem
# Host public key at:
# https://example.com/.well-known/mcp-registry-auth
# Content: v=MCPv1; k=ecdsap384; p=PUBLIC_KEY
# Log in, selecting the ECDSA P-384 algorithm explicitly
mcp-publisher login http --algorithm ecdsap384 --domain=example.com --private-key=HEX_KEYCloud signing is also supported for HTTP authentication, similar to the DNS examples above. Just swap out the dns positional argument for http.
mcp-publisher login none [--registry=URL]- No authentication - for local testing only
- Only works with local registry instances
Validate a server.json file without publishing.
Usage:
mcp-publisher validate [file]Arguments:
file- Path to server.json file (default:./server.json)
Behavior:
- Performs exhaustive validation, reporting all issues at once (not just the first error)
- Validates JSON syntax and schema compliance
- Runs semantic validation (business logic checks)
- Checks for deprecated schema versions and provides migration guidance
- Includes detailed error locations with JSON paths (e.g.,
packages[0].transport.url) - Shows validation issue type (json, schema, semantic, linter)
- Displays severity level (error, warning, info)
- Provides schema references showing which validation rule triggered each error
Example output:
$ mcp-publisher validate
✅ server.json is valid
$ mcp-publisher validate custom-server.json
❌ Validation failed with 2 issue(s):
1. [error] repository.url (schema)
'' has invalid format 'uri'
Reference: #/definitions/Repository/properties/url/format from: [#/definitions/ServerDetail]/properties/repository/[#/definitions/Repository]/properties/url/format
2. [error] name (semantic)
server name must be in format 'dns-namespace/name'
Reference: invalid-server-namePublish server to the registry.
For detailed guidance on the publishing process, see the publishing guide.
Usage:
mcp-publisher publish [PATH]Options:
PATH- Path to server.json (default:./server.json)
Process:
- Validates
server.jsonagainst schema - Publishes the
server.jsonto the registry server URL specified in the login token - Server: Verifies package ownership (see Official Registry Requirements)
- Server: Checks namespace authentication
- Server: Publishes to registry
Example:
# Basic publish
mcp-publisher publish
# Custom file location
mcp-publisher publish ./config/server.jsonUpdate the lifecycle status of a published server.
Usage:
mcp-publisher status --status <active|deprecated|deleted> [flags] <server-name> [version]Flags:
--status(required) - New status:active,deprecated, ordeleted--message- Optional message explaining the status change (not allowed when status isactive)--all-versions- Apply status change to all versions of the server--yes,-y- Skip confirmation prompt (only applies when using--all-versions)
Arguments:
server-name- Full server name (e.g.,io.github.user/my-server)version- Server version to update (required unless--all-versionsis set)
Status Values:
active- Server is active and visible in default listingsdeprecated- Server is deprecated but still visible with a warning messagedeleted- Server is hidden from default listings
Examples:
# Deprecate a specific version
mcp-publisher status --status deprecated --message "Please upgrade to 2.0.0" \
io.github.user/my-server 1.0.0
# Delete a version with security issues
mcp-publisher status --status deleted --message "Critical security vulnerability" \
io.github.user/my-server 1.0.0
# Restore a version to active
mcp-publisher status --status active io.github.user/my-server 1.0.0
# Deprecate all versions at once
mcp-publisher status --status deprecated --all-versions --message "Project archived" \
io.github.user/my-serverRequirements:
- Must be logged in with
publishoreditpermission for the server namespace
Clear stored authentication credentials.
Usage:
mcp-publisher logoutBehavior:
- Removes
~/.config/mcp-publisher/token.json - Also cleans up legacy token files (
~/.mcp_publisher_token,.mcpregistry_*) - Does not revoke tokens on server side
Authentication tokens are stored in ~/.config/mcp-publisher/token.json as JSON:
{
"token": "jwt-token-here",
"method": "github",
"registry": "https://registry.modelcontextprotocol.io"
}Note: Tokens were previously stored in
~/.mcp_publisher_token. If you are upgrading, runmcp-publisher logoutfollowed bymcp-publisher loginto migrate to the new location.