MCP: drive it from an agent
Let an AI agent discover providers, start domain connections and read their status through the hosted MCP server, with API key or scoped agent token access.
Use the MCP server when an agent (Claude, Cursor, a custom MCP client) should discover providers, start connections and read status on a user's behalf. It is the same control plane behind a tool interface.
Connect
- Endpoint:
https://mcp.customdomain.ai/mcp(Streamable HTTP). - API key: a
cd_live_…key from the console's API & SDK page (an oldersk_key keeps working), sent asAuthorization: Bearer <key>. It works for every tool exceptcreate-domain-order. It carries your whole workspace's authority, so give it only to agents you trust. - Agent token: the scoped option. A person approves exactly which scopes the
agent gets (
domains:read,domains:connect,domains:disconnect,domains:purchase) and can revoke it at any time. See Agent access. - Purchases through MCP are off on the hosted service. Buy a domain in the console instead.
- The console's MCP server page (switch it on in Settings → Features) has ready made setup for each client (with a key) and a connection test.
Set up an agent from the welcome
On the welcome's first question, tick Also let an AI agent connect and manage domains for me and it has one more step, Give your agent access. It is optional, and Not now always works. Pick your agent (Claude Code, Claude Desktop, Codex, Cursor, VS Code, ChatGPT or Other) and the step shows what to add to it: a command, or a few fields to fill in.
- Most agents sign in, so there is no key. A browser opens, you approve what the agent may do, and the step says connected, with the agent's name, only once it signed in and you approved it. A grant you revoked or that expired does not count. The same grant is what Overview shows on its Connect your agent row, and you can end it under Agents (in the sidebar under More).
- Cursor cannot sign in to a new server by itself yet, so it gets the key setup, with your default key from API & SDK (every workspace has one from the start).
- An agent that connects with a key leaves nothing to see, so the step says it cannot watch for it and the checklist does not claim it. Carry on once you have added it.
- A prompt to paste into the agent tells it to read the agent skill, to show you what it plans before anything changes, and what to do first for what you told the welcome: connect your domain, add the widget to your product, or list the domains you added. It never holds a key.
The flow an agent should follow
discover-provider { domain }is read only. It says where the domain's DNS lives and which rails can run:rails,recommendedRailandblockedReason(the same truth asrailsonPOST /v1/domains:check). Do this before promising anything.connect-domain { domain }creates the connection and returns alinkfor the human to complete (sign in with the provider, one click, or the records to add) plus aconnectionId. The agent never writes DNS itself.check-connection-status { connectionId }returns astatusofpending,propagating,liveorfailed. Stop whenconnectedistrue. A failed connection says why inerrorCode.pendinghas no deadline; afailedconnection can be retried by callingconnect-domainagain for the same domain, which revives it.- A domain that is not live yet:
diagnose-connectionsays record by record what public DNS shows and what is missing. Once the person has fixed it,recheck-connectionruns the check now.check-certificate-statusreads the HTTPS certificate; certificates renew on their own. list-connections { status?, limit?, cursor? }lists the connected domains with their status (every application in the workspace when you use an API key). A page that was cut saystruncated: true; call again withnextCursorascursor.
When a connect fails with billing_required, check-billing-status says why and
where an owner fixes it.
Buying: search-domain-availability and generate-domain-suggestions work as
read tools. create-domain-order exists, but ordering is off on the hosted
service. check-order-status and list-domain-orders read orders. Email and
forwarding: add-email, forward-domain.
Re-apply and disconnect
reapply-connectionre-pushes the stored records of a managed connection. A connection with no stored grant answers409(conflict), so readmanagedonlist-connectionsorcheck-connection-statusfirst. See Managed connections.disconnect-domain { connectionId, confirm }removes any connection of the application, managed or not. The domain stops being served and its certificate and monitoring go away. DNS records are removed only where a kept grant wrote them; anywhere else they stay at the provider and the user deletes them. It answers409 removal_in_progresswhile another removal of the same connection is running. The domain goes offline, so ask the person first and send the domain they confirmed asconfirm.- Disconnecting needs the
domains:disconnectscope, which is separate from connecting. A grant approved before that scope existed does not carry it until the person approves the agent again. See Removing a domain.
When a call fails
A failed call is an isError result with success: false, an error code and
details. Branch on the code. A token without the tool's scope gets
insufficient_scope, and an account over its limit (5 calls a second, bursts of
20) gets rate_limited with retryAfterSeconds. See
What a call answers.
Agent authorization
Delegated agent access is live. An agent registers as an OAuth client, a person approves it on the consent page, and the agent gets a 15 minute token limited to the scopes that person approved. Review and revoke agents under Agents, which switches on after your first approval (see Managing access). Full tool reference: MCP server.
Widget, let your customers connect their domains
Let your customers connect domains inside your product: mint a widget token on your server, open the modal, and see what customers get per DNS provider.
How to set up a custom domain
Connect a custom domain to your app end to end: pick the right record, handle the apex, clear CAA and conflicting records, and know when it is actually live.