DoDomain

DoDomain MCP server: Claude, ChatGPT, Cursor

DoDomain remote MCP server: one URL, OAuth 2.1 sign-in, every dashboard action as a tool. Setup for Claude, ChatGPT, Cursor, Codex and other MCP clients.

DoDomain ships a remote MCP (Model Context Protocol) server, so AI assistants and agents (Claude, coding agents, anything that speaks MCP) can check a domain's DNS provider, mint a connect session, hand your user the hosted connect link, and verify DNS, using the same REST API and permissions your integration already has.

Pick your tool in the box at the top of this page: Claude and ChatGPT open DoDomain's own listing, Cursor and VS Code add the server in one click, and coding agents get one prompt to paste. The manual setup for each client follows.

One URL, nothing else to configure

The server lives at:

https://app.dodomain.io/api/mcp

How sign-in works

It speaks Streamable HTTP (stateless) and authenticates with OAuth 2.1 (PKCE plus dynamic client registration), publishing the standard discovery documents (RFC 9728 protected-resource and RFC 8414 authorization-server metadata). MCP clients find the authorization server, register themselves, and start the sign-in flow automatically. You add the URL, sign in with your DoDomain account, and approve the requested scopes on the consent page. No API keys, no manual client setup.

Claude Code

claude mcp add --transport http dodomain https://app.dodomain.io/api/mcp

Start a new session, run /mcp, pick dodomain and choose Authenticate.

Codex

codex mcp add dodomain --url https://app.dodomain.io/api/mcp
codex mcp login dodomain

Cursor

Add the server to ~/.cursor/mcp.json (every project) or .cursor/mcp.json (one project), merging into mcpServers if the file exists:

{
  "mcpServers": {
    "dodomain": {
      "url": "https://app.dodomain.io/api/mcp"
    }
  }
}

OpenCode

Add the server to opencode.json in the project root (or ~/.config/opencode/opencode.json), then sign in:

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "dodomain": {
      "type": "remote",
      "url": "https://app.dodomain.io/api/mcp",
      "enabled": true
    }
  }
}
opencode mcp auth dodomain

GitHub Copilot (VS Code)

Add the server to .vscode/mcp.json, then start it from MCP: List Servers and sign in when VS Code asks:

{
  "servers": {
    "dodomain": {
      "type": "http",
      "url": "https://app.dodomain.io/api/mcp"
    }
  }
}

Claude.ai

DoDomain is listed in Claude's connector directory: open the listing, click Connect, then approve the DoDomain sign-in. By hand, as a custom connector: in Claude's web or desktop app, open Settings → Connectors → Add custom connector and paste the URL above as the remote MCP server URL. Claude walks you through the DoDomain sign-in and consent screen, then the tools appear in your conversations.

Connect from any MCP client

Any client that supports remote MCP servers over Streamable HTTP with OAuth works the same way: give it the URL below, sign in to DoDomain when the browser opens, and approve the scopes. The URL is the only configuration. Claude Code, Codex, Cursor, OpenCode, GitHub Copilot and Claude.ai have their own sections above; the other common clients follow.

https://app.dodomain.io/api/mcp

ChatGPT

One click: Open DoDomain in ChatGPT opens DoDomain's published ChatGPT app; click Connect, then sign in. Manual: Settings → Apps & Connectors → Create (developer mode), name it DoDomain, paste the URL, authentication OAuth. (For the Codex CLI, see Codex above.)

Google Antigravity

Install the plugin from the repository (or from the Antigravity Marketplace once listed):

agy plugin install https://github.com/DevinoSolutions/mcp-servers/antigravity-plugins/dodomain

Or add the server by hand in ~/.gemini/config/mcp_config.json (Antigravity requires the serverUrl key):

{ "mcpServers": { "dodomain": { "serverUrl": "https://app.dodomain.io/api/mcp" } } }

Gemini

  • Gemini app: Settings → Connected apps → Custom apps → Add a custom app, paste the URL, then mention @DoDomain in a chat. (Custom apps are currently limited to personal Google accounts in the US.)
  • Gemini CLI: gemini extensions install https://github.com/DevinoSolutions/mcp-servers then /mcp auth dodomain, or add { "mcpServers": { "dodomain": { "httpUrl": "https://app.dodomain.io/api/mcp" } } } to ~/.gemini/settings.json.

