Discovery
Let clients automatically discover your API's pricing
Overview
MPP's discovery system lets clients and agents learn what your endpoints cost before making a request. You serve a standard OpenAPI 3.1 document at /openapi.json with x-payment-info extensions that advertise one or more payment offers for each paid operation. Registries aggregate these documents so agents can find paid APIs automatically, and provide value-added services like reputation, search, and analytics.
Registries
Registries aggregate discovery documents from multiple services, making it easy for clients and agents to find paid APIs.
| Registry | Description | How to add |
|---|---|---|
| MPPScan | Public registry of MPP-enabled services with search and analytics | Manually register in one click |
| MPP Services directory | Curated list of live services on mpp.dev | Submit a PR to add your service |
Agents can query the curated services directory over MCP at
https://mpp.dev/mcp/services. The server is read-only and exposes tools to
list services, rank services for an agent task, inspect endpoint offers, get
usage recipes, look up services by payment recipient, inspect available filters,
and fetch advisory OpenAPI summaries.
Services MCP
The services MCP server is the agent-facing discovery surface for the curated MPP directory:
https://mpp.dev/mcp/servicesUse it when an agent needs to:
- rank paid APIs by task, category, integration, or payment method
- turn a selected service into a usage recipe with endpoint candidates
- compare endpoint-level payment offers before constructing a request
- identify which services publish offers for a payment recipient from a
402Challenge - inspect catalog facets before narrowing a search
- fetch a live OpenAPI summary or registry-derived endpoint view
{
"mcpServers": {
"mpp-services": {
"url": "https://mpp.dev/mcp/services"
}
}
}The MCP server is advisory and read-only. After discovery, clients call the
target service directly and treat the runtime 402 Challenge as authoritative.
For agent setup, MCP Inspector smoke tests, example prompts, and recipes, see Discover MPP services on Tempo docs.
Quick start
The mppx SDK generates discovery documents from your route configuration. Add discovery() to your server and it serves /openapi.json automatically.
import { Hono } from 'hono'
import { Mppx, discovery } from 'mppx/hono'
import { tempo } from 'mppx/server'
const app = new Hono()
const mppx = Mppx.create({
methods: [
tempo.charge({
currency: '0x20c0000000000000000000000000000000000000',
recipient: '0x...',
testnet: true,
}),
],
secretKey: process.env.MPP_SECRET_KEY,
})
app.get('/v1/fortune', mppx.charge({ amount: '0.01' }), (c) => c.json({ fortune: 'You will be rich' }))
discovery(app, mppx, {
auto: true,
info: { title: 'Fortune API', version: '1.0.0' },
})
This generates a GET /openapi.json endpoint with canonical x-payment-info.offers[] entries on each paid route.
Express
import express from 'express'
import { Mppx, discovery } from 'mppx/express'
import { tempo } from 'mppx/server'
const app = express()
const mppx = Mppx.create({
methods: [
tempo.charge({
currency: '0x20c0000000000000000000000000000000000000',
recipient: '0x...',
testnet: true,
}),
],
secretKey: process.env.MPP_SECRET_KEY,
})
const pay = mppx.charge({ amount: '0.01' })
app.get('/v1/fortune', pay, (req, res) => res.json({ fortune: 'You will be rich' }))
discovery(app, mppx, {
info: { title: 'Fortune API', version: '1.0.0' },
routes: [{ handler: pay, method: 'get', path: '/v1/fortune' }],
})
Next.js
In Next.js, discovery() returns a route handler you export from an API route.
import { discovery } from 'mppx/nextjs'
import { mppx, pay } from '../fortune/route'
export const GET = discovery(mppx, {
info: { title: 'Fortune API', version: '1.0.0' },
routes: [{ handler: pay, method: 'get', path: '/api/fortune' }],
})
How it works
Your server exposes a GET /openapi.json endpoint that returns an OpenAPI document. Paid operations include an x-payment-info extension with one or more payment offers, and the document root can include x-service-info for service-level metadata.
{
"openapi": "3.1.0",
"info": { "title": "My API", "version": "1.0.0" },
"x-service-info": {
"categories": ["ai"],
"docs": {
"homepage": "https://example.com",
"apiReference": "https://example.com/docs",
"llms": "/llms.txt"
}
},
"paths": {
"/v1/generate": {
"post": {
"x-payment-info": {
"offers": [
{
"amount": "1000000",
"currency": "0x20c0000000000000000000000000000000000001",
"description": "Generate text with Tempo",
"intent": "charge",
"method": "tempo"
},
{
"amount": "100",
"currency": "usd",
"description": "Generate text with Stripe",
"intent": "charge",
"method": "stripe"
}
]
},
"responses": {
"200": { "description": "Successful response" },
"402": { "description": "Payment Required" }
}
}
},
"/v1/models": {
"get": {
"responses": {
"200": { "description": "Successful response" }
}
}
}
}
}x-payment-info
Add this extension to any operation that requires payment. Prefer the canonical multi-offer shape:
| Field | Type | Description |
|---|---|---|
offers | Offer[] | Ordered list of payment offers the client can choose from |
offers[]
| Field | Type | Description |
|---|---|---|
amount | string | null | Payment amount in base units |
currency | string | Currency code or token address |
description | string | Human-readable description of the charge |
intent | string | Payment intent (charge or session) |
method | string | Payment method identifier (tempo, stripe) |
x-service-info
Optional root-level metadata about the service:
| Field | Type | Description |
|---|---|---|
categories | string[] | Free-form service categories (for example, ai, payments) |
docs.homepage | string | Link to the service homepage |
docs.apiReference | string | Link to API documentation |
docs.llms | string | Link to an llms.txt file for AI consumption |
Build manually
You can author a discovery document by hand following the discovery specification. The document is a standard OpenAPI 3.1 file with two extensions:
Create the OpenAPI skeleton
Start with a standard OpenAPI 3.1 document:
{
"openapi": "3.1.0",
"info": {
"title": "My API",
"version": "1.0.0"
},
"paths": {}
}Add x-payment-info to paid operations
For each endpoint that requires payment, add the x-payment-info extension with an offers array. Add more objects to offers[] when the client can choose between alternative payment methods or currencies. Amounts are in base units (for example, 1000000 for $1.00 with 6 decimals).
{
"paths": {
"/v1/generate": {
"post": {
"summary": "Generate text",
"x-payment-info": {
"offers": [
{
"amount": "1000000",
"currency": "0x20c0000000000000000000000000000000000001",
"intent": "charge",
"method": "tempo"
}
]
},
"responses": {
"200": { "description": "Successful response" },
"402": { "description": "Payment Required" }
}
}
}
}
}CLI
Generate a static discovery document from a config module:
$ npx mppx discover generate ./discovery.config.tsValidate an existing discovery document from a file or URL:
$ npx mppx discover validate https://example.com/openapi.jsonValidation
Common validation issues:
| Issue | Severity | Description |
|---|---|---|
Missing 402 response | Error | Operations with x-payment-info must include a 402 response |
| Invalid amount format | Error | Each offers[].amount value must be a non-negative integer string |
Missing requestBody | Warning | POST/PUT/PATCH operations without a requestBody definition |
| Invalid URI in docs | Error | docs links must be valid URIs or absolute paths |