Skip to main content
Glama
cosankov

cheapinboxes-mcp

by cosankov
README.md
# cheapinboxes-mcp

MCP server for the [CheapInboxes API](https://api.cheapinboxes.com/docs/) plus [Porkbun](https://porkbun.com) domain buying — run the whole cold-email infrastructure pipeline from any MCP client (Claude Code, Cursor, Claude Desktop, …) instead of clicking through dashboards:

**buy domains on Porkbun → import them into CheapInboxes → provision Google/Microsoft mailboxes → grab credentials / sync to Instantly, Smartlead, EmailBison, PlusVibe.**

32 tools: 8 for Porkbun, 21 for CheapInboxes, two raw escape hatches that reach every endpoint of both APIs, and a `runbook` tool that teaches the model the end-to-end flow.

## Setup

Requires Node 18+ (uses global `fetch`).

```bash
git clone https://github.com/cosankov/cheapinboxes-mcp.git
cd cheapinboxes-mcp
npm install
```

### Keys

| Variable | Where to get it | Needed for |
|---|---|---|
| `CHEAPINBOXES_API_KEY` | CheapInboxes dashboard → Integrations → API | all `ci_*` tools |
| `PORKBUN_API_KEY` + `PORKBUN_SECRET_KEY` | porkbun.com → Account → API Access (enable API access per domain too) | all `porkbun_*` tools |

The two sides are independent — with only a CheapInboxes key the `porkbun_*` tools error cleanly and everything else works, and vice versa.

Keys are read from `process.env` first, then from the first `.env` file found: `$CHEAPINBOXES_MCP_ENV` → `.env` next to `server.mjs`. Easiest: copy your keys into a `.env` in the repo root (gitignored):

```
CHEAPINBOXES_API_KEY=ci_live_...
PORKBUN_API_KEY=pk1_...
PORKBUN_SECRET_KEY=sk1_...
```

### Register with your MCP client

Claude Code / Cursor (`.mcp.json`):

```json
{
  "mcpServers": {
    "cheapinboxes": {
      "command": "node",
      "args": ["/absolute/path/to/cheapinboxes-mcp/server.mjs"]
    }
  }
}
```

(Or pass the keys via the `"env"` block instead of a `.env` file.)

### Verify

```bash
npm run smoke
```

Boots the server over stdio, lists all tools, live-pings Porkbun, and checks the CheapInboxes key — each side reports `[OK]` or a clean error telling you which key is missing.

## The flow

Ask your MCP client to run the `runbook` tool, or follow it yourself:

1. `porkbun_check_domain` per candidate — availability + live price. **Rate limit: 1 check / 10 s.**
2. `porkbun_register_domain` — `dry_run` defaults to **true** (preview, no charge); pass `dry_run: false` to buy. `cost_cents` must exactly match the checked price (Porkbun's own guard). Live runs auto-send an `Idempotency-Key`, so retries can't double-charge.
3. `ci_stage_imports` with the purchased domains (`source_provider: "porkbun"`).
4. `ci_quote` — cart of `{domain, tld, staged_import_id, mailboxes: {provider, count}}`; imported domains are $0.
5. `ci_checkout` — same cart with mailbox personas `{first_name, last_name, email_prefix}`; optional `integration_id` auto-connects mailboxes to a sending platform. **Charges the card on file.**
6. Poll `ci_list_domains` with the returned `order_id` until nameservers appear (or `ci_domain_nameservers` per domain).
7. `porkbun_set_nameservers` — point each domain at the CheapInboxes nameservers.
8. Poll `ci_get_domain` until `status: "active"` (`include_runs: true` adds provisioning-step history for debugging).
9. `ci_mailbox_credentials` for logins (password, app password, IMAP/SMTP) or `ci_sync_integration` to push mailboxes to your sequencer.

## Tool map

| Area | Tools |
|---|---|
| Guide | `runbook` |
| Porkbun | `porkbun_ping`, `porkbun_pricing`, `porkbun_check_domain`, `porkbun_register_domain` ⚠💰, `porkbun_list_domains`, `porkbun_get_nameservers`, `porkbun_set_nameservers`, `porkbun_dns` |
| CheapInboxes discovery | `ci_org`, `ci_tld_pricing`, `ci_mailbox_pricing`, `ci_search_domains` |
| Import → order | `ci_stage_imports`, `ci_list_staged_imports`, `ci_remove_staged_import`, `ci_quote`, `ci_checkout` ⚠💰, `ci_get_order` |
| Domains | `ci_list_domains`, `ci_get_domain`, `ci_domain_nameservers` |
| Mailboxes | `ci_list_mailboxes`, `ci_get_mailbox`, `ci_mailbox_credentials` 🔐, `ci_create_mailboxes` ⚠💰, `ci_update_mailbox` |
| Platform sync | `ci_list_integrations`, `ci_sync_integration` |
| Billing | `ci_billing_summary` |
| Escape hatches | `ci_api` (any CheapInboxes endpoint), `porkbun_api` (any Porkbun endpoint) |

⚠💰 = spends real money. 🔐 = returns secrets.

The escape hatches cover everything not curated: CheapInboxes DNS records, DMARC, forwarding, webhooks, cancellations, invoices, TOTP codes, org members; Porkbun SSL bundles, glue records, email forwarding, contacts, marketplace.

## Safety rails

- `porkbun_register_domain` previews by default; a purchase requires an explicit `dry_run: false`, an exact `cost_cents` match, and gets an idempotency key.
- `ci_checkout` has no server-side dry run — **always run `ci_quote` first** (identical cart shape, so it's a copy-paste).
- Rate limits: CheapInboxes 120 req/min; Porkbun 1 availability check / 10 s, 1 registration attempt / 10 s, 50 registrations / day.
- Porkbun sandbox: use `pk1_sb_` / `sk1_sb_` keys (and `PORKBUN_BASE_URL` if needed) to rehearse purchases with fake credit.

## License

MIT