---
title: Docs: license keys for MCP servers · Stevens Keys
source: https://stevens-keys.pages.dev/docs
description: Quickstart, API reference, revocation, quotas and pricing for Stevens Keys, license keys and usage metering for MCP server creators.
publisher: Stevens Keys (Canada Site Ops)
---

# Stevens Keys creator docs

License keys, edge validation and usage metering for MCP servers. Everything here is **test mode**: keys start with `sk_mcp_test_`, revenue shows simulated demo sales plus Stripe test-mode sales (no real money), and payouts aren't live.

Contents: [Quickstart](#quickstart) · [Verification](#verification) · [Validating from an MCP server](#validate) · [Revocation](#revocation) · [Quotas](#quotas) · [Pricing](#pricing) · [Stripe checkout](#checkout) · [Buy links](#buy-links) · [Refunds](#refunds) · [API reference](#api)

## Quickstart

1. **Sign up** at [/dashboard](https://stevens-keys.pages.dev/dashboard?signup=1). Complete the human check (Cloudflare Turnstile) on the sign-up form.
2. **Get verified.** Pass the human check at sign-up and your account is verified for test mode immediately; see [below](#verification).
3. **Create a product** for your MCP server (Products tab or `POST /v1/products`). Pick its **Plan** in the Plan dropdown: `free` gives each key a default quota of 3,000 calls/month; `one_time` (and other paid plans) default to unlimited calls (`monthly_quota: null`) unless you set a per-key quota. You get a `product_id`. Unverified accounts can do this.
4. **Set a price** (optional, to sell keys): Price in the Products tab is in dollars (CAD); the API field is `price_cents`. Choose a paid plan (e.g. one_time).
5. **Share the buy link** from the Products table (`/buy?product=<id>`); buyers pay with Stripe test cards and get a key shown once ([details](#buy-links)).
6. **Or issue a key yourself** (Keys tab or `POST /v1/keys`). The plaintext key is shown once; we store only its SHA-256 hash.
7. **Validate** the key on every tool call from your server: [curl first, then fetch](#validate).
8. **Delete your account** any time from the **API & SDK** tab (password confirmation; revokes all keys).

Want to see it work first? The [demo](https://stevens-keys.pages.dev/demo) lets you issue, validate and revoke a sandbox key without an account.

## Connect via MCP

Stevens Keys runs a hosted MCP server at `https://stevens-keys.pages.dev/mcp`. Agents can create a demo key, validate it and read stats without signing up.

```
# Hosted MCP server (Streamable HTTP, no auth, test mode)
https://stevens-keys.pages.dev/mcp

# Claude Desktop / Cursor (remote server) - mcp.json / claude_desktop_config.json
{
  "mcpServers": {
    "stevens-keys": { "url": "https://stevens-keys.pages.dev/mcp" }
  }
}

# stdio-only clients: bridge with mcp-remote
{
  "mcpServers": {
    "stevens-keys": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://stevens-keys.pages.dev/mcp"]
    }
  }
}
```

Tools: `create_demo_key` (free 24h sandbox key, 50 calls), `validate_license_key` (allow/deny + metering), `get_public_stats` (aggregate adoption stats). Server card: [/.well-known/mcp/server-card.json](https://stevens-keys.pages.dev/.well-known/mcp/server-card.json).

## Verification (no email)

We can't send verification emails yet. Instead, sign-up includes a Cloudflare Turnstile human check, verified server-side. Passing it marks your account *test verified*: you can create products, issue test license keys and API secrets, and run Stripe test checkouts right away. Accounts created before this can pass the same check from the dashboard banner (`POST /v1/auth/turnstile-verify`). Without it you can create products but not issue keys or secrets (`403 email_unverified`). Manual early-access review still exists and will be required before anything live; there is no live mode yet.

## Validating from an MCP server

### curl (try this first)

```
curl -X POST https://stevens-keys.pages.dev/v1/validate \
  -H "Authorization: Bearer sk_mcp_test_..." \
  -H "Content-Type: application/json" \
  -d '{"product_id":"prod_...","units":1}'
# 200 {"allow":true,"status":"active",...} · 403 {"allow":false,"status":"revoked"} · 401 missing key
```

### Raw fetch

```
const res = await fetch("https://stevens-keys.pages.dev/v1/validate", {
  method: "POST",
  headers: { authorization: `Bearer ${key}`, "content-type": "application/json" },
  body: JSON.stringify({ product_id: "prod_...", units: 1 }),
});
const r = await res.json();   // 200 allow · 403 deny · 401 missing key
if (!r.allow) return deny(r.status);
```

### TypeScript SDK (not on npm yet)

The SDK (`stevens-keys`) isn't on npm yet. Until it is, use curl or fetch above; this is what it will look like.

```
import { StevensKeys, withLicense } from "stevens-keys";

const keys = new StevensKeys({ baseUrl: "https://stevens-keys.pages.dev", productId: "prod_..." });

// Every request must carry Authorization: Bearer sk_mcp_test_...
export default { fetch: withLicense(keys, (req, license) => handleMcp(req)) };

// Or check by hand inside a tool:
const r = await keys.validate(userKey, { units: 1 });
if (!r.allow) throw new Error(`license ${r.status}`);
```

Options: `failMode: "closed"` (default, deny if the API is unreachable) or `"open"` (allow a recently valid key for `failOpenForMs`). `meter: false` checks entitlement without counting usage. The SDK never caches metered calls.

## Selling keys with Stripe Checkout (test mode)

**Status:** live in Stripe **test mode**. Buyers pay with Stripe test cards (for example 4242 4242 4242 4242); no real money. Live keys and live-mode events are refused. Each test sale appears in your dashboard Revenue tab labelled "Stripe test" (85/15 split shown). Creator payouts (Stripe Connect) are not live.

1. Set `price_cents` (CAD, at least 50) on your product. Your account must be verified (the sign-up human check is enough for test mode).
2. Your buy button calls `POST /v1/checkout {"product_id":"prod_..."}` and redirects to the returned `url`.
3. After payment, Stripe calls our signed webhook (events: `checkout.session.completed`, `checkout.session.async_payment_succeeded`, `charge.refunded`); we issue a license key for that product (stored as a SHA-256 hash).
4. The buyer lands on `/purchase-success`, which calls `POST /v1/checkout/reveal` and shows the key **once**. Reloading the success page afterwards shows "This key was already shown or the link expired". A second reveal returns `410 already_revealed`.

## Revocation behaviour

Each key has one Durable Object that every validation goes through. Revoking or suspending a key updates that object before the API responds, so the **next** validation anywhere is denied (`revoked` / `suspended`, `cache_ttl: 0`). Revocation is terminal; suspend can be resumed. Archiving a product denies all its keys with `product_archived`.

Allowed responses carry a `cache_ttl` hint (default 30s, per-product, max 300s). If you cache allows for that long, a revoke takes effect within that window. If you don't cache (or use the SDK with metering on), it's immediate.

## Quotas

- Per-key monthly quota: set per product (free-plan default 3,000 calls/key/month) or overridden per key. Over the limit, validation returns `403 over_quota`.
- `units` (1–1000) lets one call count as more than one unit.
- Creator allowance: 50,000 validations/month on the free tier. In preview it's shown in the dashboard but not enforced.
- Up to 10 products per creator.

## Pricing: 85/15 and free tier

You keep 85% of sales processed through Stevens Keys; the platform fee is 15%. No monthly fee, no compute deduction. Free to sign up with the limits above. **Payouts via Stripe Connect are not live yet**; until they are, the dashboard shows simulated demo sales plus Stripe test sales (CAD), no real money.

## Refunds (test mode)

In the Revenue tab, each Stripe test sale has a **Refund** button (with a confirmation). The API equivalent is `POST /v1/sales/{sale_id}/refund` with an optional `{"amount_cents": 300}` for a partial refund (default: the full remaining amount). Only your own *Stripe test* sales can be refunded; simulated sales can't.

- The API creates the refund in Stripe test mode and returns `202`. Our signed `charge.refunded` webhook does the rest, so refunds made in the Stripe dashboard are handled the same way.
- **Full refund:** the buyer's key is revoked immediately (the next `/v1/validate` returns `allow:false`, status `revoked`).
- **Partial refund:** the key stays active, unless the refunds add up to the full amount.
- **Ledger:** each Stripe refund becomes one negative row (kind `refund`, linked to the original purchase), splitting gross, platform fee and creator share in proportion. Revenue totals are net of refunds and each sale shows paid / partly refunded / refunded. No real money.

## Stripe checkout & buy links (test mode)

**Set a price.** In the dashboard the Price field is in **dollars** (CAD, e.g. `9.00`). The API takes **cents**: `POST /v1/products` with `"price_cents": 900`. Products priced at CA$0.50 or more can be sold.

**Buy link.** Each priced product in the dashboard Products table has a buy link (with a copy button): `/buy?product=<product_id>`. It's a public, noindex page showing the product name, CAD price and a test-mode banner. Its Buy button calls `POST /v1/checkout` and redirects to Stripe Checkout. Archived, unpriced or unknown products return 404. Product data for the page comes from `GET /v1/public/products/{id}`.

**Your own checkout button.** Call `POST /v1/checkout` with `{"product_id":"..."}` and redirect to the returned `url`. After payment the buyer lands on `/purchase-success`, where the license key is revealed once.

**What you'll see.** Checkout runs in Stripe *test mode* only (use card 4242 4242 4242 4242). Prices stay in CAD; automatic currency conversion (Adaptive Pricing) is turned off. The test checkout page shows the Stripe sandbox's account name ("Labs"), not your product brand. Payouts to creators are not live.

## API reference

Base URL `https://stevens-keys.pages.dev`. Creator endpoints take the session cookie (dashboard) or `Authorization: Bearer sk_creator_test_...`. JSON in and out.

| Method | Path | Auth | Notes |
| --- | --- | --- | --- |
| POST | `/v1/validate` | license key | Bearer or `{key}`; body `{product_id?, units=1, meter=true}`. CORS open. |
| GET | `/v1/config`, `/healthz` | none | Rev-share, free tier, test_mode. |
| POST | `/v1/auth/signup` · `/login` · `/logout` | none | Rate limited. Signup requires `turnstile_token` (Cloudflare Turnstile). |
| POST | `/v1/auth/password-reset/request` · `/confirm` | none | Reset emails aren't delivered in preview; the response says so and points to canada.site.ops@gmail.com. |
| POST | `/v1/auth/turnstile-verify` | creator | `{turnstile_token}`: pass the human check to become test verified. |
| DELETE | `/v1/account` | creator | `{password}`: revokes all keys and deletes all account data. |
| GET/POST | `/v1/verification-request` | creator | Manual early-access review (required before anything live). POST `{note?}`; 3/hour per creator. |
| GET | `/v1/me` | creator | Includes `email_verified` and `test_verified`. |
| GET/POST | `/v1/products`; GET/PATCH/DELETE `/v1/products/:id` | creator | DELETE archives. |
| GET/POST | `/v1/keys` (`?product_id=`); GET `/v1/keys/:id` | creator (verified to issue) | POST `{product_id, label?, monthly_quota?, expires_at?}` returns `key` once. |
| POST | `/v1/keys/:id/revoke` · `/suspend` · `/resume` | creator | Effective on the next validate. |
| GET/POST | `/v1/api-secrets`; POST `/v1/api-secrets/:id/revoke` | creator (verified to create) | Secret shown once. |
| GET | `/v1/usage?product_id=&days=30`, `/v1/revenue` | creator | Daily usage, top keys, revenue: simulated demo sales plus Stripe test sales (no real money). |
| POST | `/v1/ledger/simulate-sale` | creator | `{product_id, gross_cents, key_id?}`, simulated, CAD. |
| POST | `/v1/demo/keys`, `/v1/demo/revoke` | none | Sandbox demo product only. |

Validation statuses: `active`, `invalid`, `missing_key`, `suspended`, `revoked`, `expired`, `over_quota`, `wrong_product`, `product_archived`. Rate-limited calls return `429` with `Retry-After`.

### More from Stevens Keys

- [Surface](https://nova-otter-delta-cloud.grok.me): free MCP server with per-request metering
- [Usage Lab](https://usage-lab.pages.dev/)
- [Server Track Lab](https://server-track-lab.pages.dev/)
- [API Meter Lab](https://api-meter-lab.pages.dev/)

Machine files: https://stevens-keys.pages.dev/llms.txt · https://stevens-keys.pages.dev/openapi.json · https://stevens-keys.pages.dev/mcp · https://stevens-keys.pages.dev/agent-quickstart.md
