## Summary The DNS and HTTP authentication guides currently run `openssl genpkey -algorithm Ed25519 -out key.pem` without caveat. macOS ships LibreSSL as the system `openssl` binary, and LibreSSL doesn't implement Ed25519 in `genpkey` — so the very first command in the Ed25519 codepath errors out with: ``` Algorithm Ed25519 not found ``` A first-time integrator on macOS hits this immediately, with no path to a fix from the docs alone. Cost me ~5 minutes earlier today before I figured out I needed `brew install openssl@3` and an explicit binary path. This PR adds a `<Note>` callout to the **DNS Authentication** section right above the Ed25519 codepath, and a shorter cross-reference Note in the **HTTP Authentication** section since the same `openssl genpkey -algorithm Ed25519` commands appear there. The ECDSA P-384 codepath works on LibreSSL, so it's untouched. ## Test plan - [x] Verified locally that `/opt/homebrew/opt/openssl@3/bin/openssl genpkey -algorithm Ed25519 -out key.pem` works on macOS Darwin 25.4.0 - [x] Verified the system `/usr/bin/openssl genpkey -algorithm Ed25519 -out key.pem` fails with `Algorithm Ed25519 not found` on the same machine (LibreSSL 3.3.6) - [x] Verified the published `ai.ravenmcp/raven-mcp` flow end-to-end with the OpenSSL 3 binary - [ ] Markdown rendering of the `<Note>` callouts — relying on the existing `<Note>` pattern in this file (line 6) to validate the syntax Co-authored-by: Radoslav Dimitrov <radoslav@stacklok.com>
308 lines
12 KiB
Text
308 lines
12 KiB
Text
---
|
|
title: How to Authenticate When Publishing to the Official MCP Registry
|
|
sidebarTitle: Authentication
|
|
---
|
|
|
|
<Note>
|
|
The MCP Registry is currently in preview. Breaking changes or data resets may occur before general availability. If you encounter any issues, please report them on [GitHub](https://github.com/modelcontextprotocol/registry/issues).
|
|
</Note>
|
|
|
|
You must authenticate before publishing to the official MCP Registry. The MCP Registry supports different authentication methods. Which authentication method you choose determines the namespace of your server's name.
|
|
|
|
If you choose GitHub-based authentication, your server's name in `server.json` **MUST** be of the form `io.github.username/*` (or `io.github.orgname/*`). For example, `io.github.alice/weather-server`.
|
|
|
|
If you choose domain-based authentication, your server's name in `server.json` **MUST** be of the form `com.example.*/*`, where `com.example` is the reverse-DNS form of your domain name. For example, `io.modelcontextprotocol/everything`.
|
|
|
|
| Authentication | Name Format | Example Name |
|
|
| -------------- | ----------------------------------------------- | ------------------------------------ |
|
|
| GitHub-based | `io.github.username/*` or `io.github.orgname/*` | `io.github.alice/weather-server` |
|
|
| domain-based | `com.example.*/*` | `io.modelcontextprotocol/everything` |
|
|
|
|
## GitHub Authentication
|
|
|
|
GitHub authentication uses an OAuth flow initiated by the `mcp-publisher` CLI tool.
|
|
|
|
To perform GitHub authentication, navigate to your server project directory and run:
|
|
|
|
```bash
|
|
mcp-publisher login github
|
|
```
|
|
|
|
You should see output like:
|
|
|
|
```text Output
|
|
Logging in with github...
|
|
|
|
To authenticate, please:
|
|
1. Go to: https://github.com/login/device
|
|
2. Enter code: ABCD-1234
|
|
3. Authorize this application
|
|
Waiting for authorization...
|
|
```
|
|
|
|
Visit the link, follow the prompts, and enter the authorization code that was printed in the terminal (e.g., `ABCD-1234` in the above output). Once complete, go back to the terminal, and you should see output like:
|
|
|
|
```text Output
|
|
Successfully authenticated!
|
|
✓ Successfully logged in
|
|
```
|
|
|
|
## DNS Authentication
|
|
|
|
DNS authentication is a domain-based authentication method that relies on a DNS TXT record.
|
|
|
|
<Warning>
|
|
The TXT record must be placed on the **apex** of your domain (e.g. `example.com`), **not** under a selector like `_mcp-auth.example.com` or `_mcp-registry.example.com`. MCP DNS auth follows SPF-style placement (apex), not DKIM-style (selector). If you put the record under a selector, the registry will not see it and authentication will fail with a generic signature error.
|
|
|
|
If you rotate keys, also remember to remove the previous TXT record from the apex — a stale record left behind will be tried first and cause verification to fail.
|
|
</Warning>
|
|
|
|
To perform DNS authentication using the `mcp-publisher` CLI tool, run the following commands in your server project directory to generate a TXT record based on a public/private key pair:
|
|
|
|
<Note>
|
|
The Ed25519 codepath requires **OpenSSL 3.0 or later**. macOS ships with LibreSSL by default (the system `openssl` binary), which does not implement Ed25519 in `genpkey` and fails with `Algorithm Ed25519 not found`. On macOS, install OpenSSL 3 (`brew install openssl@3`) and invoke it explicitly — for example, replace `openssl` with `/opt/homebrew/opt/openssl@3/bin/openssl` (Apple Silicon) or `/usr/local/opt/openssl@3/bin/openssl` (Intel) in the commands below. The ECDSA P-384 codepath works on LibreSSL.
|
|
</Note>
|
|
|
|
<CodeGroup>
|
|
|
|
```bash Ed25519
|
|
MY_DOMAIN="example.com"
|
|
|
|
# Generate public/private key pair using Ed25519
|
|
openssl genpkey -algorithm Ed25519 -out key.pem
|
|
|
|
# Generate TXT record
|
|
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}\""
|
|
```
|
|
|
|
```bash ECDSA P-384
|
|
MY_DOMAIN="example.com"
|
|
|
|
# Generate public/private key pair using ECDSA P-384
|
|
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:secp384r1 -out key.pem
|
|
|
|
# Generate TXT record
|
|
PUBLIC_KEY="$(openssl ec -in key.pem -text -noout -conv_form compressed | grep -A4 "pub:" | tail -n +2 | tr -d ' :\n' | xxd -r -p | base64)"
|
|
echo "${MY_DOMAIN}. IN TXT \"v=MCPv1; k=ecdsap384; p=${PUBLIC_KEY}\""
|
|
```
|
|
|
|
```bash Google KMS
|
|
MY_DOMAIN="example.com"
|
|
MY_PROJECT="myproject"
|
|
MY_KEYRING="mykeyring"
|
|
MY_KEY_NAME="mykey"
|
|
|
|
# Log in using gcloud CLI (https://cloud.google.com/sdk/docs/install)
|
|
gcloud auth login
|
|
|
|
# Set default project
|
|
gcloud config set project "${MY_PROJECT}"
|
|
|
|
# Create a keyring in your project
|
|
gcloud kms keyrings create "${MY_KEYRING}" --location global
|
|
|
|
# Create an Ed25519 signing key
|
|
gcloud kms keys create "${MY_KEY_NAME}" --default-algorithm=ec-sign-ed25519 --purpose=asymmetric-signing --keyring="${MY_KEYRING}" --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="${MY_DOMAIN}" --resource="projects/${MY_PROJECT}/locations/global/keyRings/${MY_KEYRING}/cryptoKeys/${MY_KEY_NAME}/cryptoKeyVersions/1"
|
|
|
|
# Copy the "Expected proof record":
|
|
# ${MY_DOMAIN}. IN TXT "v=MCPv1; k=ed25519; p=${PUBLIC_KEY}"
|
|
```
|
|
|
|
```bash Azure Key Vault
|
|
MY_DOMAIN="example.com"
|
|
MY_SUBSCRIPTION="subscription name or ID"
|
|
MY_RESOURCE_GROUP="MyResourceGroup"
|
|
MY_KEY_VAULT="MyKeyVault"
|
|
MY_KEY_NAME="MyKey"
|
|
|
|
# Log in using Azure CLI (https://learn.microsoft.com/en-us/cli/azure/install-azure-cli)
|
|
az login
|
|
|
|
# Set default subscription
|
|
az account set --subscription "${MY_SUBSCRIPTION}"
|
|
|
|
# Create a resource group
|
|
az group create --location westus --resource-group "${MY_RESOURCE_GROUP}"
|
|
|
|
# Create a key vault
|
|
az keyvault create --name "${MY_KEY_VAULT}" --location westus --resource-group "${MY_RESOURCE_GROUP}"
|
|
|
|
# Create an ECDSA P-384 signing key
|
|
az keyvault key create --name "${MY_KEY_NAME}" --vault-name "${MY_KEY_VAULT}" --curve P-384
|
|
|
|
# Attempt login to show the public key
|
|
mcp-publisher login dns azure-key-vault --domain="${MY_DOMAIN}" --vault "${MY_KEY_VAULT}" --key "${MY_KEY_NAME}"
|
|
|
|
# Copy the "Expected proof record":
|
|
# ${MY_DOMAIN}. IN TXT "v=MCPv1; k=ecdsap384; p=${PUBLIC_KEY}"
|
|
```
|
|
|
|
</CodeGroup>
|
|
|
|
Then add the TXT record using your DNS provider's control panel. It may take several minutes for the TXT record to propagate. After the TXT record has propagated, log in using the `mcp-publisher login` command:
|
|
|
|
<CodeGroup>
|
|
|
|
```bash Ed25519
|
|
MY_DOMAIN="example.com"
|
|
|
|
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}"
|
|
```
|
|
|
|
```bash ECDSA P-384
|
|
MY_DOMAIN="example.com"
|
|
|
|
PRIVATE_KEY="$(openssl ec -in key.pem -noout -text | grep -A4 "priv:" | tail -n +2 | tr -d ' :\n')"
|
|
mcp-publisher login dns --domain "${MY_DOMAIN}" --private-key "${PRIVATE_KEY}"
|
|
```
|
|
|
|
```bash Google KMS
|
|
MY_DOMAIN="example.com"
|
|
MY_PROJECT="myproject"
|
|
MY_KEYRING="mykeyring"
|
|
MY_KEY_NAME="mykey"
|
|
|
|
mcp-publisher login dns google-kms --domain="${MY_DOMAIN}" --resource="projects/${MY_PROJECT}/locations/global/keyRings/${MY_KEYRING}/cryptoKeys/${MY_KEY_NAME}/cryptoKeyVersions/1"
|
|
```
|
|
|
|
```bash Azure Key Vault
|
|
MY_DOMAIN="example.com"
|
|
MY_KEY_VAULT="MyKeyVault"
|
|
MY_KEY_NAME="MyKey"
|
|
|
|
mcp-publisher login dns azure-key-vault --domain="${MY_DOMAIN}" --vault "${MY_KEY_VAULT}" --key "${MY_KEY_NAME}"
|
|
```
|
|
|
|
</CodeGroup>
|
|
|
|
## HTTP Authentication
|
|
|
|
HTTP authentication is a domain-based authentication method that relies on a `/.well-known/mcp-registry-auth` file hosted on your domain. For example, `https://example.com/.well-known/mcp-registry-auth`.
|
|
|
|
To perform HTTP authentication using the `mcp-publisher` CLI tool, run the following commands in your server project directory to generate an `mcp-registry-auth` file based on a public/private key pair:
|
|
|
|
<Note>
|
|
As with DNS authentication, the Ed25519 codepath requires **OpenSSL 3.0 or later**. macOS's system LibreSSL does not support Ed25519 in `genpkey`. See the note in the [DNS Authentication](#dns-authentication) section for the macOS workaround.
|
|
</Note>
|
|
|
|
<CodeGroup>
|
|
|
|
```bash Ed25519
|
|
# Generate public/private key pair using Ed25519
|
|
openssl genpkey -algorithm Ed25519 -out key.pem
|
|
|
|
# Generate mcp-registry-auth file
|
|
PUBLIC_KEY="$(openssl pkey -in key.pem -pubout -outform DER | tail -c 32 | base64)"
|
|
echo "v=MCPv1; k=ed25519; p=${PUBLIC_KEY}" > mcp-registry-auth
|
|
```
|
|
|
|
```bash ECDSA P-384
|
|
# Generate public/private key pair using ECDSA P-384
|
|
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:secp384r1 -out key.pem
|
|
|
|
# Generate mcp-registry-auth file
|
|
PUBLIC_KEY="$(openssl ec -in key.pem -text -noout -conv_form compressed | grep -A4 "pub:" | tail -n +2 | tr -d ' :\n' | xxd -r -p | base64)"
|
|
echo "v=MCPv1; k=ecdsap384; p=${PUBLIC_KEY}" > mcp-registry-auth
|
|
```
|
|
|
|
```bash Google KMS
|
|
MY_DOMAIN="example.com"
|
|
MY_PROJECT="myproject"
|
|
MY_KEYRING="mykeyring"
|
|
MY_KEY_NAME="mykey"
|
|
|
|
# Log in using gcloud CLI (https://cloud.google.com/sdk/docs/install)
|
|
gcloud auth login
|
|
|
|
# Set default project
|
|
gcloud config set project "${MY_PROJECT}"
|
|
|
|
# Create a keyring in your project
|
|
gcloud kms keyrings create "${MY_KEYRING}" --location global
|
|
|
|
# Create an Ed25519 signing key
|
|
gcloud kms keys create "${MY_KEY_NAME}" --default-algorithm=ec-sign-ed25519 --purpose=asymmetric-signing --keyring="${MY_KEYRING}" --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 http google-kms --domain="${MY_DOMAIN}" --resource="projects/${MY_PROJECT}/locations/global/keyRings/${MY_KEYRING}/cryptoKeys/${MY_KEY_NAME}/cryptoKeyVersions/1"
|
|
|
|
# Copy the "Expected proof record" to `./mcp-registry-auth`:
|
|
# v=MCPv1; k=ed25519; p=${PUBLIC_KEY}
|
|
```
|
|
|
|
```bash Azure Key Vault
|
|
MY_DOMAIN="example.com"
|
|
MY_SUBSCRIPTION="subscription name or ID"
|
|
MY_RESOURCE_GROUP="MyResourceGroup"
|
|
MY_KEY_VAULT="MyKeyVault"
|
|
MY_KEY_NAME="MyKey"
|
|
|
|
# Log in using Azure CLI (https://learn.microsoft.com/en-us/cli/azure/install-azure-cli)
|
|
az login
|
|
|
|
# Set default subscription
|
|
az account set --subscription "${MY_SUBSCRIPTION}"
|
|
|
|
# Create a resource group
|
|
az group create --location westus --resource-group "${MY_RESOURCE_GROUP}"
|
|
|
|
# Create a key vault
|
|
az keyvault create --name "${MY_KEY_VAULT}" --location westus --resource-group "${MY_RESOURCE_GROUP}"
|
|
|
|
# Create an ECDSA P-384 signing key
|
|
az keyvault key create --name "${MY_KEY_NAME}" --vault-name "${MY_KEY_VAULT}" --curve P-384
|
|
|
|
# Attempt login to show the public key
|
|
mcp-publisher login http azure-key-vault --domain="${MY_DOMAIN}" --vault "${MY_KEY_VAULT}" --key "${MY_KEY_NAME}"
|
|
|
|
# Copy the "Expected proof record" to `./mcp-registry-auth`:
|
|
# v=MCPv1; k=ecdsap384; p=${PUBLIC_KEY}
|
|
```
|
|
|
|
</CodeGroup>
|
|
|
|
Then host the `mcp-registry-auth` file at `/.well-known/mcp-registry-auth` on your domain. After the file is hosted, log in using the `mcp-publisher login` command:
|
|
|
|
<CodeGroup>
|
|
|
|
```bash Ed25519
|
|
MY_DOMAIN="example.com"
|
|
PRIVATE_KEY="$(openssl pkey -in key.pem -noout -text | grep -A3 "priv:" | tail -n +2 | tr -d ' :\n')"
|
|
mcp-publisher login http --domain "${MY_DOMAIN}" --private-key "${PRIVATE_KEY}"
|
|
```
|
|
|
|
```bash ECDSA P-384
|
|
MY_DOMAIN="example.com"
|
|
PRIVATE_KEY="$(openssl ec -in key.pem -noout -text | grep -A4 "priv:" | tail -n +2 | tr -d ' :\n')"
|
|
mcp-publisher login http --domain "${MY_DOMAIN}" --private-key "${PRIVATE_KEY}"
|
|
```
|
|
|
|
```bash Google KMS
|
|
MY_DOMAIN="example.com"
|
|
MY_PROJECT="myproject"
|
|
MY_KEYRING="mykeyring"
|
|
MY_KEY_NAME="mykey"
|
|
|
|
mcp-publisher login http google-kms --domain="${MY_DOMAIN}" --resource="projects/${MY_PROJECT}/locations/global/keyRings/${MY_KEYRING}/cryptoKeys/${MY_KEY_NAME}/cryptoKeyVersions/1"
|
|
```
|
|
|
|
```bash Azure Key Vault
|
|
MY_DOMAIN="example.com"
|
|
MY_KEY_VAULT="MyKeyVault"
|
|
MY_KEY_NAME="MyKey"
|
|
|
|
mcp-publisher login http azure-key-vault --domain="${MY_DOMAIN}" --vault "${MY_KEY_VAULT}" --key "${MY_KEY_NAME}"
|
|
```
|
|
|
|
</CodeGroup>
|