dmarc-doctor
by Baneado98
README.md
# _mcp-template-gated — MCP server template WITH the paywall gate baked in
This is the reusable factory template for every NEW MCP in the fleet. It is born
with the **server-side paywall gate** already wired, so a new MCP can never again
ship the premium tier for free (the bug that made conversion impossible on the
first 10 servers).
## The gate (the whole point)
- **`src/mcpServer.ts`** — the locally-installed package. The FREE tier (`deep=false`)
runs here. The PREMIUM tier (`deep=true`) does **NOT** run here: it is forwarded to
the hosted `/pro/run` endpoint with `Authorization: Bearer <KEY>`. No key → an
upsell (the premium is never executed for free).
- **`src/server.ts`** — the hosted side. `/pro/run` is gated by **two coexisting
payment lanes**:
- **x402** (USDC per call, for AI agents) via `x402-express`.
- **Stripe** prepaid API key (for humans) — a valid `Bearer` key skips x402.
The 402 body always shows BOTH lanes (`pay_with_card_stripe` + x402 `accepts`).
- **`src/stripeLane.ts`** — Stripe Checkout → webhook mints an API key into KV.
- **`src/kv.ts`** — Cloudflare KV (key store + funnel counters), degrades gracefully.
- **`src/engine.ts`** — EXAMPLE engine. Replace `run(input,{deep})` with the real
logic. Keep the contract: `deep=false` cheap/local, `deep=true` premium/server-only.
## Make a new MCP from this template
1. Copy the folder: `cp -r _mcp-template-gated <new-name>`.
2. Replace placeholders across the repo:
- `DMARC Doctor` → human name, e.g. `dns-doctor`
- `dmarc-doctor` → npm/url slug, e.g. `dns-doctor`
- `SERVICE_KEY` → the buyer's env var, e.g. `DNS_DOCTOR_KEY`
(PowerShell one-liner is in the comment block of `scripts/rename.txt`.)
3. In `package.json`/`server.json`/`stripeLane.ts` env defaults set:
- `STRIPE_KEY_PREFIX` (e.g. `dns_`), `STRIPE_PLAN_NAME`, `SERVICE_KEY_ENV`,
`SERVICE_PRO_URL`, `homepage`/`PUBLIC_BASE_URL` = the Vercel URL.
4. Write the real `engine.ts` and the real tool schema/description in `mcpServer.ts`.
5. `npm install && npx tsc` — must build clean.
## Verify the gate (regla 7 — not done until this passes)
```
FORCE_LISTEN=true PORT=8899 PRO_API_KEYS=test_key X402_ENABLED=true node dist/server.js &
curl -s -o /dev/null -w "%{http_code}\n" "http://127.0.0.1:8899/run?target=x" # 200 (free)
curl -s -o /dev/null -w "%{http_code}\n" "http://127.0.0.1:8899/pro/run?target=x" # 402 (no key)
curl -s -o /dev/null -w "%{http_code}\n" -H "Authorization: Bearer test_key" "http://127.0.0.1:8899/pro/run?target=x" # 200 (paid key)
curl -s -o /dev/null -w "%{http_code}\n" -H "Authorization: Bearer wrong" "http://127.0.0.1:8899/pro/run?target=x" # 402 (bad key)
```
MCP stdio: `deep=true` without a key must print the UPSELL (never run premium); `deep=false` returns the local free result.
## Production env (set in Vercel, sourced from config/)
`STRIPE_SECRET_KEY`, `STRIPE_WEBHOOK_SECRET`, `CLOUDFLARE_ACCOUNT_ID/API_TOKEN/KV_NAMESPACE_ID`,
optionally `SERVICE_KEY`. Everything degrades gracefully if a lane is unconfigured —
the x402 gate + 402 always work even with no Stripe/KV. **Never set the deep engine
to run client-side.**