关于 CustomDomain™
CustomDomain™ 是托管式 MCP 服务,让 Agent 查找、连接、诊断和管理域名,面向构建 Agent 的团队及需要客户自有域名的 SaaS 平台。它通过受限工具处理 DNS 配置、邮件记录和 HTTPS 状态,而不接受任意 DNS 记录参数。
主要功能
- 01搜索域名并查看价格
- 02连接域名并检测 DNS 服务商
- 03诊断记录问题并检查连接状态
- 04配置邮件记录和域名转发
- 05管理证书、域名清单及名称服务器
适用场景
- 01为新上线的应用连接客户域名
- 02为 SaaS 企业客户处理域名接入
- 03配置邮件域名的 MX、SPF、DKIM 和 DMARC
- 04排查或修复未生效的域名连接
MCP 相关
托管式 MCP 服务通过 Streamable HTTP 提供 20 个域名管理工具,支持 OAuth 和按范围授权。工具返回所需 DNS 记录并处理连接检查等操作,不允许 Agent 直接提交任意记录值。
配置
远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。
https://mcp.customdomain.ai/mcpclaude mcp add --transport http ai-customdomain https://mcp.customdomain.ai/mcp{"mcpServers":{"ai-customdomain":{"type":"http","url":"https://mcp.customdomain.ai/mcp"}}}在 Cursor 中打开{"servers":{"ai-customdomain":{"type":"http","url":"https://mcp.customdomain.ai/mcp"}}}在 VS Code 中打开{"mcpServers":{"ai-customdomain":{"type":"http","url":"https://mcp.customdomain.ai/mcp"}}}{"mcpServers":{"ai-customdomain":{"serverUrl":"https://mcp.customdomain.ai/mcp"}}}命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。
工具
详细介绍
CustomDomain™ MCP 服务:为 AI Agent 提供自定义域名
这是官方 CustomDomain™ 产品 MCP 服务。它唯一的端点是 https://mcp.customdomain.ai/mcp,
在官方 MCP 注册表中的名称为 ai.customdomain/mcp,OAuth 作用域为 domains:read、
domains:connect、domains:disconnect 和 domains:purchase。没有其他主机提供此服务,因此,任何其他
地址上自称为 CustomDomain™ 的服务都不是此服务。
用于自定义域名的 MCP 服务:让 Claude 和其他 AI Agent 查找、连接、诊断和管理域名。
状态: 生产环境 · 服务端 0.6.0 · 发布版本 v0.6.0
网站 · 文档 · 控制台 · 产品页面 · MCP 文档 · 工具参考 · 服务商覆盖范围 · 定价
安装:
· Claude Code、Claude Desktop 和 Cursor:快速入门 · GitHub Copilot 云 Agent:配置
星标可以帮助 GitHub 上的其他开发者发现此服务。如果它对你有用,请为此代码库点亮星标。
| 它是什么 | 一个托管式 MCP 服务,为 AI Agent 提供 20 种域名工具 |
| 适用对象 | 需要客户使用自有域名的 Agent 构建者、SaaS 平台和编码 Agent 用户 |
| 在线地址 | customdomain.ai/mcp-server · 端点 https://mcp.customdomain.ai/mcp |
| 技术栈 | Go 1.26 · 基于 streamable HTTP 的 JSON-RPC 2.0 · 托管式,服务中不设数据存储 |
| 状态 | 生产环境 · 已在官方 MCP 注册表发布 0.6.0 版本 · 20 种工具 · 收录 178 家 DNS 服务商,其中 62 家支持自动配置 |
CustomDomain™ MCP 是一个托管式 Model Context Protocol 服务,让 AI Agent 帮助用户使用自己的域名:连接已有域名、设置电子邮件记录、 监控域名何时启用 HTTPS,以及查明尚未启用的原因。它取代了人们通常在 DNS 控制面板中手动完成的那部分工作。无需安装,也无需持续运行任何程序:将 MCP 客户端指向上面的端点即可。
flowchart LR
A["Agent<br/>Claude · Cursor · ChatGPT"] -->|"JSON-RPC over HTTPS"| M["mcp.customdomain.ai<br/>20 tools"]
M -->|"credential forwarded"| C["Control plane<br/>api.customdomain.ai"]
C --> R["Registrars<br/>search · price"]
C --> D["DNS providers<br/>178 catalogued · 62 automatic"]
C --> E["Edge<br/>TLS issued"]
问题
每款 SaaS 产品最终都需要让客户使用自己的域名:白标应用的主机、个性化链接,或用于发送邮件的域名。这项工作不复杂,而且总是一样:查明客户使用哪家 DNS 服务商,按正确格式写入正确的记录,等待记录生效,然后获取证书。手动完成,这就是一张支持工单;用代码完成,这就是一个你并不想维护的 DNS 服务商集成,而且要做 60 次。
Agent 在带来好处之前,反而会让问题变得更糟。让 Agent 来做这项工作的显而易见的方法,是给它 DNS 凭据和写入记录的能力。这意味着,只要一次误解指令,或一张被投毒的网页,就可能修改客户的区域配置。没人愿意把生产域名上的 SetRecords 调用交给大模型,而另一种做法(让 Agent 把说明念出来,再请用户到别处手动输入)又会变回支持工单,只是多了几步。这不是靠提示词就能解决的权限问题,而是参数列表的问题;解决方法是改变 Agent 能够发出的指令。
适用对象
- 打造可交付产品的团队。 编码 Agent、网站构建器、部署机器人:任何能产出可运行应用,并且需要一个用户真正会输入的地址的工具。Agent 会连接域名并轮询其状态,直到变为
live,而不是在最后一步停下来,只给出一段 DNS 操作说明。 - 拥有租户域名的 SaaS 平台。 如果客户会将自己的域名连接到你的产品,这就是 CustomDomain™ 小组件和 REST API 背后的同一套引擎,Agent 可以通过自己已经使用的协议来访问。
- 电子邮件和消息平台。 在客户的服务商处,以正确格式验证发件域名(MX、SPF、DKIM、DMARC),在这里一次调用即可完成,无需翻阅文档或排队等待支持。
- 需要维护域名组合的任何人。 域名连接可能失效,证书需要仍能解析的记录。能够列出、诊断、重新检查并重新应用设置的 Agent,比每季度都由人工处理更省钱。
功能
二十种工具,只需一个凭据,参数中无需包含 DNS 记录。以下每项都是独立的工具调用,而不是你必须自行组装的工作流:
- 检查域名是否可以注册,并获取实时购买和续费价格:
search-domain-availability - 根据一组关键词,以确定性方式推荐确实可用的名称:
generate-domain-suggestions - 通过已解析的注册商注册域名,并受默认拒绝授权关卡保护。目前托管服务上已禁用:
create-domain-order - 连接客户已拥有的域名,并获取必须存在的准确记录:
connect-domain - 在向任何人索取信息之前检测 DNS 提供商,提供各接入线路的判定结果,并进行冲突和 CAA 预检:
discover-provider - 轮询连接直至完成,从写入记录到签发证书:
check-connection-status - 逐条说明域名为何尚未上线:
diagnose-connection - 在用户修复问题后立即重新运行 DNS 检查:
recheck-connection - 读取 HTTPS 证书(到期时间、续订失败情况):
check-certificate-status - 跨两个不同的账本轮询注册订单,无需猜测适用哪一个:
check-order-status - 列出通过该账户完成的购买:
list-domain-orders - 通过一次调用设置电子邮件(根据服务器端模板配置 MX、SPF、DKIM 和 DMARC):
add-email - 将域名永久指向其他位置,并使用 301 重定向:
forward-domain - 修复已偏离
live状态的域名,使用已存储的授权:reapply-connection - 下线域名,操作前让用户确认具体域名:
disconnect-domain - 分页列出整个账户的资源清单,以便 Agent 协调整个域名组合,而不只是它发起的任务:
list-connections - 在批量操作前,或收到
billing_required拒绝后,检查工作区是否可以连接新域名:check-billing-status - 将域名的名称服务器迁移到应用的 DNS 主机,先复制记录(包括邮件记录),以便此后始终正确维护这些记录:
migrate-nameservers - 跟踪迁移直至完成,并转达需要用户执行的步骤:
check-nameserver-status - 将名称服务器迁回旧服务器,或迁至注册商自有的 DNS:
rollback-nameservers
完整的参数、权限范围和响应结构请参阅:TOOLS.md。
所有凭据均可从外部验证:该服务已在官方 MCP 注册表中以 ai.customdomain/mcp 发布,版本为 0.6.0,支持协议修订版 2025-06-18,无需身份验证即可在 /.well-known/agent/mcp.json 查看其版本和工具;对于未经身份验证的调用,服务会返回 RFC 9728 挑战,其中会指明自身的元数据文档,而不是仅返回裸 401。自动设置涵盖目录中列出的 178 家提供商中的 62 家(其中 55 家使用受限范围 API 令牌,6 家使用提供商 OAuth,1 家使用 Domain Connect);其余 116 家仍可使用,并会返回记录和供人工操作的链接。实时分布见 /v1/providers/census。
所有这些工具都遵循同一条经验构建:只返回控制台链接就停止工作的 Agent,并没有完成任务。工具会直接返回权威记录集,因此 Agent 可以明确告知用户需要添加哪些记录;完成信号是布尔值,而不是集成可能误读的状态字符串。
使用场景
- 交付副项目的编码 Agent。“把我的域名指向这个应用。”先调用
discover-provider,再调用connect-domain,然后反复调用check-connection-status,直到connected为true。唯一需要人工操作的步骤是 在 DNS 服务商处授权,或添加返回的记录。 - **为企业客户提供服务的 SaaS。**Agent 首先调用
discover-provider,发现客户使用的服务商无法为根域名设置别名,于是在任何人授权之前发出警告。 - 电子邮件平台。
add-email根据模板写入 MX、SPF、DKIM 和 DMARC 记录;Agent 只需提供每个域名的 DKIM 选择器,无需提供其他内容。 - **拥有上千个租户域名的平台。**调用
list-connections并设置status=failed(持续使用nextCursor,直到获取完整列表),保留managed: true的行,对这些行调用reapply-connection,对其余行调用diagnose-connection并交由人工处理。这是 Agent 可以按计划运行的协调循环,也是库存工具存在的原因。 - 回答“为什么我的域名还不能用”的支持 Agent。
diagnose-connection会说明哪条记录缺失或有误,以及原因(例如在 Name 字段中输入了主机名,或前面有代理),而recheck-connection无需等待下一次计划检查即可确认问题已修复。 - **确保用户域名持续正常运行的平台。**应用负责维护域名时,Agent 会询问用户,调用
migrate-nameservers并设置confirm: true,然后轮询check-nameserver-status,直到状态为done;每当用户需要在注册商处操作时,Agent 都会转达nextStep。rollback-nameservers可撤销迁移。
通过 MCP 购买域名的功能已经开发完成,但托管服务暂不可用:购买需要授权,而此处未配置购买授权回调,因此 create-domain-order 会返回 rejected。请先在控制台购买,再在此处连接域名。
为什么使用 MCP 服务而不是 REST API
REST API 确实存在,也是此服务调用的对象。区别在于 Agent 可以发出什么请求。REST API 接受 DNS 记录,而 MCP 工具不接受。每条记录的值都由控制平面根据经过审核的模板计算,因此,遭到提示词注入的 Agent 在这里最糟糕的操作也只是连接错误的域名,而不是向客户的区域写入任意 MX 记录。安全模型由参数列表构成。此外,委托的 Agent 令牌只包含用户批准的作用域;移除域名需要单独的作用域,并且必须在 confirm 中再次指定域名。付费注册有单独的门控:create-domain-order 要求在 confirm_domain 中再次填写域名,并且只有在集成方的购买授权回调批准后才会下单;未配置的回调会拒绝所有购买请求。迁移名称服务器需要设置 confirm: true,而 Agent 令牌无法选择名称服务器的目标位置:由应用的设置决定。
第二个原因是发现能力。即使 Agent 从未听说过这款产品,也能找到它:该服务已列入官方 MCP 注册表,会在 well-known 路径发布 Agent 清单和 OAuth 受保护资源文档;未通过身份验证的调用会返回一个指向受保护资源文档的质询,而不是简单的 401。支持 OAuth 的客户端会根据该文档找到授权服务器,为用户登录,并获取作用域受限的令牌,无需复制任何密钥。REST API 无法以这种方式介绍自己。
快速入门
大多数客户端通过 OAuth 登录,因此无需复制密钥:浏览器会打开,由用户批准 Agent 可以执行的操作,然后 Agent 会获得一个限定范围的令牌。无法登录的客户端会使用从 app.customdomain.ai 控制台的 API & SDK 页面获取的 API 密钥。密钥格式为 cd_live_... 或 cd_test_...(旧版 sk_live_ / sk_test_ 密钥仍可使用)。请将密钥存放在环境变量中,切勿放在会提交的文件里。
Claude Code,使用 OAuth 登录:
claude mcp add --transport http customdomain https://mcp.customdomain.ai/mcp
# then run /mcp inside Claude Code and sign in
或使用环境中的 API 密钥:
claude mcp add --transport http customdomain https://mcp.customdomain.ai/mcp \
--header "Authorization: Bearer $CUSTOMDOMAIN_API_KEY"
Claude Desktop:进入 Settings → Connectors → Add custom connector。输入 URL
https://mcp.customdomain.ai/mcp,添加后选择 Connect 并登录(OAuth)。
Cursor 目前还不能独立登录新的服务,因此需要使用密钥。请将以下内容放入用户级的
~/.cursor/mcp.json,不要放在会提交的项目 .cursor/mcp.json 中,并在启动 Cursor 时使用的环境中设置
CUSTOMDOMAIN_API_KEY:
{
"mcpServers": {
"customdomain": {
"url": "https://mcp.customdomain.ai/mcp",
"headers": { "Authorization": "Bearer ${env:CUSTOMDOMAIN_API_KEY}" }
}
}
}
任何 HTTP 客户端:此端点使用标准 JSON-RPC 2.0,因此你可以通过 curl 调用工具:
curl -X POST https://mcp.customdomain.ai/mcp \
-H "Authorization: Bearer $CUSTOMDOMAIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"discover-provider","arguments":{"domain":"example.com"}}}'
控制台的 MCP server 页面提供这些客户端以及 Codex、VS Code、ChatGPT 等客户端的复制粘贴式配置,还提供连接测试。
VS Code
顶部的安装徽章会添加此条目。你也可以自行将其放入 .vscode/mcp.json,或运行
MCP: Add Server:
{
"servers": {
"customdomain": { "type": "http", "url": "https://mcp.customdomain.ai/mcp" }
}
}
该条目不包含密钥。服务会在收到第一个请求时返回 401,其 WWW-Authenticate 标头会注明
受保护资源元数据,该文档会将 https://api.customdomain.ai 指定为授权服务器(使用 PKCE 的授权码流程,并支持动态客户端注册)。按照 VS Code 文档所述,遵循此质询的客户端会打开浏览器,让用户登录并批准所需权限范围。若要改用 API 密钥,请添加一个由 VS Code 提示你输入一次并以机密形式存储的标头:
{
"servers": {
"customdomain": {
"type": "http",
"url": "https://mcp.customdomain.ai/mcp",
"headers": { "Authorization": "Bearer ${input:customdomain-key}" }
}
},
"inputs": [
{ "type": "promptString", "id": "customdomain-key", "description": "CustomDomain™ API key", "password": true }
]
}
GitHub Copilot 云 Agent
Copilot 云 Agent(负责处理议题和拉取请求的编码 Agent)不支持通过 OAuth 登录的远程 MCP 服务,因此会将凭据作为标头发送。在代码库中,打开 Settings → Copilot → MCP servers,粘贴此配置并保存:
{
"mcpServers": {
"customdomain": {
"type": "http",
"url": "https://mcp.customdomain.ai/mcp",
"headers": { "Authorization": "$COPILOT_MCP_CUSTOMDOMAIN_AUTH" },
"tools": ["*"]
}
}
}
然后添加一个名为 COPILOT_MCP_CUSTOMDOMAIN_AUTH 的 Agents 机密(Copilot 只会传递名称以
COPILOT_MCP_ 开头的机密)。其值是完整的标头值,即 Bearer 后接以下任一内容:
- 从控制台的 API & SDK 页面获取的 API 密钥(
cd_live_...),该密钥对整个工作区生效;或 - 通过
POST /v1/applications创建的应用程序的APPLICATION_ID:CLIENT_SECRET。该接口仅返回一次密钥。服务会在每个请求中将这对凭据兑换为有效期为 15 分钟的令牌,与POST https://mcp.customdomain.ai/token使用client_credentials授权类型进行的兑换相同;Agent 仅代表该应用程序执行操作。通过控制台创建的应用程序不会显示其密钥,因此请为这些应用程序使用 API 密钥。
"tools": ["*"] 允许 Agent 无需询问即可调用所有工具,包括会使域名离线的
disconnect-domain。若要限制 Agent 只执行读取和诊断操作,请改为列出具体工具,例如
["discover-provider", "check-connection-status", "diagnose-connection", "list-connections", "check-certificate-status"]。
客户端支持
| 客户端 | 连接方式 | 备注 |
|---|---|---|
| Claude Code | 原生可流式传输 HTTP | claude mcp add --transport http;使用 /mcp 登录,或传入密钥标头 |
| Claude Desktop | 自定义连接器 | 设置 → 连接器 → 添加自定义连接器;使用 OAuth 登录 |
| Cursor | 原生 HTTP(带标头) | 在 ~/.cursor/mcp.json 中使用来自环境变量的密钥;暂不支持登录 |
| ChatGPT | 开发者模式应用 | 使用 OAuth 登录;无法发送 API 密钥 |
| 其他客户端 | POST /mcp,JSON-RPC 2.0 | 按照 401 提示登录,或在 Authorization 标头中发送 Bearer 令牌 |
工具与三条约定
所有工具都遵循三条规则,而集成方常常会在这些地方出错。
没有工具接受 DNS 记录。 add-email 接受邮件设置(MX 主机、DKIM 选择器),然后由模板将其转换为记录。forward-domain 接受重定向目标。两者都不接受记录。
connected: true 是完成信号。 状态字符串仅供参考;用于分支判断的是布尔值,而且即使状态枚举日后扩展,它也会保持稳定。
无法撤销的调用必须得到用户同意。 disconnect-domain 接受 connectionId 和 confirm,其中 confirm 是用户确认过的域名;create-domain-order 会在 confirm_domain 中重复该域名;migrate-nameservers 和 rollback-nameservers 接受 confirm: true。若调用未提供确认信息,系统会在执行任何操作前拒绝该调用。
此外,没有所有权验证步骤:没有工具会要求或检查 TXT 验证记录。域名控制权通过写入记录的通道来证明(提供商处的 OAuth 授权、一键应用,或范围受限的 API 令牌);在手动操作流程中,控制平面只会等待记录出现在公共 DNS 中。
身份验证
POST /mcp 接受四种 Bearer 凭据。
| 凭据 | 颁发方 | 代表对象 |
|---|---|---|
API 密钥 cd_live_ / cd_test_(旧版 sk_live_ / sk_test_) | 控制台中的 API & SDK。每个工作区都有一个默认密钥;创建的密钥只会显示一次。 | 整个工作区 |
来自 POST /token 的 JWT | 使用 application_id + client_secret 进行 client_credentials 交换。有效期为 15 分钟。 | 一个应用程序 |
CLIENT_ID:CLIENT_SECRET | 供无法运行令牌交换的主机使用的快捷方式;服务会在每次请求时进行交换 | 一个应用程序 |
| 委派 Agent 令牌 | 在 https://api.customdomain.ai 上通过 OAuth 获取:动态客户端注册、使用 PKCE(S256)的授权码,以及由用户批准的作用域 | 一个应用程序,仅限已批准的作用域 |
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": 900 }
APPLICATION_ID 和 CLIENT_ID 是同一个值的两种名称。
集成方凭据(API 密钥、/token JWT、CLIENT_ID:CLIENT_SECRET 形式)不由服务本身验证:服务会将其转发给控制平面,由控制平面在每次调用时执行与 REST API 相同的权限检查。它们不携带作用域。在控制台中撤销密钥后,Agent 会在下一次调用时失去访问权限;目前,该调用会返回工具失败并显示 error: "unauthorized",而不是 HTTP 401。
委派 Agent 令牌是为受众 https://mcp.customdomain.ai/mcp 颁发的 ES256 令牌。服务会根据控制平面的 JWKS 在本地验证令牌,拒绝受众不匹配的令牌并返回 401 invalid_token,且会在每次调用时检查工具的作用域:
| 作用域 | 工具 |
|---|---|
domains:read | search-domain-availability、generate-domain-suggestions、check-connection-status、check-order-status、discover-provider、list-connections、check-certificate-status、diagnose-connection、check-billing-status、list-domain-orders、check-nameserver-status |
domains:connect | connect-domain、reapply-connection、forward-domain、add-email、recheck-connection、migrate-nameservers、rollback-nameservers |
domains:disconnect | disconnect-domain |
domains:purchase | create-domain-order |
令牌缺少工具所需作用域时,会返回 JSON-RPC 错误 -32003、insufficient_scope,其中会指出所需的作用域。请参阅 Agent 访问和身份验证。
对于 Agent 会接触的任何内容,优先使用 Agent 令牌或应用程序范围的 JWT:泄露的 cd_live_ 密钥会赋予整个工作区的权限。
速率限制
每个调用方的工具调用速率限制为每秒 5 次,突发最多 20 次。对于委派 Agent 令牌,调用方是工作区(同一工作区的所有 Agent 共用一个配额桶);对于 API 密钥或 /token JWT,调用方是凭据本身(拥有三个密钥的工作区有三个配额桶);对于 CLIENT_ID:CLIENT_SECRET 形式,调用方是应用程序。超过限制时,该调用会返回工具失败并附带 error: "rate_limited" 和 retryAfterSeconds,且不会到达控制平面。控制平面还会限制每个客户端地址。
生命周期、轮询与错误
连接状态依次为 pending → propagating → live。failed 表示诊断结果,并非终结状态。
| 状态 | 含义 |
|---|---|
pending | 已创建。记录尚未写入,或尚未在公共 DNS 中观察到。手动连接不会自行失败:72 小时后仍会保持 pending,并带有 errorCode: "setup_incomplete",每六小时重新检查一次。 |
propagating | 某个接入渠道已写入记录。轮询器正在根据记录值对照公共 DNS 进行检查。 |
live | 每条预期记录都解析为其目标值,且边缘节点已为该主机提供 TLS 服务。 |
failed | 接入渠道写入的记录在 24 小时内始终未解析(errorCode: "propagation_timeout"),或接入渠道拒绝了写入。如果连接之后重新验证成功,此状态会清除。 |
后台轮询器大约每分钟重新检查一次,因此将轮询间隔设为短于 30 到 60 秒毫无益处。failed 状态可以恢复,不应因此告诉用户从头开始:diagnose-connection 会说明问题所在,修复后,recheck-connection 会重新运行检查。完整生命周期请参阅连接。
错误有两种形式。格式错误的调用会在 JSON-RPC 层失败:参数无效或缺失时返回 -32602,工具未知时返回 -32601,JSON 无法解析时返回 -32700,缺少作用域时返回 -32003。这些都是调用方的问题。控制平面拒绝的调用会作为标记了 isError: true 的工具结果返回,无论调用的是哪个工具,格式都相同:
{ "success": false, "error": "billing_required", "message": "A card is needed to connect more domains.", "details": "..." }
如果控制平面提供了 error,它就是控制平面的错误代码;否则它是工具的备用代码(connect_failed、status_failed、list_failed 等)。根据 error 进行分支处理;显示 message。完整列表请参阅 TOOLS.md。
工作原理
本仓库是托管服务的公开入口:其中包含列出该服务的注册表清单、工具契约以及本页面。服务本身是一个小型 Go 进程。它负责终止 JSON-RPC、验证委托的 Agent 令牌及其作用域、限制每个调用方的速率,并将每次工具调用转发到 CustomDomain™ 控制平面。控制平面负责提供商检测、记录模板、注册商接入渠道、传播轮询器和证书签发。这种拆分让工具接口能够保持精简:所有状态和判断都在一跳之外。
仓库布局
.
├── README.md # this file: what the server is, how to point a client at it, how it is built
├── TOOLS.md # the tool contract: every argument, scope, response field, status value and error code
├── CHANGELOG.md # one entry per server version, matching the tags and GitHub releases
├── server.json # MCP registry manifest: name ai.customdomain/mcp, version 0.6.0, remote endpoint, tools and scopes
├── glama.json # Glama directory ownership claim
└── LICENSE # MIT
服务模块
服务端源代码位于私有的 CustomDomain™ 单体仓库中,路径为 services/mcp,与其调用的控制平面并列列出。这里列出模块名称,是为了清楚说明边界;由于仓库不公开,因此不提供链接。
| 模块 | 用途 | 调用对象 |
|---|---|---|
server.go | 路由 initialize、tools/list、tools/call;按固定顺序注册 20 个工具;工具运行前检查作用域和速率限制 | tools.go、usage.go |
tools.go | 工具定义、JSON 架构、注解、处理程序和统一的失败格式 | client.go |
nameservers.go | 三个名称服务器工具的处理程序:confirm: true,且 Agent 令牌不提供 target 或 nameservers | client.go |
scopes.go | 工具与作用域的映射,以及确保每个工具恰好声明一个作用域的构建检查 | server.go |
ratelimit.go | 每个调用方的令牌桶(默认每秒 5 个,突发上限为 20 个) | server.go |
jsonrpc.go | JSON-RPC 2.0 帧格式和错误代码 | transport.go |
transport.go | stdio 和可流式传输的 HTTP 传输 | server.go |
client.go | ControlPlane 端口:每个工具处理程序都会调用的接口 | 由 httpclient.go 实现 |
httpclient.go | 接入控制平面 REST API 的 HTTP 适配器 | api.customdomain.ai |
clientinfo.go | 传递调用方地址,以便控制平面的按地址限额能识别每位用户 | 控制平面 |
origin.go | 对 /mcp 执行 Origin 检查(浏览器来源必须是服务端自身的来源,或由运营方列出的来源,否则返回 403),并处理 CORS 预检请求 | 无 |
auth.go | Bearer 令牌提取、POST /token 和 RFC 9728 WWW-Authenticate 挑战 | 控制平面 |
agenttoken.go | 在本地验证委派 Agent 令牌的 ES256 签名、有效期和受众 | 控制平面 JWKS |
purchaseauth.go | 默认拒绝的购买授权回调,在任何付费订单前进行检查 | 集成方回调 |
registrar.go | 注册商解析和首选注册商排序 | 控制平面 |
untrusted.go | 限制第三方文本(DNS 值、提供商错误)的长度,避免其未经处理就传给 Agent | 无 |
wellknown.go | 提供受保护资源和授权服务器元数据,以及 /.well-known/agent/mcp.json | 无 |
usage.go | 批量使用量记录器,满载时丢弃;绝不阻塞工具调用 | 控制平面采集端 |
cmd/mcp/main.go | 进程入口:标志、环境、Sentry、OpenTelemetry | 以上全部 |
入口:services/mcp/cmd/mcp/main.go。
关键流程
连接用户已有的域名,是其他所有流程围绕其构建的核心流程。
sequenceDiagram
participant A as Agent
participant M as mcp.customdomain.ai
participant C as Control plane
participant D as Customer's DNS
participant E as Edge
A->>M: tools/call connect-domain {domain}
M->>C: POST /v1/connections (credential forwarded)
C->>C: detect provider, choose rail, compute records
C-->>M: connectionId, records[], link, managed
M-->>A: same payload as structuredContent
Note over A,D: automatic rail: user authorizes once<br/>manual rail: user adds the returned records
C->>D: poll public DNS by value (~60s)
C->>E: request certificate once records resolve
A->>M: tools/call check-connection-status {connectionId}
M-->>A: status live, connected true
不变量
- 没有工具接受 DNS 记录作为输入。 记录值由服务端根据经过审核的模板计算得出。 这是安全模型,并非功能缺失。
- 服务端不使用数据库。 其
go.mod只引入 Sentry 和 OpenTelemetry,没有其他依赖;工具返回的所有信息都在该请求期间从控制平面获取。速率限制器的令牌桶存储在内存中。 - 每个工具恰好声明一个作用域。 若有工具未声明,服务端将拒绝启动。
- 没有所有权挑战步骤。 没有工具会要求或检查 TXT 验证记录。
- 此仓库中的任何内容都不会部署。 没有构建、没有 CI,也没有服务端源代码:这里的文件供 MCP 注册表和人阅读,服务端点在其他地方发布。
POST /v1/connections按应用和域名幂等,因此重复调用connect-domain会恢复现有连接,并返回already_connected: true,而不是创建第二个连接。
配置
作为客户端需要设置的内容。 此仓库中没有需要设置的环境变量。
| 设置项 | 必填 | 默认值 | 用途 |
|---|---|---|---|
| Endpoint URL | 是 | 无 | https://mcp.customdomain.ai/mcp |
Authorization header | 除非客户端登录 | 无 | Bearer cd_live_...、来自 /token 的 JWT,或 CLIENT_ID:CLIENT_SECRET。登录的客户端会获取 Agent 令牌并自行发送。 |
| Token URL | 仅用于 /token JWT | 无 | https://mcp.customdomain.ai/token |
如果客户端支持,请勿将密钥写入配置文件。如果密钥存储在密钥管理器中,请在启动时注入;切勿将明文密钥粘贴到仓库、提交的 .cursor/mcp.json 或问题帖中。
托管服务的配置方式。 列出这些设置,是因为其中一些会改变工具的行为,而且集成方会询问购买被拒绝的原因。密钥值会在部署时注入,不会出现在任何仓库中。
| 变量 | 必填 | 默认值 | 用途 |
|---|---|---|---|
MCP_ADDR | 否 | :8080 | HTTP 监听地址 |
MCP_API_BASE | 否 | https://api.customdomain.ai | 控制平面基础 URL |
MCP_PUBLIC_BASE | 否 | https://mcp.customdomain.ai | 写入发现文档的公共来源,以及 Agent 令牌受众的基础 URL |
MCP_AUTH_SERVER | 否 | https://api.customdomain.ai | 签发 Agent 令牌的控制平面公共来源;在受保护资源元数据中列为首项 |
MCP_AGENT_JWKS_URL | 否 | 未设置 | 委托 Agent 令牌的 JWKS。未设置时,Agent 令牌路径将保持关闭。 托管服务会设置此项。 |
MCP_ALLOWED_ORIGINS | 否 | 未设置 | 除服务自身来源外,允许调用 /mcp 的浏览器来源(格式为 scheme://host[:port],以逗号分隔)。任何其他 Origin 都会收到 403;不含 Origin 的请求(所有非浏览器客户端)不受影响。不支持通配符。托管服务中未设置此项。 |
MCP_TENANT_RPS | 否 | 5 | 每位调用方每秒可调用工具的次数。0 表示关闭限制。 |
MCP_TENANT_BURST | 否 | 20 | 每位调用方单次突发可调用工具的次数 |
MCP_LINK_BASE | 否 | 控制台 URL | 返回给 Agent 的引导式 DNS 回退链接前缀 |
MCP_PURCHASE_AUTHZ_URL | 购买时必填 | 未设置 | 授权回调。未设置时会拒绝所有付费订单,这正是托管服务目前的运行方式。 |
MCP_PURCHASE_AUTHZ_USER | 设置了 URL 时必填 | 未设置 | 该回调的基本身份验证用户名 |
MCP_PURCHASE_AUTHZ_PASSWORD | 设置了 URL 时必填 | 未设置 | 该回调的基本身份验证密码(注入,不会存储) |
MCP_PREFERRED_REGISTRAR | 否 | 未设置 | 订单解析期间优先尝试的注册商 |
JUSTEASY_MCP_USAGE_KEY | 否 | 未设置 | 启用用量记录;未设置时,记录器不执行任何操作。系统会先读取 CUSTOMDOMAIN_MCP_USAGE_KEY,并在未设置时使用 MCP_USAGE_INGEST_KEY 作为备用值。 |
MCP_USAGE_INGEST_URL | 否 | 根据 MCP_API_BASE 推导 | 用量批次的提交目标 |
CUSTOMDOMAIN_API_TOKEN | 仅限 stdio | 未设置 | 本地 stdio 传输使用的静态控制平面 bearer;JUSTEASY_API_TOKEN 是旧名称 |
MCP_INSECURE | 否 | 未设置 | 不进行 bearer 检查即可提供 /mcp 服务,仅供一位开发者在自己的机器上使用:除非监听地址为环回地址,否则服务拒绝启动;在生产主机上也会拒绝启动。 |
SENTRY_ENVIRONMENT | 否 | 未设置 | 环境标签;生产环境防护也会读取此项 |
OTEL_EXPORTER_OTLP_ENDPOINT | 否 | 未设置 | 启用追踪(选择性);未设置时不执行任何操作 |
开发与测试
这里无需构建。仓库中只有两个 JSON 清单和三份 Markdown 文档,因此检查也相应简单:
git clone https://github.com/CUSTOM-DOMAIN-APP/customdomain-mcp.git
cd customdomain-mcp
jq -e . server.json glama.json > /dev/null && echo "manifests parse"
server.json 必须符合它声明的 MCP 注册表架构
(https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json;请注意,description 的长度上限为 100 个字符),其 version 也必须与发布到注册表的版本一致。TOOLS.md 是约定文档:如果上游更改了工具参数或响应字段,只有将更改反映到该文档中,工作才算完成。
服务本身使用 Go 1.26,包含196 项测试,分布在 26 个测试文件中(于 2026-10-21 在 0.6.0 提交中统计),覆盖协议、传输、控制平面适配器、购买门控及其确认、范围强制执行、Agent 令牌验证、速率限制器、Origin 检查、名称服务器工具,以及发现文档的一致性。在有内容到达端点之前,会先在单体仓库中运行 go build ./... && go test ./...,并执行 -race 检查。
实时检查无需任何准备,因为 Agent 清单是公开的:
curl -s https://mcp.customdomain.ai/.well-known/agent/mcp.json | jq '{version, tools: (.tools | length)}'
# -> { "version": "0.6.0", "tools": 20 }
版本管理与发布
服务的版本号只有一个:serverInfo、/.well-known/agent/mcp.json、注册表条目以及此处的 server.json 中的 version。每个版本都有一个 vX.Y.Z 标签、一项 GitHub 发布和一条 CHANGELOG.md 记录。当前版本为 0.6.0。
有两类内容按不同的节奏发布,混淆它们就会导致版本字符串过期。
此仓库向目录发布。官方 MCP 注册表会读取 server.json,用于 ai.customdomain/mcp;glama.json 则是向 Glama 目录声明所有权的文件。发布更改意味着更新 server.json 中的 version、将清单重新发布到注册表(已发布的注册表版本不可变)、添加 CHANGELOG 记录并打上标签。如需回滚:还原提交并重新发布之前的版本。这里的任何内容都不在请求路径上,因此此处的错误提交不会导致端点宕机。
注册表通过 customdomain.ai 上的 DNS TXT 记录(v=MCPv1; k=ed25519; p=...)识别命名空间 ai.customdomain,因此发布时需要使用与该记录匹配的 Ed25519 私钥以及注册表的 mcp-publisher CLI。私钥由维护人员保管,绝不会放入此仓库:
mcp-publisher login dns --domain customdomain.ai --private-key "$REGISTRY_PRIVATE_KEY_HEX"
mcp-publisher publish server.json
端点以 distroless 容器形式从私有单体仓库发布,二进制文件内置了 /healthz 探针(使用 -probe,因为镜像中没有 shell)。客户端始终连接到已部署的构建,上游新增的工具会自动出现,无需你做任何更改;回滚只需重新部署之前的镜像,客户端完全无需采取任何操作。请将集成固定到工具名称和 connected 布尔值,而非版本字符串。
按通常的处理顺序,可用的运维手段如下:在控制台撤销密钥或 Agent 的授权,以切断行为异常的 Agent;降低 MCP_TENANT_RPS;取消设置 MCP_PURCHASE_AUTHZ_URL 以拒绝所有购买;监控服务和控制平面的错误报告。影响工具的更改会记录在文档更新日志中。
已知限制
- 178 个已编目的 DNS 提供商中,有 116 个没有自动流程。 工具仍然可用(会返回记录和链接),但需要人工添加。先调用
discover-provider,了解你遇到的是哪种情况。详细情况已发布在 提供商 页面。 - Agent 无法独自完成手动连接。 这种设计有意采用链接中介方式:Agent 返回链接并轮询;人工完成付款步骤,以及在没有自动流程时完成 DNS 步骤。
- 托管服务上无法购买。
create-domain-order需要授权,但该服务未配置购买授权回调,因此会返回rejected。请在控制台购买。 - 只有对 Agent 令牌,才会将
confirm与域名进行比对。disconnect-domain要求所有调用方都提供confirm,但目前控制平面仅会对委派的 Agent 令牌检查该值是否为连接对应的域名。使用 API 密钥或客户端凭据令牌时,请在调用前自行检查。 - Cursor 目前尚无法登录。 它使用 API 密钥,该密钥可访问整个工作区。
- 基于浏览器的客户端会被拒绝。 网页发出的请求会携带
Origin,而托管服务只接受自身的来源(该服务未设置MCP_ALLOWED_ORIGINS),因此此类客户端会收到403。以进程或服务器形式运行的客户端不会发送Origin,不受影响。 - Agent 令牌无法选择域名名称服务器的目标位置。
migrate-nameservers会将名称服务器迁移到应用程序的 DNS 主机;指定target或nameservers需要平台自身的凭据。 - 绝不支持任意 DNS 写入。 如果你需要写入自定义记录,这不是适合的服务;请使用 REST API 或你所用提供商自己的服务。
- API 密钥的速率限制按凭据计算。 将调用分散到多个密钥上的工作区,每个密钥都有各自的额度桶;Agent 令牌则在每个工作区内共享一个额度桶。连接数也会按 UTC 日历月计量,并受套餐额度限制。
- 此仓库不包含服务端源代码。 这里提供的是清单和契约;服务端托管在其他位置。
安全
本仓库中不应存放任何凭据,这里也没有。MCP 服务本身不持有任何密钥:它会将你的凭据转发给控制平面,并在不存储 Agent 令牌的情况下对其进行验证。对于 Agent 会接触的内容,优先使用委派的 Agent 令牌(范围受限、可撤销、有效期为 15 分钟)或应用级 JWT,而不是工作区级的 cd_live_ 密钥。请按“支持”部分所述报告漏洞,切勿在公开议题中披露。
相关项目
- connect-domain-for-ai-agents:Agent 技术栈指南
- customdomain-sdk:官方 JS/TS 客户端,包含
customdomain-js和@customdomain/react - awesome-custom-domains:整个领域的概览,包括可替代方案
- docs:docs.customdomain.ai 的源文件
贡献
欢迎在此提交有关文档和清单的问题与拉取请求。工具行为的变更在上游私有单体仓库中进行:请提交议题描述所需行为,相关请求会转交处理。请确保 TOOLS.md 与线上工具架构保持一致;如果拉取请求只修改其中一项而未修改另一项,我们会要求补齐。
支持
- 文档: docs.customdomain.ai
- 问题和想法: GitHub 讨论
- Bug 和修正: 在此仓库中提交 issue
- 服务状态: status.customdomain.ai
- 账户和账单: [email protected]
- 安全: 请私下发送报告至 [email protected],切勿在公开 issue 中报告。政策:app.customdomain.ai/security
许可证
MIT。CustomDomain™ 是 EverJust Company 的产品。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。