Core concepts
Capabilities and discovery
What a capability is, the two protocols and two kinds of address, how discovery ranks results, and why an unverified seller doesn't appear in it.
A capability is one thing a buyer can pay for, called once per payment. It's either an HTTP endpoint or a single tool on an MCP server.
The record
{
"capability": {
"id": "cap_d2383f37…",
"providerId": "prv_3652ec9e…",
"name": "Invoice OCR",
"description": "Extract text and structured line items from scanned invoices",
"category": "OCR",
"protocol": "mcp",
"toolName": "extract_invoice",
"priceMinor": "100",
"currency": "USD",
"tags": ["invoices"],
"schema": { "type": "object", "properties": { "imageUrl": { "type": "string" } }, "required": ["imageUrl"] },
"latencyP50Ms": 900,
"status": "active"
},
"version": {
"id": "ver_…",
"version": "1.0.0",
"endpoint": "https://demo-seller.zanora.dev/mcp",
"address": { "kind": "url", "url": "https://demo-seller.zanora.dev/mcp" },
"pricingModel": "per_call",
"hash": "…"
}
}| Field | Meaning |
|---|---|
protocol | "rest" (an HTTP endpoint) or "mcp" (a tool on an MCP server) |
toolName | required for mcp, and not allowed for rest. One MCP server hosts many tools, so the URL alone doesn't say what was bought |
priceMinor | the price per call, as a string of cents |
schema | the request body's JSON Schema, when the seller published one. Read it before paying, so you don't pay for a call that fails with a 400 |
latencyP50Ms | the seller's advertised median response time, used in ranking |
version.address | where to reach it: a URL to call, or a package to run (see below). version.endpoint is the same thing as a display string |
version.hash | covers the fields that define what's being sold. Changing the schema publishes a new version |
status | active, draft or deprecated. Only active capabilities appear in discovery, but deprecated ids still resolve |
Two kinds of address
address.kind | Buyer does | For |
|---|---|---|
url | calls the URL (HTTP, or MCP over Streamable HTTP) | any hosted endpoint or MCP server |
package | runs a pinned npm package locally over stdio | an MCP server whose seller doesn't host it |
A package address pins an exact version, such as @acme/ocr-mcp@1.4.2, because the buyer runs that code. Discovery marks these results runsLocally: true. Buyers don't run them unless they have explicitly allowed that package. See Running seller packages.
Resolve the address; don't read endpoint
version.endpoint is a display string. In code, call resolveCapabilityAddress(version) from @zanora/core. It returns the URL or the package, and your code handles each correctly.
Discovery
curl -s -X POST https://api.zanora.dev/v1/discovery/search -H "x-api-key: $KEY" \
-H 'content-type: application/json' \
-d '{"query":"extract text from invoices","maxPriceMinor":"200","protocol":"mcp","limit":5}'Every filter is optional: query, category, protocol, maxPriceMinor, maxLatencyMs, limit. Each result has the capability, its version, its provider (id, name, verified, reputation) and a score.
Results are ranked on:
- Relevance: how closely the name, description and tags match your query.
- Price: cheaper ranks higher, within your filter.
- Latency: the seller's advertised median response time.
- Reputation: ratings from buyers who hold a receipt for what they rated.
- Verification: verified sellers rank higher.
The verification gate
Unverified sellers aren't in discovery
A seller can publish as soon as they sign up, but their capabilities stay out of discovery until a Zanora operator verifies them. If a seller publishes correctly and searches return {"results":[]}, this is the usual reason. Sellers can ask for verification from the console or the API. See Getting verified.
Changing a listing
Sellers can edit a live capability's price, wording, tags, schema and advertised latency without changing its id. They can't change its address, protocol or tool name, because a buyer's saved capability id has to keep pointing at the same thing. Moving a capability means deprecating it and publishing a new one.
Changing a price is safe even while buyers are mid-flow. Every call pays the price in the challenge Zanora signs at call time, never a price the buyer saw earlier.