auth: Add HTTP-based authentication support to validate domain ownership (#282)

Add HTTP-based authentication to prove domain ownership, similar to
https://github.com/modelcontextprotocol/registry/pull/238's DNS
authentication but using HTTPS well-known URIs instead of DNS TXT
records.

Fixes #280

## Motivation and Context

Some organizations don't have easy access to DNS records, but can easily
deploy web assets. They would therefore prefer to be able to complete a
HTTP challenge rather than a DNS one to authenticate to the registry.

This would in some way mirror ACME challenges: where you can do a DNS-01
or a HTTP-01 challenge.

## How Has This Been Tested?

- Tested locally by stubbing out the HTTP getter
- Added unit tests

## Breaking Changes

None

## Types of changes
<!-- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update

## Checklist
<!-- Go over all the following points, and put an `x` in all the boxes
that apply. -->
- [x] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
- [x] My code follows the repository's style guidelines
- [x] New and existing tests pass locally
- [x] I have added appropriate error handling
- [x] I have added or updated documentation as needed

## Additional context

I concern I had when building this that it might expose us to SSRF
attacks.

I think on reflection this is not a significant problem:
- We only GET a fixed file `.well-known/mcp-registry-auth` (redirects
disallowed) after sanitizing the domain, and then also don't expose the
response to the user. This means the user shouldn't be able to hit
anything very interesting.
- The information they might get is what domains/servers exist in the
network. Our infrastructure is already all open-source, so attackers
aren't getting any additional real info by prodding at the environment
this way.
This commit is contained in:
adam jones 2025-08-21 23:13:09 +01:00 • committed by GitHub
commit ee910ca286
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -49,9 +49,12 @@ The tool supports two main commands:
- `github-at`: Interactive GitHub OAuth device flow authentication
- `github-oidc`: GitHub Actions OIDC authentication (for CI/CD)
- `dns`: DNS-based public/private key authentication
- `http`: HTTP-based public/private key authentication
- `none`: No authentication (for registry contributors testing locally)
- `--dns-domain`: Domain name for DNS authentication (required for dns auth method)
- `--dns-private-key`: 64-character hex seed for DNS authentication (required for dns auth method)
- `--http-domain`: Domain name for HTTP authentication (required for http auth method)
- `--http-private-key`: 64-character hex seed for HTTP authentication (required for http auth method)
## Creating a server.json file
@ -210,6 +213,31 @@ For domain-based authentication using public/private key cryptography:
This grants publishing permissions for both `example.com/*` and `*.example.com/*` namespaces.
### HTTP Authentication (`http`)
For domain-based authentication using HTTP-hosted public keys:
1. **Generate Ed25519 keypair**:
```bash
openssl genpkey -algorithm Ed25519 -out /tmp/key.pem && \
echo "\n\nFile to host on your domain:" && \
echo " URL: https://yoursite.com/.well-known/mcp-registry-auth" && \
echo " Content: v=MCPv1; k=ed25519; p=$(openssl pkey -in /tmp/key.pem -pubout -outform DER | tail -c 32 | base64)" && \
echo "" && \
echo "Private key for --http-private-key flag:" && \
echo " $(openssl pkey -in /tmp/key.pem -noout -text | grep -A3 "priv:" | tail -n +2 | tr -d ' :\n')\n" && \
rm /tmp/key.pem
```
2. **Host public key**: Create an HTTP endpoint at `https://yoursite.com/.well-known/mcp-registry-auth` that returns: `v=MCPv1; k=ed25519; p=<base64-public-key>`
3. **Use CLI arguments**: Provide domain and private key via command line flags
```bash
./bin/mcp-publisher publish --registry-url <REGISTRY_URL> --mcp-file <PATH_TO_MCP_FILE> \
--auth-method http --http-domain example.com --http-private-key abc123...
```
This grants publishing permissions for the `example.com/*` namespace.
### No Authentication (`none`)
Mainly for registry contributors, for testing locally: