Start

Quickstart

From zero to a paid tool. Under ten minutes if your Moove account is ready.

What you need

  • Node 20 or newer.
  • A Moove account with a handle and a default wallet set. Without both, link creation fails with a 409 and no retry helps. See Moove setup.
  • An API key from the Moove dashboard. It is shown once.

Run the reference server

shell
git clone https://github.com/Jagadeeshftw/tollbooth
cd tollbooth
npm install
npm run build

export MOOVE_API_KEY=mk_live_...
# Only if your key names a different host. Do not guess it.
# export MOOVE_API_BASE_URL=https://api.moove.xyz

node examples/research-tools/dist/stdio.js

You should see [research-tools] ready on stdio. That is a complete paid MCP server: three research tools behind a credit pack, settling to your wallet.

Point a client at it

For a local stdio server, add it to your client’s MCP config with command: node and the path to dist/stdio.js. To try the deployed one instead:

claude_desktop_config.json / ~/.claude.json
{
  "mcpServers": {
    "tollbooth-research": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://tollbooth-server-production.up.railway.app/mcp"]
    }
  }
}

Then ask for something that needs a tool — Read https://example.org and tell me what it says. The first call returns a payment challenge. Open the link, pay, tell the agent you have paid, and it retries with the handle.

Make your own tool paid

Wrap the server once:

server.ts
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { definePrice } from '@tollbooth/core';
import { withPaywall } from '@tollbooth/mcp';
import { MooveClient, MooveProvider } from '@tollbooth/moove';
import { SqliteEntitlementStore } from '@tollbooth/store-sqlite';

const store = new SqliteEntitlementStore({ path: './tollbooth.sqlite' });

const provider = new MooveProvider({
  client: new MooveClient({ apiKey: process.env.MOOVE_API_KEY! }),
  store,
  prices: [
    definePrice({
      sku: 'research',
      unit: 'credit_pack',
      amount: '10.00',      // decimal string, never a number
      credits: 250,
      label: 'Research tools — 250 credits',
    }),
  ],
});

const server = withPaywall(
  new McpServer({ name: 'my-server', version: '0.1.0' }),
  { provider, store }
);

Then paidTool takes the same arguments as registerTool, plus a sku and a per-call cost. The argument order mirrors Cloudflare Agents’ paidTool so the shape is familiar.

server.ts
server.paidTool(
  'fetch_readable',
  'Fetch a web page and return its readable text.',
  { sku: 'research', cost: 1 },   // an expensive tool can cost more
  { url: z.string() },
  { readOnlyHint: true },
  async (args) => readable(String(args.url))
);

Tollbooth adds the tollboothTokenargument to your tool’s schema, gates the call, and hands your handler the arguments with the token already stripped. Unpaid calls never reach your code.

WarningBefore this takes money from strangers
The reference server’s tools take a URL from a model and fetch it. Read the SSRF section before you add a tool that reaches the network, and the link id page before you share a checkout URL anywhere public.

Where to next

Tollbooth

A paywall layer for MCP servers. An agent calls a paid tool, a human pays, the agent retries. Every number on this page is one we measured, at the precision we measured it.