ZZanoraDocs

Get started

Sell an MCP tool on the hosted platform. Sign up, ask for verification, publish and serve with one call, make a test purchase, and see the sale land.

This walkthrough sells one MCP tool for $0.10 a call. For an HTTP endpoint, the steps are the same except step 3. See Sell an HTTP endpoint. Steps marked 👤 need a person.

1

Create a provider account 👤

At console.zanora.dev↗, choose Seller, enter your email, organisation and password, and click the emailed link. The console shows your provider API key once. Save it:

Terminal
export ZANORA_API_KEY='zk.akey_….…'
curl -s https://api.zanora.dev/v1/whoami -H "x-api-key: $ZANORA_API_KEY"   # → "kind":"provider","providerId":"prv_…"
2

Ask to be verified

In the console, Seller → Publish shows a banner with a Request verification button. Or:

Terminal
curl -s -X POST https://api.zanora.dev/v1/providers/prv_…/verification-request \
  -H "x-api-key: $ZANORA_API_KEY" -H 'content-type: application/json' \
  -d '{"note":"Market data API, live since 2024, ~40k calls/month","contact":"ops@acme.example"}'

You can carry on while you wait. Your listing exists, but buyers won't find it until an operator approves you.

3

Publish and serve in one call

Terminal
npm install @zanora/middleware-mcp @modelcontextprotocol/sdk zod express
server.ts
import express from "express";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { zanoraSeller } from "@zanora/middleware-mcp";
import { z } from "zod";

// Reads ZANORA_API_KEY (a provider key). The gateway defaults to https://api.zanora.dev.
const seller = zanoraSeller();
const paid = await seller.sell({
  tool: "quote",
  description: "Latest price for a stock ticker",
  category: "finance",
  price: "$0.10",
  url: "https://acme.example/mcp",   // where buyers reach this server; or set ZANORA_PUBLIC_URL
});

const app = express().use(express.json());
app.post("/mcp", async (req, res) => {
  const server = new McpServer({ name: "acme-quotes", version: "1.0.0" });
  server.tool("quote", "Latest price for a ticker. Costs $0.10.", { ticker: z.string() },
    paid(async ({ ticker }) => {
      const answer = { ticker: String(ticker), price: await lookup(String(ticker)) };
      // structuredContent is what the receipt's hash covers, so it's what the buyer can prove they received.
      return { content: [{ type: "text", text: JSON.stringify(answer) }], structuredContent: answer };
    }),
  );
  const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
  res.on("close", () => void transport.close());
  await server.connect(transport);
  await transport.handleRequest(req, res, req.body);
});
app.listen(4025);

async function lookup(ticker: string) { return 187.42; }

The first start publishes the capability. Later starts reconcile it: if you've changed the price or description in code, the listing is updated to match. A call without payment gets back a signed price quote, and your handler runs only once the call is paid for.

The URL must be public

Buyers' agents call https://acme.example/mcp themselves. While you develop, put the port behind a tunnel (for example ngrok http 4025) and publish that URL instead.

4

Make a test purchase

Once you're verified, buy from yourself with any buyer setup, for example the buyer quickstart:

Output
Use zanora_discover to find "stock price" tools, then buy a quote for AAPL.

Before verification, you can still check the handshake. A call without payment should come back as a PAYMENT_REQUIRED result carrying the challenge.

5

Watch the sale land

Seller → Sales lists every paid call with its receipt. Seller → Earnings shows your balance. The 3% fee rounds down to the cent, so at $0.10 it rounds to zero and you keep all "10". At $1.00 you would keep "97". Or from the API:

Terminal
curl -s "https://api.zanora.dev/v1/receipts?limit=10" -H "x-api-key: $ZANORA_API_KEY"
6

Set a payout destination and cash out 👤

In Seller → Earnings, save a bank account id (ext_…) or a USDC address, then request a payout. See Earnings and payouts.

Runnable versions

The platform repository has complete starters: starters/c-seller-mcp (this page) and starters/b-seller-rest (HTTP), each with a --request-verification flag that does step 2.