Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 184 additions & 9 deletions examples/mcp-paid-tool/README.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,205 @@
# paid MCP tool pattern
# Paid MCP tool guide

Best fit: MCP servers with expensive data, scraping, enrichment, analytics, compliance checks, search, or model calls.
This guide shows the smallest reproducible pattern for selling an MCP tool or API
call with x402 and Pyrimid. It is written for MCP maintainers who already have a
useful tool and want to add pay-per-call access without building a custom
checkout flow.

## Tool design
Best fit: MCP servers with expensive data, scraping, enrichment, analytics,
compliance checks, search, model calls, or other usage-based work.

- Free tool: `preview_*` returns schema, price, sample output, and payment requirement.
- Paid tool: `buy_*` returns HTTP 402/x402 requirement until paid.
- Discovery: publish server card, `llms.txt`, `agents.txt`, and Pyrimid catalog entry.
## What you will publish

## Minimal product metadata
Expose three machine-readable surfaces:

- A free preview tool, such as `preview_paid_search`, that returns the schema,
price, sample output, and payment instructions.
- A paid HTTP endpoint, such as `GET /api/paid/search`, that returns HTTP 402
until the buyer sends x402 payment proof.
- Discovery metadata in `llms.txt`, `agents.txt`, a server card, and the Pyrimid
catalog so buyer agents can find the tool before paying.

## 1. Add a paid endpoint

This endpoint returns a real x402-style challenge until a buyer retries with a
payment proof header. Keep the example response deterministic so agents can test
their integration without guessing the shape.

```ts
import { NextRequest, NextResponse } from "next/server"

const PRICE_USDC = 50_000 // $0.05, USDC has 6 decimals

export async function GET(request: NextRequest) {
const payment = request.headers.get("X-PAYMENT") ||
request.headers.get("X-PAYMENT-TX")

if (!payment) {
return NextResponse.json(
{
x402Version: 2,
error: "X402 payment required",
accepts: [
{
scheme: "exact",
network: "base",
asset: "USDC",
maxAmountRequired: PRICE_USDC.toString(),
resource: "https://your-service.example/api/paid/search",
payTo: "0xc949AEa380D7b7984806143ddbfE519B03ABd68B",
description: "Paid MCP search result routed through Pyrimid",
},
],
},
{
status: 402,
headers: {
"X-Pyrimid-Vendor": "your-mcp-server",
"X-Pyrimid-Product": "paid_search",
},
},
)
}

return NextResponse.json({
result: {
title: "Example paid search result",
summary: "The buyer supplied x402 payment proof and can receive data.",
citations: ["https://pyrimid.ai/quickstart"],
},
routed_by: "pyrimid",
})
}
```

## 2. Verify the 402 response

Run the endpoint without payment. Buyer agents should see HTTP 402 and parse the
`accepts[]` metadata.

```sh
curl -i "https://your-service.example/api/paid/search?q=mcp"
```

Expected response shape:

```http
HTTP/2 402
x-pyrimid-vendor: your-mcp-server
x-pyrimid-product: paid_search
content-type: application/json
```

```json
{
"x402Version": 2,
"error": "X402 payment required",
"accepts": [
{
"scheme": "exact",
"network": "base",
"asset": "USDC",
"maxAmountRequired": "50000",
"resource": "https://your-service.example/api/paid/search",
"payTo": "0xc949AEa380D7b7984806143ddbfE519B03ABd68B",
"description": "Paid MCP search result routed through Pyrimid"
}
]
}
```

After the buyer pays through an x402 client, it retries with `X-PAYMENT` or
`X-PAYMENT-TX`. Your server verifies the proof or transaction, then returns the
paid result.

## 3. Publish catalog metadata

Use stable IDs because agents may cache catalog entries.

```json
{
"vendor_id": "your-mcp-server",
"vendor_name": "Your MCP Server",
"product_id": "paid_search",
"description": "Paid MCP search result with enriched citations",
"category": "search-scraping",
"tags": ["mcp", "search", "x402", "paid-tools"],
"price_usdc": 50000,
"price_display": "$0.05",
"affiliate_bps": 3000,
"endpoint": "https://your-service.com/api/paid/search",
"endpoint": "https://your-service.example/api/paid/search",
"method": "GET",
"network": "base",
"asset": "USDC"
"asset": "USDC",
"output_schema": {
"type": "object",
"properties": {
"result": { "type": "object" },
"routed_by": { "const": "pyrimid" }
}
}
}
```

## 4. Add an MCP preview tool

The preview tool lets agents decide whether to pay before invoking the paid
route.

```json
{
"tool": "preview_paid_search",
"input_schema": {
"type": "object",
"properties": {
"query": { "type": "string" }
},
"required": ["query"]
},
"output": {
"price": "$0.05 USDC",
"network": "Base",
"asset": "USDC",
"paid_endpoint": "https://your-service.example/api/paid/search",
"catalog_product_id": "paid_search",
"sample": {
"result": {
"title": "Example paid search result",
"summary": "Short result preview"
}
}
}
}
```

## 5. Make it discoverable

Add these files at the root of your MCP/API host:

```txt
# llms.txt
Your MCP Server sells paid search results over x402 on Base.
Catalog product: paid_search
Paid endpoint: https://your-service.example/api/paid/search
Pyrimid: https://pyrimid.ai
```

```txt
# agents.txt
Service: Your MCP Server
Use: preview_paid_search before buying paid_search
Payment: x402 USDC on Base
```

## Launch checklist

- [ ] Unpaid request returns HTTP 402 with `x402Version` and `accepts[]`.
- [ ] `accepts[0].network` is `base` and `asset` is `USDC`.
- [ ] Paid retry accepts `X-PAYMENT` or `X-PAYMENT-TX`.
- [ ] Product appears in the Pyrimid catalog.
- [ ] `llms.txt`, `agents.txt`, and server card link to the paid endpoint.
- [ ] Preview tool explains price, schema, and sample output.

## Why route through Pyrimid?

- Agents can find your tool in one catalog.
Expand Down