All your domains, from every registrar, in one app + MCP.
DomBot pulls your whole domain portfolio — scattered across GoDaddy, Dynadot, Cloudflare, and more — into one desktop app, and serves the same portfolio to your AI agents through a built-in MCP server. It's free, open source, and local-first: your data and API keys stay on your machine.
Download for macOS, Windows, or Linux from dombot.ai or the Releases page, or try the live demo: the full app in your browser on an invented portfolio, no install and no account.
- One portfolio, every registrar. Aggregates all your domains across the registrars you configure into a single sortable, filterable table — search by name, filter by TLD / registrar / nameserver, and see registrar, creation and expiry dates, auto-renew, transfer lock, WHOIS privacy, and nameservers side by side. Expiry dates are color-coded by urgency, and at-risk domains (expired, grace, redemption, hold) get a status badge.
- Renewal costs at a glance. A renewals dashboard forecasts your spend: yearly total, amount due in the next 90 days, a month-by-month renewal chart, and breakdowns by registrar and TLD. Prices come from registrar quotes where available and a base per-TLD price database otherwise, and you can enter a price by hand for anything still unpriced.
- Export. One click exports the current (filtered, sorted) view to a spreadsheet-friendly CSV.
- Instant, offline-friendly launch. The whole portfolio is cached on disk and painted the moment the app opens, with no network calls; you refresh on demand (it never auto-refreshes) and a timestamp flags when data is going stale.
- Agent-ready. An embedded local MCP server lets AI agents (Claude Code, Claude Desktop, any MCP client) read and manage the same portfolio — see Connecting an AI agent.
DomBot currently supports GoDaddy, Cloudflare, Dynadot, NameSilo, Spaceship, Namecheap, Porkbun, Gandi, and NameBright, with more on the way.
Add each registrar in Settings → Registrars with an API key from that
provider's account — DomBot shows where to find each one. Credentials are stored
encrypted on your device via your OS keychain (Electron safeStorage) and are
never sent anywhere but the registrar's own API. See SECURITY.md
for the full trust model and how to verify it yourself.
After saving a registrar’s first account, use Add another account inside its card to connect more. An account selector appears only for registrars with multiple accounts; single-account registrars keep the original flow. See multiple registrar accounts for migration and MCP selection.
DomBot runs a local MCP server, bound to your machine only, so any MCP client can work with your portfolio. To connect Claude Code:
claude mcp add dombot --transport http http://127.0.0.1:4123/mcpOn first connect a browser page opens and DomBot's own window shows an Approve/Deny prompt with a matching confirmation code. Approve once and the client stays paired across restarts; manage or revoke paired clients in Settings → MCP Clients. The URL and a ready-to-paste connect command are also shown on the Home screen.
Claude Desktop (and other clients that can only launch a command) use the
app itself as a stdio server. Copy the ready-made entry from Settings → MCP
into claude_desktop_config.json; it looks like:
{
"mcpServers": {
"dombot": {
"command": "/Applications/DomBot.app/Contents/MacOS/DomBot",
"args": ["--mcp-stdio"]
}
}
}No approval prompt is needed for this route — it runs as you, on your machine — and if DomBot isn't open when the client starts, it launches automatically.
Once a week DomBot reads the list of releases at dombot.ai/releases.json. When there's a newer version, a green notification appears in the bell; dismiss it and it stays quiet until the next release. Nothing about you or your portfolio is sent, and you can turn the check off, or check by hand, in Settings → About.
On macOS and Windows, Update to … in Settings → About downloads the new version and Restart to update switches to it. Nothing downloads until you click. Linux packages, and copies run from somewhere other than an installed location, get a download link instead. Self-hosted instances link to how to update your setup.
The same app runs as a private web app on your own Cloudflare account — a
Worker plus one D1 database, encrypted under a key only you hold, with the MCP
server reachable at https://<your-host>/mcp.
The recommended setup is to fork this repository and connect your fork in the Cloudflare dashboard; updating is then GitHub's Sync fork button. The Deploy button is faster to start, but updates are trickier, so it isn't recommended. Both, plus the CLI and putting it behind Cloudflare Access, are in docs/self-hosting.md.
Moving from the desktop app: Settings → Sync → Export data, then import the file on your instance.
DomBot is a cross-platform desktop app built with Electron Forge, React 19,
TypeScript (strict), and Vite, styled with Tailwind CSS v4 and Zustand for
state. Registrar API support comes from
@aoxborrow/registrar-client;
agents connect through an embedded MCP server. Contributions welcome — use Node.js 22.13 or newer, clone
the repo, npm install, and npm start to run the app with hot reload.
| Command | Description |
|---|---|
npm start |
Run the app with hot reload (Forge + Vite) |
npm run package |
Package the app into an unpacked bundle |
npm run make |
Build distributables (zip/deb/rpm/Squirrel) |
npm run lint |
Lint .ts/.tsx files |
npm run format |
Format the codebase with Prettier |
npm run typecheck |
Type-check without emitting |
npm run site:build |
Minify the landing page (site/src → site/dist) |
npm run web:dev |
Run the self-hosted web app locally (wrangler dev) |
npm run web:deploy |
Build and deploy the web app to Cloudflare |
Registrar credentials are entered in Settings → Registrars and stored
encrypted via Electron safeStorage — in development and production alike. There
is no .env/environment-variable fallback: credentials come only from the
GUI store, so ambient vars from other tools can't silently shadow them (see
resolveField and
src/core/services/credentials.ts). The same
saved credentials feed both the UI and the MCP server. For the full trust model
and how to verify it, see SECURITY.md.
The MCP server (see Connecting an AI agent) is a
third adapter over the same services/ core the UI uses — see
src/electron/mcp/.
- Transport: Streamable HTTP, bound to
127.0.0.1only. Never exposed off the machine. - Auth: OAuth 2.1 (dynamic client registration + PKCE), served by the app.
The approval prompt lives in DomBot's own window; the issued token is
persisted (
userData/mcp-tokens.json) so clients stay paired across restarts. Env knobs:DOMBOT_MCP_PORT(default4123),DOMBOT_MCP_ENABLED=0to disable,DOMBOT_MCP_AUTOAPPROVE=1to skip the approval prompt (dev/testing),DOMBOT_MCP_TOKENfor a static bearer token escape hatch (dev/testing). Seesrc/core/mcp/oauth.ts. - stdio shim.
DomBot --mcp-stdioruns the same binary headless as a stdin/stdout bridge to the HTTP server, for clients that can't dial a URL (Claude Desktop). It authenticates with a per-install token the app writes touserData/mcp-stdio.json, launches the app if it isn't running, and re-initializes its session transparently if the app restarts. stdout is the JSON-RPC channel, so all logging in that mode goes to stderr. Seesrc/electron/mcp/stdio.ts. Dev builds aren't auto-launched — start the app first. - Tools. Named by scope, so a caller can tell at a glance what a tool acts
on:
portfolio_*take no scope params,registrar_*require aregistrarid, anddomain_*take adomain. Fordomain_*tools theregistraris optional — DomBot resolves it from the cached portfolio (you own the domain, so it knows who holds it), so an agent can act on a name without first looking up its registrar. Passregistrarto skip the lookup, or to act on a name not yet in the cache; if the cache can't resolve it, the tool says so and points atportfolio_sync, or says the name is in Archive.- Portfolio:
registrar_list,portfolio_query, andportfolio_sync.portfolio_queryis the primary way to read the portfolio: list, search, filter, sort, and page the cached portfolio and your imported names (by registrar, source, TLD, folder, name, nameserver, auto-renew/lock/privacy, status, and expiry), returning only the fields an agent needs (including what you paid, sold for, noted, and are asking, and the estimated renewal price) plus sync health (total,stale, and per-registrarerrors). Like the Domains page it covers the names you own by default;ownershipswitches to Archive (sold, dropped, archived, or gone from your accounts) or both, and each row says which, and whether it's Hidden. With no filters it returns every name you own (paged), so it doubles as a plain list. It's a pure cache read (no registrar calls);portfolio_syncruns the live cross-registrar pass that refreshes the cache, returning a per-registrar summary. An agent syncs once (or whenportfolio_queryreportsstale/empty), then reads cheaply. - Folders:
folder_list(with domain counts, including the built-in Hidden folder),folder_create,folder_rename,folder_delete(its domains go back to no folder), anddomain_set_folder(by folder name or id, ornullto clear). They write the same folder store as the app, so an open window updates live. - History and review:
domain_history(every event for a name, with alert status),portfolio_alerts(what the bell shows) andportfolio_alert_dismiss. - Money, notes and ownership:
domain_purchase_set,domain_sale_set,domain_note_set,domain_asking_price_set,domain_renewal_price_set(your own yearly price, overriding the estimate), anddomain_ownership_set(Dropped, Archived, or back to Owned). Each can answer an open alert withresolveswhere it fits. DomBot-local, no registrar calls; history they write is marked Agent in Activity. - Registrar accounts:
registrar_set_enabled. - Registrar reads:
registrar_test,registrar_domains,registrar_sync(targeted single-registrar refresh of the cache),registrar_check_availability,registrar_pricing. - Domain reads:
domain_get,domain_contacts_get,domain_nameservers_get,domain_dns_get,domain_email_forwarding_get,domain_url_forwarding_get,domain_renewal_price(DomBot's own estimate, distinct fromregistrar_pricing).domain_getanddomain_nameservers_getserve from the detail cache when fresh, fetch live and write through otherwise, and takerefreshto force a live fetch. - Writes (non-money):
domain_nameservers_set,domain_dns_set,domain_contacts_set,domain_email_forwarding_set,domain_url_forwarding_set,domain_set_autorenew,domain_set_lock,domain_set_privacy. Forwarding (email alias and URL redirect) is per-registrar — unsupported providers return an error. - Writes (money):
registrar_register_domain,registrar_transfer_domain,domain_renew. Not gated behind extra per-call approval — the connection-level OAuth approval is the gate — and annotated non-idempotent. - Cache write-through. A successful write patches the local cache (the same cache the desktop UI reads) and pushes an update to any open window, so the Domains table reflects the change live — no manual Sync needed.
- Cache freshness. Reads serve the local cache and report
stale/fetchedAt; an agent refreshes explicitly withportfolio_sync/registrar_sync. The app also runs a periodic background sync so the cache stays warm for MCP-only use (no window ever opened). The interval is set in Settings → Sync (Every hour … 7 days, or Off; default 24h, applied live); large portfolios may prefer a longer interval or Off.DOMBOT_SYNC_INTERVAL_MINUTESoverrides the setting for dev/testing (0disables).
- Portfolio:
- Credentials. Resolved the same way as the UI (see Credentials); a registrar is "configured" when all of its required fields are present.
DomBot is free and open source software: Copyright (C) 2026 Aaron Oxborrow, licensed under the GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later). You may use, study, share, and modify it; if you distribute a modified version, it must also be AGPL and ship its source.
Any paid data feeds are a separate, optional add-on service with their own terms
— the app itself is and stays free. The registrar logic in
@aoxborrow/registrar-client
is a separate project under the MIT license.
