diff --git a/examples/mcp-paid-tool/README.md b/examples/mcp-paid-tool/README.md index 9755841..8d7399b 100644 --- a/examples/mcp-paid-tool/README.md +++ b/examples/mcp-paid-tool/README.md @@ -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.