Custom Domain
MCP

MCP server

The Model Context Protocol server — six domain tools an AI agent can call over JSON-RPC, its transports, and its auth.

Customdomain ships an optional Model Context Protocol (MCP) server so an AI agent can search for, register, and connect domains through the same control-plane /v1 API — without ever handling DNS records itself. It runs as a separate process (services/mcp) and wraps the control-plane; it adds no business logic of its own.

The server reports itself as customdomain-mcp (protocol revision 2025-06-18) and advertises only the tools capability.

Tools

The server registers six tools, in a fixed order. None of them takes DNS records as input — records always come from the control-plane server-side, so an agent can never inject them.

ToolArgumentsWhat it does
search-domain-availability{ domain }Check whether a domain is available to register, with real-time price + renewal price.
generate-domain-suggestions{ keywords, limit? }Return available-to-register suggestions for a set of keywords (default 5, min 5, max 20), each priced; the cheapest is marked the top pick.
create-domain-order{ domain }Start a registration/purchase through the resolved registrar. Enterprise/direct registrars return an orderId; sharing registrars return a checkout link + jobId to poll.
connect-domain{ domain }Start a guided DNS-configuration flow for a domain the user already owns. Returns a link for the user and a jobId to poll. Never writes DNS directly.
check-connection-status{ jobId }Read the live status of a connection job. Statuses: pending, propagating, completed, failed, error, expired.
check-order-status{ orderId } or { jobId }Read the live status of a domain order — by orderId (enterprise) or jobId (sharing). Provide exactly one.

create-domain-order is fail-closed. The server places a paid order only after a successful call to the integrator's purchase-authorization callback (MCP_PURCHASE_AUTHZ_URL, HTTP Basic). If that callback is unset, every purchase is denied — the safe default. Registrar purchasing is also gated on the control-plane by SELL_PURCHASE_ENABLED, which is off on the hosted service.

Transports

The server binary (cmd/mcp) speaks two transports, selected with -transport:

  • stdio (default) — line-delimited JSON-RPC on stdin/stdout, one message per line. This is what a locally-launched host (or mcp-remote) uses when it runs the server as a subprocess. It authenticates with a single static control-plane credential (-bearer / JUSTEASY_API_TOKEN).

  • http — a Streamable-HTTP style endpoint. Three routes:

    RoutePurpose
    POST /mcpThe MCP JSON-RPC endpoint. Requires Authorization: Bearer (unless started with -insecure for local dev).
    POST /tokenOAuth 2.0 client-credentials grant — exchange client_id + client_secret for a short-lived Bearer.
    GET /healthzLiveness.

The hosted server is at https://mcp.customdomain.ai.

Authentication

POST /token proxies the control-plane's POST /v1/tokens: it exchanges an application's client_id + client_secret (also accepted as application_id) for a widget JWT. Credentials may be sent as HTTP Basic auth, form fields, or a JSON body; the only supported grant_type is client_credentials.

# Mint a short-lived Bearer
curl -X POST https://mcp.customdomain.ai/token \
  -u "<APPLICATION_ID>:<CLIENT_SECRET>" \
  -d "grant_type=client_credentials"
# → { "access_token": "eyJ…", "token_type": "Bearer", "expires_in": 3600 }

POST /mcp accepts three Bearer forms, so hosts that can't run the token dance still authenticate:

  1. a JWT minted by /token,
  2. a console API key (sk_live_… / sk_test_…),
  3. the mcp-remote shortcut CLIENT_ID:CLIENT_SECRET, which the server exchanges for a JWT on the fly.

The MCP server never validates tokens cryptographically itself — it forwards the caller's credential to the control-plane, which is the authority and rejects bad credentials on every wrapped call.

# Call a tool
curl -X POST https://mcp.customdomain.ai/mcp \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
       "params":{"name":"search-domain-availability","arguments":{"domain":"example.com"}}}'

Configuration

The http transport reads these (flags shown; each has an env alias):

Flag / envPurpose
-api / MCP_API_BASEControl-plane base URL (default https://api.customdomain.ai).
-addr / MCP_ADDRHTTP listen address (default :8080).
-link-base / MCP_LINK_BASEConsole URL prefix for guided-DNS fallback links.
-preferred-registrar / MCP_PREFERRED_REGISTRARRegistrar tried first during order resolution.
-purchase-authz-url/-user/-pass / MCP_PURCHASE_AUTHZ_*The fail-closed purchase-authorization callback. Unset ⇒ purchases denied.
-insecure / MCP_INSECURE=1Serve /mcp without Bearer auth — local development only.

On this page