Skip to main content
Glama
shaimaiiee-design

x402-email-verifier

README.md
# x402 Email Verifier: pay-per-call email verification for AI agents

A remote **MCP server** on **Cloudflare Workers** that lets an AI agent check an email address before it sends to it, stores it, or acts on it. Each call to the `email_verify` tool costs **$0.001 USDC**, paid with the [x402](https://x402.org) protocol. You don't need an account or an API key: an x402-capable client pays per call.

Built on the Cloudflare Agents SDK (`McpAgent`, `withX402`, `paidTool`). The endpoint is Streamable HTTP at `/mcp`.

> **Status:** live on **Base mainnet** (`eip155:8453`, USDC) since 2026-10-17, settled via the PayAI facilitator.

## Tools

| Tool | Price | Description |
|---|---|---|
| `email_verify` | **$0.001 USDC / call** (x402) | Checks one email address and returns a JSON report (see below). |
| `health` | Free | Returns service status, price and payment network. |

### What `email_verify` checks
- **Syntax:** a pragmatic RFC 5322 subset (dot-atom local part, LDH domain labels, length limits, valid TLD). Failures return a reason code such as `invalid_local_part`, `multiple_at` or `domain_missing_tld`.
- **MX lookup:** DNS-over-HTTPS through Cloudflare DNS (`cloudflare-dns.com`). It returns up to 5 MX records sorted by priority, and it detects NXDOMAIN and null MX.
- **Disposable domain:** an offline list that also matches subdomains.
- **Role address:** for example `info@`, `support@` and similar. Plus-tags are ignored.
- **Free provider:** flags consumer mailbox providers such as gmail.com.
- **Score (0–100) and verdict:** `deliverable`, `risky`, `undeliverable` or `unknown`.

Scoring: valid syntax = 50; MX found +40 (lookup failed +15); not disposable +10, disposable −40; role address −20; no MX caps the score at 10. Invalid syntax scores 0. Verdicts:
- `undeliverable`: invalid syntax or no MX.
- `deliverable`: MX found and score ≥ 80.
- `risky`: MX found and score < 80, or the MX lookup failed on a disposable domain.
- `unknown`: the MX lookup failed and the domain is not disposable.

### Limitation: domain-level only
The server does **not** do an SMTP mailbox probe (Workers can't open port 25). It can tell you whether a **domain** accepts mail. It can't tell you whether a specific **mailbox** exists. Treat `deliverable` as "the domain is set up to receive mail and nothing looks risky".

## Example

Request (MCP `tools/call`):
```json
{ "name": "email_verify", "arguments": { "email": "jane.doe@gmail.com" } }
```

Response (returned as text content containing JSON; this is real output from the code, with `mx_records` trimmed):
```json
{
  "email": "jane.doe@gmail.com",
  "normalized": "jane.doe@gmail.com",
  "syntax_valid": true,
  "syntax_reason": null,
  "local_part": "jane.doe",
  "domain": "gmail.com",
  "disposable": false,
  "role_based": false,
  "free_provider": true,
  "mx_found": true,
  "mx_records": [
    { "priority": 5, "exchange": "gmail-smtp-in.l.google.com" },
    { "priority": 10, "exchange": "alt1.gmail-smtp-in.l.google.com" }
  ],
  "score": 100,
  "verdict": "deliverable",
  "checked_at": "2026-10-14T14:52:50.844Z"
}
```

`health` returns:
```json
{ "ok": true, "service": "x402-email-verifier", "price_usd": 0.001, "network": "eip155:8453" }
```

## Connect

> **Endpoint (TBD):** `https://<your-worker>.workers.dev/mcp`. A public hosted URL hasn't been published yet. Replace this placeholder with your own deployment.

**Payment is required for `email_verify`.** Without payment, the server answers with an x402 payment-required response that lists the payment requirements (amount, asset, network, recipient). To pay automatically, your MCP client must support x402, for example `withX402Client` from `agents/x402`, with a wallet funded with USDC on the configured network. The `health` tool works with any MCP client.

**Claude Desktop / Cursor / other clients:** add the server as a remote (Streamable HTTP) MCP server. If your client only supports stdio, use a bridge such as `mcp-remote`:
```json
{
  "mcpServers": {
    "email-verifier": {
      "command": "npx",
      "args": ["mcp-remote", "https://<your-worker>.workers.dev/mcp"]
    }
  }
}
```
Standard clients and bridges can't sign x402 payments on their own. To make paid calls, route them through an x402-capable client or proxy.

**Testing with the MCP Inspector:**
```bash
npx @modelcontextprotocol/inspector   # connect to https://<your-worker>.workers.dev/mcp
```

Payments are real Base mainnet USDC. For local testing on Base Sepolia, set `X402_NETWORK=eip155:84532` and get test USDC from https://faucet.circle.com

## Payment details
| | |
|---|---|
| Price | $0.001 USDC per `email_verify` call (1000 atomic units) |
| Network | Base mainnet, `eip155:8453` |
| Asset | USDC (Base: `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`) |
| Facilitator | `https://facilitator.payai.network` (PayAI, keyless free tier) |

## Self-host / deploy

Requirements: Node ≥ 22 (for Wrangler 4) and a Cloudflare account.

```bash
npm install
cp .dev.vars.example .dev.vars   # then set MCP_ADDRESS to YOUR Base address
npm run typecheck
npm run smoke                    # runs the verification logic, no payment (-- --offline skips DNS)
npm run dev                      # http://localhost:8787/mcp
```

Deploy:
```bash
npx wrangler login
npx wrangler secret put MCP_ADDRESS   # address that receives payments
npm run deploy                        # https://x402-email-verifier.<subdomain>.workers.dev/mcp
```

> ⚠️ The address in `.dev.vars.example` is a throwaway test address with no saved key. Never use it to receive real funds.

### Configuration
| Variable | Purpose |
|---|---|
| `MCP_ADDRESS` / `X402_RECIPIENT` | Address that receives payments. `X402_RECIPIENT` takes precedence. Required. |
| `X402_NETWORK` | Payment network. Set to `eip155:8453` (Base mainnet) in wrangler.jsonc; code default is `eip155:84532` (Base Sepolia). |
| `X402_FACILITATOR_URL` | x402 facilitator. Set to `https://facilitator.payai.network` in wrangler.jsonc (x402.org is testnet-only; code default). |

The disposable, role and free-provider lists are in `src/lists.ts`, and the verification logic is in `src/verify.ts`. No third-party email API is used.

## Credits
Adapted from the [cloudflare/agents x402-mcp example](https://github.com/cloudflare/agents/tree/main/examples/x402-mcp).