Apexly
Add, check, diagnose and remove your SaaS customers' custom domains from any MCP client.
Should I use this
Quality & Safety
Findings (1)
- LOWin get_connect_url
Based on automated analysis of tool definitions and protocol compliance.
Context Cost
This is the approximate number of tokens consumed each time the server's tools are loaded into a model's context. Higher counts reduce the attention available for other tasks.
Install
One-Click Install
Add this to your `claude_desktop_config.json` file:
{
"mcpServers": {
"mcp": {
"url": "https://mcp.apexly.dev/mcp"
}
}
}Remote endpoints
https://mcp.apexly.dev/mcpstreamable-httpWhat it can do
Tool inventory
Tools (8)
🟡create_domain(hostname, metadata, apex_redirect, origin)
Add a customer's hostname (e.g. careers.acme.com or acme.com) to the app this API key belongs to. Idempotent: adding a hostname the app already has returns the existing domain. The domain starts in pending_dns; the customer must then add the DNS record in status_explained / get_dns_instructions, or open the connect_url to be guided through it. Apexly checks DNS every 15 seconds and issues the TLS certificate itself. With a test key (sk_test_…) the domain is a sandbox one that goes active by itself in about 30 seconds. Never invent a hostname: ask the user which one.
Input Schema
{
"type": "object",
"properties": {
"hostname": {
"type": "string",
"maxLength": 1024,
"description": "The customer's hostname, no scheme or path, e.g. careers.acme.com"
},
"metadata": {
"description": "Any JSON object up to 4 KB, e.g. {\"customer\": \"Acme\", \"tenant_id\": \"42\"}",
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
"apex_redirect": {
"description": "Apex domains only: also serve www.<apex> and redirect it",
"type": "string",
"enum": [
"none",
"www"
]
},
"origin": {
"description": "Per-domain origin override (paid plans); omit to use the app origin",
"type": "string",
"maxLength": 2048
}
},
"required": [
"hostname"
],
"$schema": "http://json-schema.org/draft-07/schema#"
}🟢get_domain(id)
Current state of one domain: status (pending_dns → verifying → issuing → active; or dns_broken, cert_failed, held, expired), the DNS record the customer must add, the connect_url and the certificate. status_explained says in one sentence why it is in that status and what to do next. Use it to poll after create_domain or verify_domain.
Input Schema
{
"type": "object",
"properties": {
"id": {
"type": "string",
"minLength": 1,
"maxLength": 64,
"description": "The domain id (dom_…), from create_domain or list_domains"
}
},
"required": [
"id"
],
"$schema": "http://json-schema.org/draft-07/schema#"
}🟢list_domains(status, hostname, limit, cursor)
The app's domains, newest first, one page at a time. Pass next_cursor back as cursor for the next page (null means there are no more). Filter by status or by hostname prefix to find a domain id.
Input Schema
{
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": [
"pending_dns",
"verifying",
"issuing",
"active",
"dns_broken",
"cert_failed",
"expired",
"held",
"deleted"
]
},
"hostname": {
"description": "Hostname prefix, e.g. careers.",
"type": "string",
"maxLength": 253
},
"limit": {
"default": 20,
"type": "integer",
"minimum": 1,
"maximum": 100
},
"cursor": {
"description": "next_cursor of the previous page",
"type": "string",
"maxLength": 200
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}🟢verify_domain(id)
Queue a DNS check right away instead of waiting for the next scheduled one; use it after the customer says they added the record. On cert_failed it retries the certificate. At most one per 15 seconds per domain. The check runs in the background: call get_domain a few seconds later for the result.
Input Schema
{
"type": "object",
"properties": {
"id": {
"type": "string",
"minLength": 1,
"maxLength": 64,
"description": "The domain id (dom_…), from create_domain or list_domains"
}
},
"required": [
"id"
],
"$schema": "http://json-schema.org/draft-07/schema#"
}🟢get_connect_url(id)
The link to send the customer (the domain owner): a page branded with the app that detects their DNS provider, shows the exact record with copy buttons and tells them when the domain is live. Prefer it when the customer is not technical. It is safe to share with the customer, not publicly.
Input Schema
{
"type": "object",
"properties": {
"id": {
"type": "string",
"minLength": 1,
"maxLength": 64,
"description": "The domain id (dom_…), from create_domain or list_domains"
}
},
"required": [
"id"
],
"$schema": "http://json-schema.org/draft-07/schema#"
}🟢get_dns_instructions(id)
The exact DNS record(s) the customer must add for this domain, plus step-by-step instructions for their DNS provider (detected from the domain's nameservers: GoDaddy, Cloudflare, Namecheap, Route 53 and ~40 more; generic steps otherwise). Record names are relative to the registrable domain ("careers" in acme.com, "@" for the apex).
Input Schema
{
"type": "object",
"properties": {
"id": {
"type": "string",
"minLength": 1,
"maxLength": 64,
"description": "The domain id (dom_…), from create_domain or list_domains"
}
},
"required": [
"id"
],
"$schema": "http://json-schema.org/draft-07/schema#"
}🟢diagnose_domain(id)
Why a domain is not live and what to change (the domain doctor, same as GET /v1/domains/{id}/diagnose): runs every check live (the record at 1.1.1.1, 8.8.8.8 and the domain's own nameservers, other A and stale AAAA records, the Cloudflare proxy, CAA, the certificate, the origin, the www pair). Each check is pass, fail, warn or skip with what we saw (detail) and what to change (fix); blocking_check_id is the one to fix first. status_explained says why the domain is in its status. Use it when a domain stays in pending_dns, dns_broken or cert_failed, then relay the fix to the customer. Results are reused for 20 seconds.
Input Schema
{
"type": "object",
"properties": {
"id": {
"type": "string",
"minLength": 1,
"maxLength": 64,
"description": "The domain id (dom_…), from create_domain or list_domains"
}
},
"required": [
"id"
],
"$schema": "http://json-schema.org/draft-07/schema#"
}🔴delete_domain(id, confirm)
Remove a domain: it stops being served within 5 seconds and its certificate is dropped. Irreversible (adding the hostname again starts over with a new record). Only call it after the user explicitly confirmed deleting this hostname, and pass confirm: true.
Input Schema
{
"type": "object",
"properties": {
"id": {
"type": "string",
"minLength": 1,
"maxLength": 64,
"description": "The domain id (dom_…), from create_domain or list_domains"
},
"confirm": {
"description": "Must be true: the user confirmed deleting this domain",
"type": "boolean"
}
},
"required": [
"id"
],
"$schema": "http://json-schema.org/draft-07/schema#"
}Community
Evidence