AgentDomains
When an AI agent builds a website or an API, it needs a domain to serve it on.
AgentDomains hands out free ones under makes.fyi (the default) and
agentdomains.co, claimable from a single CLI command. Point a domain
at an IP or a CNAME, delegate it to your own nameservers, or add TXT records to
get HTTPS.
API base: https://api.agentdomains.co · CLI:
github.com/tashfeenahmed/AgentDomains · source-available (FSL-1.1).
Install
# with the Go toolchain
go install github.com/tashfeenahmed/AgentDomains/cmd/agentdomains@latest
# verify
agentdomains --help
Or download a prebuilt binary — macOS, Linux and Windows, amd64 and arm64 —
from the latest release.
Each archive carries the binary, README and LICENSE, and every release ships a
SHA256SUMS you can check with
shasum -a 256 -c SHA256SUMS --ignore-missing. Note the module path keeps its
capitals (AgentDomains) even though the command is lowercase.
Quickstart
agentdomains signup # instant account + API key
agentdomains claim myagent --email you@example.com --type A --content 203.0.113.10
dig +short myagent.makes.fyi # 203.0.113.10 ✨
--email — we send a
confirmation link and start a 30-day clock. Confirm within 30 days or the name (and any others
on the account) is deleted automatically. After the first time, the email is remembered on the
account, so later claim/forward/proxy calls don't repeat it.Choosing a domain
Names are claimed under makes.fyi by default. Pass
--domain agentdomains.co (CLI) or a "domain" field
(API) to claim under the other one. The same label can exist under each domain
independently; scope get/delete with
--domain when a label is claimed under both.
agentdomains claim myagent --domain agentdomains.co # myagent.agentdomains.co
Accounts & confirmation
Signup creates an anonymous provisional account and API key.
The first time you register a name you pass --email; we email a confirmation
link and the account stays provisional on a 30-day clock. Confirming the
link (a human clicks it) makes the account — and all its names — permanent:
agentdomains claim myagent --email you@example.com # registers + emails a link
agentdomains whoami # state: verified once confirmed
You can also (re)send the link any time with agentdomains email you@example.com.
If the account is never confirmed within 30 days, it and all its names are removed automatically
by a background job and the names are released. One account can hold up to ten names at once.
Labels are lowercased when you register them: claiming MyApp gives you
myapp.makes.fyi, and that is the label every later command expects.
DNS records
Claim a label, optionally with a record, then add more any time:
agentdomains claim shop --type CNAME --content myshop.vercel.app
agentdomains record shop --type A --content 203.0.113.10 --host www
agentdomains get shop # show all records, each with its id
agentdomains get shop --json # machine-readable
agentdomains unrecord shop <record-id> # remove ONE record, keep the name
| Type | Use |
|---|---|
A / AAAA | Point at an IPv4 / IPv6 address. |
CNAME | Alias to another hostname (e.g. a PaaS). |
TXT | Verification / ACME challenges (see SSL below). |
Every record has an id, printed beside it by get and
returned by claim and record. Pass that id to
unrecord to drop a single record while keeping the name — deleting the
whole name to undo one wrong IP is no longer the only option.
claim --type … --content … is given a record the API can't create, the
label is not claimed: fix the record and run the same command again.
Re-claiming a name you already hold is not an error either — the CLI says "you already
own it" and exits 0, and the API answers 409 with
"owned": true.Getting HTTPS / SSL
AgentDomains handles DNS, so you bring your own certificate. Two paths:
HTTP-01 (simplest)
Point your domain at your server, then let Let's Encrypt verify over HTTP:
agentdomains claim mybot --type A --content "$(curl -s ifconfig.me)"
sudo certbot certonly --standalone -d mybot.makes.fyi
DNS-01 (no inbound server needed)
Add the ACME challenge token as a TXT record:
agentdomains txt mybot "<token-from-acme-client>" --host _acme-challenge
URL forwarding
Forward a name to any URL with a real HTTP redirect, served at the edge with
valid HTTPS. forward claims the label first if you don't own it yet,
so it's a single step:
agentdomains forward me https://my-portfolio.example.com
# me.makes.fyi -> 302 redirect to https://my-portfolio.example.com
agentdomains forward me https://dest.com --permanent # 301 instead of 302
agentdomains forward me https://dest.com --no-preserve-path # land on target root
agentdomains unforward me # remove the forward
The request path and query are preserved by default
(me.makes.fyi/blog?x=1 → …/blog?x=1).
A forward takes the hostname over. Any A/AAAA/CNAME sitting on the
label itself is deleted as part of the call — at the DNS provider and here — and handed
back as replaced_records, which the CLI prints. So claiming a name with a
record and then forwarding it is a perfectly good sequence; nothing has to be cleared
out of the way first. Records on a sub-label (www.me.makes.fyi) are separate
hostnames and survive, and TXT records are untouched. If the forward then fails to come
up, the replaced records are put back with new ids. Going the other way is still
refused: while a forward stands, adding an address record to the same label answers a
409 telling you to unforward first.
Reverse proxy
Point a name at a backend you run somewhere else and serve it over HTTPS at
your name, with our edge certificate — nothing to configure on
the backend. Unlike a forward, the address bar stays on your name and your backend's
own content is served. proxy claims the label first if you don't own
it yet:
agentdomains proxy shop myapp.fly.dev
# shop.makes.fyi -> serves https://myapp.fly.dev, over our cert, at shop.makes.fyi
agentdomains unproxy shop # remove the proxy
We terminate HTTPS at the edge and fetch your backend by its own hostname,
so it accepts the request and you never need a certificate for your AgentDomains
name. Like a forward, a proxy replaces the label's own A/AAAA/CNAME
records, reporting them as replaced_records, and leaves sub-label and TXT
records alone. A proxy and a forward remain mutually exclusive on one label.
Nameserver delegation
Want full control of the subtree, with your own records, MX, and sub-domains? Delegate it to your nameservers:
agentdomains ns mybot ns1.yourdns.com ns2.yourdns.com
From then on, mybot.makes.fyi and everything under it is served by your
nameservers.
Using it from agents
Every command accepts --json for clean machine output, and reads
credentials from the environment so no interactive setup is needed:
export AGENTDOMAINS_API_KEY=adom_... # skip local config
agentdomains claim $NAME --email you@example.com --type A --content $IP --json | jq -r .fqdn
You can also call the HTTP API directly (below), which is handy inside sandboxes.
If your agent speaks MCP, skip the shell entirely: the
MCP server exposes every operation as a typed tool, over stdio
(npx -y agentdomains-mcp) or the hosted endpoint at
mcp.agentdomains.co.
CLI commands
| Command | Description |
|---|---|
agentdomains signup | Create an account; saves the key to ~/.agentdomains/config.json |
agentdomains whoami | Account state, usage, and the per-account cap on names held at once |
agentdomains email <addr> | Attach an email for human validation |
agentdomains claim <label> | Register <label>.makes.fyi (--email required on first use; --domain agentdomains.co; optional --type/--content/--host) |
agentdomains list | List your domains |
agentdomains get <label> | Show one domain and its records |
agentdomains record <label> | Add a record: --type --content [--host]; prints the new record's id |
agentdomains unrecord <label> <record-id> | Remove one record, keeping the name (ids come from get) |
agentdomains forward <label> <url> | Forward to a URL (--permanent, --no-preserve-path); claims the label if needed |
agentdomains unforward <label> | Remove a forward |
agentdomains proxy <label> <host> | Serve a backend at the name over HTTPS (our cert); claims the label if needed |
agentdomains unproxy <label> | Remove a reverse proxy |
agentdomains ns <label> <ns>… | Delegate to your nameservers |
agentdomains txt <label> <value> | Add a TXT record (--host _acme-challenge) |
agentdomains delete <label> | Delete a domain and its records |
agentdomains account delete | Close the account and invalidate its key; --force deletes the names it still holds |
agentdomains version | Print the CLI version |
Global flags: --json, --api-url,
--domain. Env: AGENTDOMAINS_API_KEY,
AGENTDOMAINS_API_URL.
MCP server
AgentDomains ships a Model Context Protocol server, so an agent can register and manage names as typed tool calls instead of shelling out. Run it locally over stdio, or point at the hosted endpoint — same tools either way.
Local (stdio)
AGENTDOMAINS_API_KEY=adom_… npx -y agentdomains-mcp
In Claude Code:
claude mcp add agentdomains --env AGENTDOMAINS_API_KEY=adom_… -- npx -y agentdomains-mcp
In Claude Desktop, add to claude_desktop_config.json:
{
"mcpServers": {
"agentdomains": {
"command": "npx",
"args": ["-y", "agentdomains-mcp"],
"env": { "AGENTDOMAINS_API_KEY": "adom_…" }
}
}
}
No env var needed if you already use the CLI — the server reads
~/.agentdomains/config.json. AGENTDOMAINS_API_URL overrides the
API base. The key is never logged or echoed in tool output.
Hosted (remote)
Streamable HTTP at https://mcp.agentdomains.co, authenticated with the
same Bearer key. Nothing to install:
claude mcp add --transport http agentdomains https://mcp.agentdomains.co \
--header "Authorization: Bearer adom_…"
# or by hand
curl -s https://mcp.agentdomains.co \
-H "Authorization: Bearer adom_…" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
Or as a config-file entry, for clients that take one:
{
"mcpServers": {
"agentdomains": {
"type": "http",
"url": "https://mcp.agentdomains.co",
"headers": { "Authorization": "Bearer adom_…" }
}
}
}
Tools
| Tool | Endpoint | Description |
|---|---|---|
check_availability | GET /v1/available | Is a label free? No key required |
signup | POST /v1/signup | Create an account; the key is shown once. No key required |
whoami | GET /v1/whoami | Account state, email, quota, usage |
attach_email | POST /v1/account/email | Attach an email and send its verification link |
claim_domain | POST /v1/subdomains | Register a name, optionally with a first record |
list_domains | GET /v1/subdomains | List every name on the account |
get_domain | GET /v1/subdomains/{label} | One name, its records and forward/proxy state |
delete_domain | DELETE /v1/subdomains/{label} | destructive Delete a name and all its records |
add_dns_record | POST /v1/subdomains/{label}/records | Add an A, AAAA, CNAME, or TXT record |
delete_record | DELETE /v1/subdomains/{label}/records/{id} | destructive Remove one record, keeping the name |
add_acme_challenge | POST /v1/subdomains/{label}/records | TXT at _acme-challenge for Let's Encrypt DNS-01 |
set_forward | PUT /v1/subdomains/{label}/forward | Redirect the name to a URL; replaces the address records on it |
remove_forward | DELETE /v1/subdomains/{label}/forward | Stop forwarding |
set_proxy | PUT /v1/subdomains/{label}/proxy | Serve a backend through the edge, TLS terminated for you; replaces the address records on it |
remove_proxy | DELETE /v1/subdomains/{label}/proxy | Stop proxying |
delegate_nameservers | PUT /v1/subdomains/{label}/ns | Delegate the name to your own nameservers |
delete_account | DELETE /v1/account[?force=true] | destructive Close the account and kill its key; refuses while names are held unless force |
Every label-scoped tool takes an optional domain
(makes.fyi or agentdomains.co). Seventeen tools in all.
set_proxy (the edge terminates TLS with its own certificate — nothing
to install on your origin), or add_acme_challenge (publishes the DNS-01
record so your own ACME client can issue a cert). A plain public web server needs
neither: Let's Encrypt HTTP-01 just works. See Getting HTTPS / SSL.Client compatibility
Any MCP client works. Common ones:
| Client | How |
|---|---|
| Claude Code | claude mcp add, stdio or --transport http |
| Claude Desktop | mcpServers block in claude_desktop_config.json |
| OpenAI Agents SDK | MCPServerStdio, or MCPServerStreamableHttp for the hosted URL |
| LangChain / LangGraph | langchain-mcp-adapters → MultiServerMCPClient |
| CrewAI | MCPServerAdapter with the same stdio command |
Source: github.com/tashfeenahmed/AgentDomains-mcp
HTTP API
Base URL https://api.agentdomains.co. Authenticate with
Authorization: Bearer <api_key>.
| Method & path | Description |
|---|---|
POST /v1/signup | Create a provisional account, returns api_key |
GET /v1/whoami | Account info |
POST /v1/account/email | {"email":"…"}, sends a validation link |
POST /v1/subdomains | {"label","email?","domain?","type?","content?","host?"} — email required on first registration |
GET /v1/subdomains | List |
GET /v1/subdomains/{label} | Show one |
POST /v1/subdomains/{label}/records | Add a record |
DELETE /v1/subdomains/{label}/records/{id} | Remove one record, keeping the name |
PUT /v1/subdomains/{label}/ns | {"nameservers":[…]} |
PUT /v1/subdomains/{label}/forward | {"target","permanent?","preserve_path?","cloak?"} |
DELETE /v1/subdomains/{label}/forward | Remove a forward |
PUT /v1/subdomains/{label}/proxy | {"origin","domain?"} — reverse-proxy the name to a backend host |
DELETE /v1/subdomains/{label}/proxy | Remove a reverse proxy |
DELETE /v1/subdomains/{label} | Delete |
DELETE /v1/account[?force=true] | Close the account; 409 listing held names unless force=true |
Errors are JSON too, and carry the field that tells them apart:
409 {"owned":true} means the name is already yours (carry on),
400 means the request was wrong, and an upstream failure is
503 {"upstream":"cloudflare","retry":…} — retry:true for an
outage worth coming back to, retry:false for one that needs us to fix
something first. A 429 carries Retry-After and repeats it in
the body as retry_after.
# example: claim with curl
KEY=$(curl -s -X POST https://api.agentdomains.co/v1/signup | jq -r .api_key)
curl -s -X POST https://api.agentdomains.co/v1/subdomains \
-H "Authorization: Bearer $KEY" \
-d '{"label":"myagent","email":"you@example.com","type":"A","content":"203.0.113.10"}'
agent·domains · agentdomains.co · Pricing · GitHub