Kiro

One click: Add to Kiro. Or in .kiro/settings/mcp.json:

{ "mcpServers": { "dodomain": { "url": "https://app.dodomain.io/api/mcp" } } }

Perplexity, Mistral Le Chat, Grok

  • Perplexity (Pro, Max, Enterprise): Settings → Connectors → Custom connector, paste the URL, authentication OAuth.
  • Mistral Le Chat (all plans): Intelligence → Connectors → Add Connector → Custom MCP Connector, paste the URL.
  • Grok: grok.com → Connectors → New connector → Custom, paste the URL.

Other clients

  • Replit: Add to Replit, or Integrations → Add MCP server.
  • Devin, Windsurf, Zed, JetBrains Junie, Cline, MCP Inspector, your own agent built on an MCP SDK: add a remote (HTTP) MCP server with the URL above; each prompts for the OAuth sign-in on first use. Cline can also install it from the Cline marketplace entry using its llms-install.md.

Tokens are scoped to what you approve on the consent screen; a tool you did not grant is never shown to the assistant. Revoke access at any time: ask the assistant to run revoke_connected_app (it asks for a confirmation first), or use the Connected apps page; see Revoking access.

The tools

Everything you can do in the DoDomain dashboard, your assistant can do by calling a tool: check a domain, create apps and connect sessions, manage API keys and webhook endpoints, read sessions and deliveries, invite teammates, upgrade or cancel your plan, open a support request, and delete things when you say so. A new team can start from chat: call create_app with a name and the permissions you choose for its key, then pass its returned id as appId to create_connect_session.

Anything that needs your hands, such as typing a card number, finishing a Cloudflare sign-in or signing in with Google, comes back as a one-time link the assistant gives you (see Handoff links). Everything else runs through the tool.

The server uses Code Mode. Its tool list has two tools, search_tools and execute_typescript, not one tool per row below. Your assistant calls search_tools to find the tools below, then runs a short TypeScript program through execute_typescript that calls them. Each call goes through the same scope and team checks as a direct call, and a refused call comes back as an error inside the program, such as SCOPE_MISSING or TEAM_REQUIRED. Tools that delete or cancel something return CONFIRMATION_REQUIRED first and act only when called again with the one-time token (see Confirmations).

Where a decision is yours, the tool takes it as a required argument and the assistant asks you instead of choosing: the plan and billing interval, which permissions a new key gets, whether a rotated key overlaps the old one, a teammate's role, and the exact app name or account email you type to confirm a deletion. A call that leaves one out is refused with VALIDATION_ERROR, and next.args shows the argument as <ask the user: ...>.

