Metadata-Version: 2.5
Name: custom-domain-mcp
Version: 0.11.0
Summary: MCP server for the Custom Domain API: let an AI assistant register and check your customers' hostnames.
Project-URL: Homepage, https://customdomainapi.com
Project-URL: Documentation, https://github.com/sireto/custom-domain/blob/main/mcp-server/README.md
Project-URL: Source, https://github.com/sireto/custom-domain/tree/main/mcp-server
Project-URL: Issues, https://github.com/sireto/custom-domain/issues
Author-email: Sireto <info@sireto.com>
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: custom-domain,custom-domains,mcp,model-context-protocol,multi-tenant,saas
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Internet :: WWW/HTTP
Requires-Python: >=3.10
Requires-Dist: custom-domain-sdk>=0.10.0
Requires-Dist: mcp<3,>=2.3
Description-Content-Type: text/markdown

# custom-domain-mcp

An [MCP](https://modelcontextprotocol.io) server for the Custom Domain API.
It lets an AI assistant (Claude, Cursor, any MCP client) register your
customers' hostnames, show them their DNS records, check why a domain isn't
live yet, and recheck or delete it. It acts as one application, with that
application's own API key.

## Setup

```bash
uvx custom-domain-mcp        # or: pip install custom-domain-mcp
```

It reads two settings from the environment:

| Setting | Value |
|---|---|
| `CUSTOM_DOMAIN_API_URL` | your edge, such as `https://edge.example.net` (https only; plain http just for `localhost`) |
| `CUSTOM_DOMAIN_API_KEY` | an application API key (`cd_…`) |

Claude Code:

```bash
claude mcp add custom-domain --env CUSTOM_DOMAIN_API_URL=https://edge.example.net \
  --env CUSTOM_DOMAIN_API_KEY=cd_... -- uvx custom-domain-mcp
```

Claude Desktop, Cursor and other clients (`mcpServers` in their config):

```json
{
  "mcpServers": {
    "custom-domain": {
      "command": "uvx",
      "args": ["custom-domain-mcp"],
      "env": {
        "CUSTOM_DOMAIN_API_URL": "https://edge.example.net",
        "CUSTOM_DOMAIN_API_KEY": "cd_..."
      }
    }
  }
}
```

## Tools

| Tool | Does |
|---|---|
| `create_domain` | Register a customer's hostname for a workspace; returns its DNS records. Safe to retry. |
| `get_domain` | A domain with its status, records and the four checks. |
| `list_domains` | Domains, filtered by workspace or status, paged. |
| `dns_instructions` | The records as text for the customer, with help for each. |
| `recheck_domain` | Run the checks again after a DNS fix (once a minute per domain). |
| `delete_domain` | Stop serving a hostname and delete it (marked destructive). |
| `list_webhooks` | Webhook subscriptions, without secrets. |

## What it can't do

- **No operator actions.** It never holds an operator token, only the
  application's key, so it can do exactly what the application's backend
  can.
- **No webhook creation or rotation.** Their responses carry the signing
  secret, which would end up in the assistant's conversation. Create
  webhooks through the API or the portal.

**Customer data is data, not instructions.** Hostnames, workspace
references, metadata and check messages come from your application's
customers and from DNS. The server tells the assistant to report them,
never to follow them, and to call `delete_domain` only when you explicitly
asked for that domain to be deleted, repeating its hostname back to you
first. Your MCP client's own confirmation for destructive tools adds a
second check.

The server's instructions also tell the assistant the one rule integration
code must follow: select the tenant from the verified
`X-Custom-Domain-Assertion`, never from `Host`
([verifying requests](https://github.com/sireto/custom-domain/blob/main/docs/edge-routing.md)).
