Skip to main content
Glama
README.md
# faucet-mcp

MCP server that lets a coding agent request small dev funds (ETH/WETH/USDC/USDT) from a personal hot wallet, with caps and TOTP approval so a misbehaving agent can't drain it.

## Why

Agent work on smart wallets constantly needs small dev top-ups: fund a fresh smart account, seed a session key, test on a new chain. Public faucets are unreliable and rate-limited; topping up by hand is friction. This is a self-hosted faucet over MCP behind tight per-call and 24h budgets.

## Features

- Two MCP tools: `send` (transfer) and `status` (balances + remaining budget).
- Two-layer caps scoped per `(chain class, token pool)`:
  - **Soft caps** — enforced unconditionally.
  - **Hard caps** (10× soft) — also unconditional and *not* bypassable with a code.
- TOTP approval required for amounts above the soft cap; codes are single-use within a 90s replay window.
- Token pools: USDC + USDT share a `STABLE` window; ETH + WETH share `ETHWETH`.
- JIT WETH wrap on native-ETH chains — sends WETH even when the funder only holds ETH.
- Rolling 24h windows, pruned on each read.
- Chains: `ethereum`, `base`, `arbitrum`, `optimism`, `polygon`, `plasma` + their sepolia testnets and `plasma-testnet`.

## Caps (defaults)

| Chain class | Pool   | Soft/call | Soft 24h | Hard/call | Hard 24h |
| ----------- | ------ | --------- | -------- | --------- | -------- |
| mainnet     | stable | 0.10      | 1.0      | 1.0       | 10.0     |
| mainnet     | eth    | 0.00002   | 0.0005   | 0.0002    | 0.005    |
| testnet     | stable | 2         | 20       | 20        | 200      |
| testnet     | eth    | 0.001     | 0.01     | 0.01      | 0.1      |

## Setup

```bash
bun install
bun run setup            # generates a FAUCET_TOTP_SECRET + otpauth URI
cp .env.example .env     # then fill FUNDING_PRIVATE_KEY and FAUCET_TOTP_SECRET
```

Add the printed `otpauth://` URI (or scan the QR) into Apple Passwords / 1Password as a verification-code entry. Fund the hot wallet with small dev amounts on the chains/tokens you expect to use.

Smoke-test the TOTP loop:

```bash
bun run bin/verify.ts <6-digit code from your authenticator>
```

## Configuration

| Variable              | Required | Default                | Description |
| --------------------- | -------- | ---------------------- | --- |
| `FUNDING_PRIVATE_KEY` | yes      | —                      | 0x-prefixed hot wallet private key. |
| `FAUCET_TOTP_SECRET`  | yes      | —                      | Base32 TOTP secret (generated by `bun run setup`). |
| `FAUCET_STATE_FILE`   | no       | `~/.faucet/state.json` | Path for the rolling 24h send log + OTP replay cache. |
| `RPC_URL_<chainId>`   | no       | viem's public RPC      | Override the RPC for a specific chain (e.g. `RPC_URL_1=https://...`). |

## Wire into Claude Code

`~/.claude.json` or project `.claude/settings.json`:

```json
{
  "mcpServers": {
    "faucet": {
      "command": "bun",
      "args": ["run", "--cwd", "/absolute/path/to/faucet-mcp", "src/server.ts"]
    }
  }
}
```

`bun run --cwd <dir>` makes Bun auto-load `.env` from the faucet directory, so the MCP can be invoked from any cwd.

## Tools

- **`send(amount, token, chain, recipient, code?)`** — execute a transfer. `amount` is a decimal string in human units (e.g. `"0.5"`), never wei. `code` is required only when the request exceeds the soft cap.
- **`status(chain?, token?)`** — funder balances, configured caps, used budget, remaining window. Use this to plan before calling `send`.

## License

MIT — see [LICENSE](./LICENSE).

For the full design notes, threat model, and limitations: see [AGENTS.md](./AGENTS.md).