ToolWhat it doesScopeAccess
accept_team_invitationAccept a team invitation as the signed-in person, using the token from the invitation link.teams:writeWrites
add_webhook_endpointRegister an HTTPS URL that receives this app's signed webhooks (session.* and connection.* events).webhooks:writeWrites
billing_statusThe team's plan, subscription state (status, billing interval, trial), this month's verified-connection usage against the plan cap, and the app count against the app limit.billing:readRead-only
check_domainPre-flight a domain before connecting it.domains:readRead-only
convert_guest_accountTurn a guest account into a permanent one.account:writeWrites
create_api_keyMint an additional secret key for an app with a label and the permission groups it may use.keys:writeWrites
create_appCreate an app in the team (admins and owners; limited by the plan's app cap, QUOTA_EXCEEDED points at upgrade_plan).apps:writeWrites
create_connect_sessionStart a domain-connect session so an end user can point their domain at the integrator's product.sessions:writeWrites
create_shared_setup_linkMint (or rotate) the shared setup link for a session: a page the end user can forward to whoever edits their DNS.sessions:writeWrites
create_support_ticketSend a support request to the DoDomain team on the signed-in person's behalf.support:writeWrites
create_teamCreate a new team owned by the signed-in person and make it their active team.teams:writeWrites
decline_team_ownershipTurn down an ownership invitation sent to the signed-in person.teams:writeWrites
delete_accountPermanently delete the signed-in person's DoDomain account and every team they solely own.account:deleteConfirms first
delete_appPermanently delete an app and everything under it (owners only).apps:deleteConfirms first
delete_teamDelete a team once it is empty: no apps, no subscription, and you are its only member (owners only).teams:deleteConfirms first
delete_webhook_endpointStop delivering to an endpoint.webhooks:deleteConfirms first
detect_connect_sessionRun DNS-provider detection for a session and persist the detected tier (what the hosted flow does when it opens).sessions:writeWrites
disconnectDisconnect something.connections:writeConfirms first
disconnect_sign_in_methodRemove one way to sign in (accountId from list_sign_in_methods).account:writeConfirms first
export_dataExport data.account:writeRead-only
get_connect_linksClick-ready links for the connect flows that finish in a browser.connections:writeWrites
get_connect_sessionFetch the current state of one domain-connect session by its sessionToken (the token returned by create_connect_session).sessions:readRead-only
get_connectionRead one connection by id (from list_connections or a connection.* webhook): domain, recordFqdns, status (active or broken), verifiedAt, lastCheckedAt, brokenAt and disconnectedAt.connections:readRead-only
get_notification_inbox_sessionThe session details the in-app notification bell needs for this person (application id, subscriber id and hash).account:readRead-only
get_profileThe signed-in person's profile: name, email, display currency, the tips-and-prompts preference, whether the account is a guest, and every team with their role.account:readRead-only
get_referralThe person's Refer and Earn state: their referral link, click, sign-up and sale counts, and upcoming versus paid earnings.account:readRead-only
get_webhook_deliveryOne webhook delivery: its status, how many attempts were made and the last error.webhooks:readRead-only
invite_memberInvite someone to the team by email (admins and owners only).teams:writeWrites
leave_teamLeave the team.teams:writeConfirms first
list_api_keysThe app's API keys: the primary secret key and any additional ones, each with its label, the permission groups it holds, when it was created and (for the primary key) when the previous key stops working.keys:readRead-only
list_appsList the apps in one team.apps:readRead-only
list_connected_appsThe AI apps the person has connected to their DoDomain account, with the permission groups each holds and when it was last used.grants:readRead-only
list_connectionsList verified domain connections and their live DNS health, in one team.connections:readRead-only
list_granted_scopesWhat this very connection may do: its permission groups, the exact scopes, and the teams it reaches.grants:readRead-only
list_invitesPending team invitations with the invited email, role, state (pending or expired) and expiry.teams:readRead-only
list_membersEveryone on the team with their role (owner, admin, member) and when they joined.teams:readRead-only
list_plansThe paid plans with monthly and annual prices, caps and highlights, and which one is current.billing:readRead-only
list_sessionsThe team's connect sessions, newest first (50 per page; pass nextCursor back as cursor).sessions:readRead-only
list_sign_in_methodsThe ways into the signed-in person's own account (Google, Apple, email and password), each with its accountId and whether disconnect_sign_in_method may remove it.account:readRead-only
list_support_ticketsThe support requests this person has sent, newest first, last 50: ticketId, type, subject, a preview and when.support:readRead-only
list_teamsList the teams this connection can use: each team's id and name.teams:readRead-only
list_vercel_connectionsThe team's Vercel connections: which app each belongs to, the Vercel account, and the linked projects.connections:readRead-only
list_webhook_deliveriesThe team's webhook delivery log, newest first (50 per page; pass nextCursor back as cursor).webhooks:readRead-only
list_webhook_endpointsThe webhook endpoints of an app: id, URL, creation time and pausedAt (set while the endpoint is auto-paused after repeated failures).webhooks:readRead-only
manage_subscriptionManage the team's subscription.billing:writeConfirms first
redrive_webhook_deliverySend a failed or skipped delivery again with its original id.webhooks:writeWrites
remove_memberRemove a teammate from the team.teams:writeConfirms first
rename_appRename an app.apps:writeWrites
request_scopesAsk the user for more access.grants:readWrites
resume_webhook_endpointResume an auto-paused endpoint.webhooks:writeWrites
reverify_connectionQueue an on-demand DNS health recheck of ONE existing connection (find its id via list_connections).connections:writeWrites
revoke_api_keyRevoke one additional key of an app by its id (from list_api_keys).keys:writeConfirms first
revoke_connected_appDisconnect an AI app from the person's account by its id (from list_connected_apps).grants:writeConfirms first
revoke_inviteCancel a pending invitation by its id (from list_invites).teams:writeWrites
rotate_api_keyReplace the app's primary secret key.keys:writeWrites
rotate_webhook_secretMint a new signing secret for an endpoint.webhooks:rotateWrites
run_dns_toolDoDomain's keyless DNS tools.domains:readRead-only
send_test_webhook_eventSend a session.completed-shaped test event (payload marked test:true) to one endpoint.webhooks:writeWrites
switch_active_teamPoint the person's dashboard at one of their teams.teams:writeWrites
update_app_allowed_originsReplace the app's allowed origins with exactly this list (send the whole list; origins are normalised and de-duplicated).apps:writeWrites
update_app_brandingChange the end-user-facing branding of the connect flow: logoUrl (https), brandColor (#RRGGBB), and on Pro/Scale the headline, subheadline, success button label and redirect, font preset and footer-help toggle.apps:writeWrites
update_app_tls_issuerSet (or clear with an empty string) the CAA issuer domain of the certificate authority this app's customers' certificates come from, e.g.apps:writeWrites
update_member_roleChange a teammate's role (owners only).teams:writeWrites
update_notification_prefsChange notification preferences: the tips-and-prompts switch (promptsEnabled).account:writeWrites
update_profileChange the profile name and/or display currency.account:writeWrites
update_webhook_endpointPoint an existing endpoint at a new HTTPS URL.webhooks:writeWrites
upgrade_planStart a purchase or a plan change.billing:writeWrites
verify_connect_sessionTrigger a live DNS check of a session's expected records against authoritative nameservers.sessions:writeWrites

Teams

If you belong to more than one DoDomain team, the consent screen asks which ones the connection can use: the teams you tick (your current team is ticked to start with), or All my teams, which also covers teams you join later. The connection can act on a team only while you are still a member of it; leave a team and the connection loses it on the next request. If you rejoin a team the connection was granted, it can use that team again; to stop that, disconnect the client (revoke_connected_app, or the Connected apps page) or connect it again without that team. To change the teams later, connect the client again and choose again: the new choice replaces the old one for the whole connection, including the access tokens the client already holds.

When a connection covers more than one team, the agent says which team each call is for. list_teams returns the teams it can use, and the tools that read or write team data (check_domain, list_apps, create_app, list_connections, create_connect_session, reverify_connection) take an optional teamId. With more than one team, a call without teamId is refused with TEAM_REQUIRED (except check_domain, whose answer does not depend on the team), and a call naming a team the connection cannot use is refused with TEAM_NOT_FOUND; both list the usable teams. With a single team, teamId can be left out.

Over REST, the same choice is the DoDomain-Team header (a team id from GET /api/v1/teams); see the API reference. A secret key (dd_sk_) belongs to exactly one team, so it needs no header, and a header naming any other team is refused with 404 TEAM_NOT_FOUND.

Errors and recovery

Every refusal, over MCP and over REST, uses one envelope: { "code", "message", "next", "docs" }. next names the tool to call to recover, with its arguments; message is one sentence and never contains a link.

CodeMeaningnext
SCOPE_MISSINGThe connection does not hold the permission this tool needs.request_scopes for the missing tier
CONFIRMATION_REQUIREDA destructive tool needs a one-time confirmation.the same tool, with a confirmToken
QUOTA_EXCEEDEDThe plan limit is reached.upgrade_plan
VALIDATION_ERRORAn argument is missing or wrong.the argument to supply, when known
NOT_FOUNDThe thing does not exist or is not yours.
RATE_LIMITEDToo many requests for the plan. Back off and retry.
CONFLICTThe call conflicts with the current state.
TOOL_FAILEDAn unexpected failure. Retry once, then contact support.
UNAUTHORIZED, CONSENT_REVOKEDThe credential is missing, expired or revoked. Connect again.
TEAM_REQUIRED, TEAM_NOT_FOUNDName a usable team with teamId.

Permissions

The consent screen groups what a connection can do into nine permission tiers, all ticked by default: read your data, create and edit, delete, billing and subscription, profile and account deletion, members and invites, connected services, support requests, and API keys. Untick a tier and the connection cannot call its tools; search_tools does not even list them. Read your data stays on, because every other tier needs it. A tool the connection cannot call returns SCOPE_MISSING, and request_scopes gives a one-time link to widen the grant.

Write tools also follow your role. Creating apps, creating sessions and disconnecting or re-verifying connections need the Admin role or higher on the teams the connection covers. If you are a member, the consent screen says so and approves the rest of what you ticked: the connection is read-only, without those tools. Ask a team admin to connect the client when it needs them.

An app's dd_sk_ secret key chooses from five of those tiers when it is created or rotated: read, create and edit, delete, connected services and API keys. Billing, account, team and support tools act on a person, so a secret key never holds them.

Confirmations

Tools that delete, cancel or remove things return CONFIRMATION_REQUIRED the first time, with a confirmToken in next.args. State the action to the user, then call the same tool again with that token. A token works once, for the same arguments, for ten minutes. We keep backups: contact support to restore anything removed by mistake.

Some steps cannot happen in chat: entering a card, finishing a Cloudflare, Domain Connect or Vercel sign-in, downloading an export, converting a guest account or widening a grant. The tool for that step (upgrade_plan, manage_subscription for the billing portal, get_connect_links, request_scopes, export_data, convert_guest_account) returns a https://app.dodomain.io/go/<id> link. Give it to the person as it is. The link expires after 15 minutes, and a link tied to a person works once and only for that person.

Secret keys over MCP

An app's dd_sk_ secret key is accepted as the Bearer token. It acts as its one app, within the tiers chosen when the key was created, and cannot call any tool that acts on a person.

Billing from chat

billing_status shows the plan, state and usage, and list_plans shows what you can buy. upgrade_plan returns a checkout link with the plan and interval you chose, and the payment happens there. manage_subscription opens the payment-method and invoice portal, or cancels or refunds the latest payment, and always asks for a confirmation before cancelling or refunding. A plan bought through the App Store or Google Play is managed in that store, so the tool says so and returns the store's management link instead of cancelling it. Deleting your account cancels a web subscription for you. A store subscription you cancel yourself in the store, and the delete result and the deletion email say so.

Revoking access

Every connected client is listed by list_connected_apps and on the Connected apps page. Revoking one (revoke_connected_app, which asks for a confirmation) takes effect immediately: both its access and refresh tokens stop working on the next request, because every MCP request checks that your consent still exists.

Rate limits and pricing

MCP access is included on every plan: there is no separate SKU. Requests ride the same per-minute plan meters as the REST API (Free 60, Pro 300, Scale 1,200 requests/min per team), and the monthly connection quota is metered identically to REST: creating a session costs nothing, and one unit is charged when a domain is first verified. create_connect_session is refused with quota_exceeded exactly when the REST endpoint would refuse it: on every plan once the team's monthly cap is reached, and on Free also once the Free teams owned by any of this team's owners together reach it, or once its unfinished sessions reach what the month has left plus 10 (see Pricing).

Security

MCP callers authenticate with OAuth 2.1 (PKCE on every flow, access tokens that expire after 30 days by default, a revoked client refused on its next request, and refresh only for clients granted it at consent) or with an app's dd_sk_ secret key, which acts only as that app. Every tool call is recorded with its tool, outcome and a hash of its arguments, never the arguments themselves. Grants are per-user, per-client, scope-limited, and revocable instantly with revoke_connected_app.

On this page

We use analytics cookies to understand how DoDomain is used. The sign-in cookie is essential and is set regardless; the privacy policy names every service involved. Privacy policy