# Publisher CLI Commands Reference Complete command reference for the `mcp-publisher` CLI tool. See the [publishing guide](../../modelcontextprotocol-io/quickstart.mdx) for a walkthrough of using the CLI to publish a server. ## Installation Install via Homebrew (macOS/Linux): ```bash $ brew install mcp-publisher ``` ## Global Options All 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. ## Commands ### `mcp-publisher init` Generate a `server.json` template with automatic detection. **Usage:** ```bash mcp-publisher init ``` **Behavior:** - Creates `server.json` in 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:** ```json { "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" } ] } ``` ### `mcp-publisher login ` Authenticate with the registry. **Authentication Methods:** #### GitHub Interactive ```bash mcp-publisher login github [--token=PAT] [--registry=URL] ``` - Opens browser for GitHub OAuth flow - Grants access to `io.github.{username}/*` and `io.github.{org}/*` namespaces - `--token` supplies a GitHub Personal Access Token instead of the interactive flow, which is how [publishing from GitHub Actions](../../modelcontextprotocol-io/github-actions.mdx) authenticates without a browser. This flag is accepted by `login github` only. 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. #### GitHub OIDC (CI/CD) ```bash mcp-publisher login github-oidc [--registry=URL] ``` - Uses GitHub Actions OIDC tokens automatically - Requires `id-token: write` permission 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](../../modelcontextprotocol-io/github-actions.mdx). #### DNS Verification ```bash 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) - `--algorithm` defaults to `ed25519`. **For an ECDSA P-384 key you must pass `--algorithm ecdsap384`**, otherwise the key is rejected with `invalid 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 `--algorithm` does not apply to them. **Setup:** (for Ed25519, recommended) ```bash # 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) ```bash # 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 -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_KEY ``` **Setup:** (for Google KMS signing) This requires the [gcloud CLI](https://cloud.google.com/sdk/docs/install). ```bash # 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/1 ``` **Setup:** (for Azure Key Vault signing) This requires the [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest). ```bash # 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 MyKey ``` #### HTTP Verification ```bash mcp-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) - `--algorithm` defaults to `ed25519`. **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 `--algorithm` does not apply to them. **Setup:** (for Ed25519, recommended) ```bash # 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_KEY ``` **Setup:** (for ECDSA P-384) ```bash # 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_KEY ``` Cloud signing is also supported for HTTP authentication, similar to the DNS examples above. Just swap out the `dns` positional argument for `http`. #### Anonymous (Testing) ```bash mcp-publisher login none [--registry=URL] ``` - No authentication - for local testing only - Only works with local registry instances ### `mcp-publisher validate` Validate a `server.json` file without publishing. **Usage:** ```bash 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:** ```bash $ 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-name ``` ### `mcp-publisher publish` Publish server to the registry. For detailed guidance on the publishing process, see the [publishing guide](../../modelcontextprotocol-io/quickstart.mdx). **Usage:** ```bash mcp-publisher publish [PATH] ``` **Options:** - `PATH` - Path to server.json (default: `./server.json`) **Process:** 1. Validates `server.json` against schema 2. Publishes the `server.json` to the registry server URL specified in the login token 3. Server: Verifies package ownership (see [Official Registry Requirements](../server-json/official-registry-requirements.md)) 4. Server: Checks namespace authentication 5. Server: Publishes to registry **Example:** ```bash # Basic publish mcp-publisher publish # Custom file location mcp-publisher publish ./config/server.json ``` ### `mcp-publisher status` Update the lifecycle status of a published server. **Usage:** ```bash mcp-publisher status --status [flags] [version] ``` **Flags:** - `--status` (required) - New status: `active`, `deprecated`, or `deleted` - `--message` - Optional message explaining the status change (not allowed when status is `active`) - `--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-versions` is set) **Status Values:** - `active` - Server is active and visible in default listings - `deprecated` - Server is deprecated but still visible with a warning message - `deleted` - Server is hidden from default listings **Examples:** ```bash # 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-server ``` **Requirements:** - Must be logged in with `publish` or `edit` permission for the server namespace ### `mcp-publisher logout` Clear stored authentication credentials. **Usage:** ```bash mcp-publisher logout ``` **Behavior:** - Removes `~/.config/mcp-publisher/token.json` - Also cleans up legacy token files (`~/.mcp_publisher_token`, `.mcpregistry_*`) - Does not revoke tokens on server side ## Configuration ### Token Storage Authentication tokens are stored in `~/.config/mcp-publisher/token.json` as JSON: ```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, run `mcp-publisher logout` followed by `mcp-publisher login` to migrate to the new location.