How it fits: discover, then pay
The Catalog MCP is the same two-step motion the rest of the Catalog documents, exposed as tools:Discover
list_categories, search_services, and get_service read the Catalog — public, no key. Your agent finds a service and reads its protocol, endpoint, and price.Pay
pay_service hands the call to the Router, which reads the merchant’s 402, pays it from your Delegation, enforces the cap, and relays the vendor’s response.route_by_intent does both steps in one call: describe the need, get back the best payable service, and optionally pay it — see Let the platform pick a service.
The tool surface
Discovery is free — no credential needed. Pricing, picking or paying for a service, reading your ledger, your budget and your wallet are paid tools: they need a credential, either your API key or an OAuth grant your host obtains for you. Of those, onlypay_service and route_by_intent with autoPay move money; the rest read or price and charge nothing. Each tool has its own reference page — every argument, return field and refusal:
Discovery (free)
Payments
Ledger & wallet
securitySchemes: noauth on the free tools, oauth2 with the commerce scope on the paid ones), so a host that reads tool metadata — ChatGPT does — knows which tools need linking before it calls one.
Import the MCP
Environments
Instant Setup Commands
Any host that can send headers takes the server URL plus your Nevermined API key on theAuthorization header. Discovery works with no key; paying needs a Nevermined API key and a funded, spend-capped Delegation — get a key from the Nevermined app (see Get an API key). Choose your tool:
- Claude Code
- Cursor
- Continue
- Claude Desktop
https://mcp.sandbox.nevermined.app/mcp first. A stdio-only host can bridge with mcp-remote.
If your assistant runs OAuth for you (Claude, ChatGPT, LangSmith Fleet), you don’t need a key at all — connect by URL and approve a spending cap once. That path is Connect from your assistant below; the API-key path is the Quickstart.
Auth & transport
- Transport: Streamable HTTP at
POST /mcp(stateless — each call is a self-contained JSON-RPC request; no session id). Liveness atGET /health; readiness — which checks the Nevermined API is reachable — atGET /ready.initializereports the server asnevermined-commerce. - Two ways to authenticate, one server.
- API key (any host that can send headers): put your Nevermined key on
Authorization: Bearer <key>. Every tool is served exactly as before; this is the path the quickstart below uses. - OAuth (hosts that can’t be handed a key — Claude connectors, and hosts that follow the MCP authorization spec): connect with no header at all. The server is an OAuth 2.0 protected resource — when it needs a credential it answers
401with aWWW-Authenticatechallenge that points your host at the discovery document (/.well-known/oauth-protected-resource/mcp) and asks for thecommercescope. Your host follows it to Nevermined, you approve a spending cap once, and the host retries the call with the credential it was granted. The credential is acommercegrant: it spends only from the Delegation you approved, through the Router, and nothing else.
- API key (any host that can send headers): put your Nevermined key on
- Which hosts can be granted
commerce. A host that follows the MCP spec identifies itself with a URL (its Client ID Metadata Document), so it never needs registering — but acommercegrant is account-level authority, and Nevermined grants it only to hosts its operator has listed by that URL. ChatGPT, Claude (the claude.ai connector) and Claude Code are listed out of the box, and a statically registered connector (LangSmith Fleet, with a registered redirect allow-list instead of a URL) is enabled the same way; a host that is neither is refused when you press Approve (BCK.OAUTH.0018), never silently granted. For a self-registering host the consent screen shows its domain (chatgpt.com) beside the name it calls itself, so you can check who is asking; a statically registered one shows its registered name only. How an operator lists another assistant: self-registering clients. - The credential — key or grant — is forwarded to the Nevermined API per request, never stored, never logged. Never send it to the merchant you’re paying; it authenticates you to Nevermined, nothing else.
What happens without a credential
The server runs on two hostnames per environment. They serve the same tools and differ only in when a request without a credential gets the challenge:401 (error="invalid_token"), so a host can refresh or re-authorize on its own rather than surfacing an error to you. A host that links accounts per tool rather than per connection (ChatGPT’s documented mechanism) gets the same information in-band: the paid tools carry securitySchemes, and a refused call returns an error result carrying the challenge under _meta["mcp/www_authenticate"].
sandbox and live — mcp.sandbox.nevermined.app and mcp.live.nevermined.app. The OAuth ceremony lands you on the same consent screen for both; on live the cap you approve is real money.See it in action
Claude, ChatGPT and a LangSmith Fleet agent each buy real services from a $5 budget approved once — recorded on live, with real money.
Connect from your assistant
If your assistant can run OAuth for you — Claude, ChatGPT, LangSmith Fleet — you never handle a key. The shape is the same in all three:Point your assistant at the server
nevermined, client ID langsmith-fleet, a placeholder secret, the authorization and token URLs, PKCE/S256) and then the MCP server pointed at it. Its tab below has the values.Browse the Catalog for free
Approve a spending cap, once
That approval is the credential
Pick an environment
- Claude (claude.ai)
- ChatGPT
- LangSmith Fleet
- Any other MCP host
Add the connector
Ask for something free
Ask it to buy
<slug> through the Nevermined connector and show me the merchant’s response.” The paid tool answers 401, and Claude shows an inline Connect card.Approve the cap
Claude retries
nevermined provider ID) are enabled today. An unknown client is refused when you press Approve, never silently granted. Building your own host? Contact us with its client identity — a metadata-document URL, or the client ID and redirect URIs you need registered — before you try; how listing works.What the consent page asks
One screen. What you set:- The spending cap, in USDC or EURC.
- How long the grant is valid for.
- Nothing else — the environment badge (Sandbox or Live) and who is asking are shown, not chosen. The assistant’s name appears with its origin beside it (
chatgpt.com,claude.ai) for a self-registering client; a statically registered client such as LangSmith Fleet shows its name only.
- On Live, the cap is real money.
- The assistant may pay any service it can reach, not a fixed list.
- Nevermined’s routing fee comes out of the same cap — the cap is the total debited, not what merchants receive.
- Beyond spending, the grant lets the assistant read your Router payment history, your spend totals, and the funding wallet’s address and balance. The cap bounds what it can spend, not what it can see.
When the grant runs out
- The credential itself is short-lived (about an hour) and the assistant renews it silently with a refresh token for as long as the Delegation is usable and the assistant keeps using it: a grant left idle for 30 days can no longer be renewed silently (the renewal answers HTTP 400,
BCK.OAUTH.0011) and has to be re-linked, even on a 90-day cap — the Delegation itself is untouched. You see nothing otherwise. - When you disconnect, the credential is refused on its next use — a
401on the paid call. What the assistant then shows you differs by product, verified on live 2026-09-24: Claude renders an inline Connect card and, once you grant, retries the blocked call by itself; ChatGPT shows a Reconnect Nevermined card with a button (its wording says the connection “expired” even when you revoked it); LangSmith Fleet reports “Authorization required” in the thread and names Integrations, but offers no button — and needs the extra step in the troubleshooting section below. On all three the connector itself stays configured; you never remove and re-add it. When the cap is spent or the validity window ends, the credential itself is still valid: the paid call fails with an error naming the exhausted or expired Delegation (an in-band tool error, not a re-link prompt), and the next renewal is refused with an HTTP 400 carryingBCK.OAUTH.0013(budget exhausted) orBCK.OAUTH.0012(delegation expired). Discovery keeps working in every case. Re-run the connect step to approve a new cap — a Delegation is never widened or extended in place. - To revoke early, open Connections in the Nevermined app and disconnect the assistant. The credential stops working on its next call.
When connecting goes wrong
Connect completed instantly and no consent screen ever appeared
Connect completed instantly and no consent screen ever appeared
BCK.OAUTH.0017 when you press Approve
BCK.OAUTH.0017 when you press Approve
nevermined — the provider ID is what forms the callback path. Recreate the provider with the right ID, and expect the stale-account behaviour above on the next connect.The agent says the budget is spent, or the grant expired
The agent says the budget is spent, or the grant expired
It answers the question without paying anything
It answers the question without paying anything
Quickstart
The API-key route, for hosts that can send headers but cannot run OAuth (a coding agent with a config file, a script, a stdio bridge). Connect a host, run a discovery call, then a paid call — end to end. Discovery works with no credentials; paying needs a Nevermined API key and a funded, spend-capped Delegation. Using Claude, ChatGPT or Fleet? You want Connect from your assistant instead — no key involved.1. Connect your host
Point an MCP client at the server URL and set theAuthorization header to your Nevermined API key — the Instant Setup Commands above have the per-host form; the generic shape is:
mcp-remote, which forwards the same URL and header to a local stdio endpoint.2. Get an API key
Create a Nevermined API key from the Nevermined app. Discovery tools don’t need it, butpay_service and the ledger tools do. Older keys are rejected by the Router — see the Router quickstart for how to tell which you have.
The key is sent as a request header, forwarded to the Nevermined API per call, and never stored or logged by the MCP server. Never put it in a tool argument or send it to a merchant.
3. Run a discovery call
Discovery is public — call these before you’ve set any key. Ask your host to run:list_categories— the Catalog’s categories, each with a count.search_serviceswith{ "query": "weather", "protocol": "x402" }— weather listings on the x402 rail, most relevant first.queryis required; also filter bycategoryandtag(both narrow the same tag set, so passing both matches a listing tagged with either), and setpageSize(1–100). You get the first page only: thepageTokenin the result can’t be passed back yet, so narrow the query rather than paging. Each result is an ARD record carrying anidentifierURN, not aslug— the slug is its last segment (urn:air:api.live.nevermined.app:service:openweather-mpp→openweather-mpp).get_servicewith{ "slug": "<a-slug-from-the-search>" }— one service’s protocol, price label, and itsrequestShape: every callable endpoint with itspath, HTTPmethod, price andpathParams, each carrying the exactpayServiceArgsto hand topay_service. An endpoint may also carry the JSON Schema of its request (requestSchema, as the merchant declares it — sanitised by Nevermined, not verified) ornoParameters: true; for one with neither, build the request from its description or the provider’s docs. An endpoint with aquotehas a live price: the merchant’s price for one call, on the rail and network the Router pays it on, with the routing fee excluded — see Price a call before paying.
4. Prepare to pay
pay_service moves money — real on live, testnet funds on sandbox — so it needs a funded budget on your account: a Delegation whose wallet holds the asset the rail settles in (on sandbox, testnet pathUSD on Tempo Moderato for MPP, testnet USDC on Base Sepolia for x402).
Create a Delegation
setup_delegation returns a single URL for you to open; you set the currency, cap, duration and transaction limit in the browser, and the agent carries on. The agent cannot choose those numbers — that is the point of a mandate. See Getting a Delegation from inside the chat.Fund its wallet
wallet_balance reads it back from inside the chat — including after a payment fails for lack of funds. See step 6.pay_service uses the accessible Delegation (Active, unexpired, funded) automatically. Pass an explicit delegationId only to override that choice.
Getting a Delegation from inside the chat
If your agent reaches a paid call with no Delegation,pay_service returns { "error": "no_delegation", "nextTool": "setup_delegation" } instead of stopping. Calling setup_delegation answers with one URL:
pay_service picks the new Delegation up on its next call. Nothing needs to redirect back to the agent, and in a chat host nothing can: the page simply confirms and you close the tab.
If your host can receive a redirect — a CLI listening on http://127.0.0.1:<port>/… — pass it as returnUrl and your browser returns there with the delegationId. Any other origin has to be allow-listed on the deployment first; one that isn’t comes back as { "error": "return_url_not_allowed" } before you open a browser, rather than failing after you’ve filled in the form.
If a usable Delegation already exists — including the one an OAuth commerce grant just created — nobody is interrupted; the tool answers with the budget so the assistant can state it without a second call:
budget carries only the figures the API reported and is omitted entirely when none did; source (oauth_grant or account) is omitted when the origin is unknown; message is the human-relayable half and instructions the agent-facing next step — both are always present.
5. Make a paid call
Readget_service first, then call pay_service with the payServiceArgs of the endpoint you want — pass them through as-is (they carry the slug, path, method, and for a verified endpoint a pre-filled body). For a slug-routed GET, put the query string without ? in search, separate from path. Optional maxTotalCents is a non-negative safe integer that caps this call’s fee-inclusive, whole-cent budget reserve; the Delegation cap still limits total spend. To learn that figure before paying, quote the call.
For example:
slug reaches the service’s base URL, which for a multi-endpoint API is a 404, not a purchase — fal-ai-mpp, for instance, needs "path": "/fal-ai/flux/schnell". Only a single-endpoint service (the sandbox test merchants, say) is called by slug alone. method is optional: the server takes it from the Catalog endpoint matching your path, and falls back to POST when the Catalog records no method, when no Catalog endpoint matches your path, or when the matching ones disagree on the method.
The server resolves the slug, confirms it’s payable, pays the vendor’s 402 from your Delegation, and relays the vendor’s own response — with a request block showing exactly what was sent and where the method came from (caller, catalog, or default):
pay_service reference for every argument, the payable: false shape, and all outcomes.
6. Check your spend and your balance
list_payments— your Router payments, newest first, across every protocol. Filter bydelegationId,from,to.payment_summary— a count of payments plus a daily time series. (For what you’ve spent, useget_budget; for per-payment amounts,list_payments.)get_budget— the spending budgetpay_servicedraws on: cap, spent, remaining, and expiry. Relay itsmessageverbatim.wallet_balance— what your personal wallet actually holds. Different question: the ledger says what you’ve spent, the budget says what you’re allowed to spend, but the crypto rails pull from your wallet and only this says whether the money is there. Read the network the merchant quoted, not the one with money in it — live settles on two chains (USDC on Base8453, USDC.e on Tempo4217) and most services accept only one.
When a payment is refused
Refusals come back as legible results, not exceptions. The full set is on each tool’s page (pay_service); the ones to recognize:
Price a call before paying
quote_service answers “what will this one call cost?” without paying for it. It takes the slug, path, method, search, headers, body and delegationId you’d pass to pay_service and returns the live, fee-inclusive price of that exact request: the rail (protocol), the network and merchant amount (settlement), and what the call would reserve against your budget (fee). Pin the quote by passing the quoteId it returns to pay_service.
Quote the call
Decide
fee.capChargedCents is the call’s fee-inclusive price in whole cents, rounded up from fee.capChargedMicros (exact, in 1/10,000 of a cent). Here a $0.02 call plus a 2% routing fee is 2.04¢, so the figure is 3.Pay with a ceiling
pay_service with the same arguments, the quoted quoteId and delegationId, and maxTotalCents set to that figure as a number:quote_service reference for optionSet, every field, and the no-charge refusals.
Let the platform pick a service
route_by_intent turns a plain-language need into the single best payable service in the Catalog, plus the ranked shortlist it was chosen from — so your agent doesn’t search, compare listings and pick one itself. The ranking is deterministic — no randomness, and no model doing the picking — but it’s recomputed on every call from the live Catalog, so the pick can change as listings, health and payability change. It uses Nevermined’s own relevance and quality signals, behind a payability gate (listed, not flagged unpayable, healthy, not held by moderation, on x402 or MPP). When nothing passes the gate you get an explicit refusal, never a weak match.
Which tool to reach for
autoPay: false (the default) it returns the pick and charges nothing; with autoPay: true it also pays the winner (requires requestId, plus delegationId on an API key). Because an autoPay call ranks afresh and reaches the winner’s base URL, when the exact service or endpoint matters you should propose first, read get_service on chosen.slug, then pay with pay_service. See the route_by_intent reference for every argument (including filters.require / prefer / exclude), the full result shape, and the refusals.
Result and error conventions
These hold across every tool; each tool page notes only what it adds.- One JSON object per call. Each tool returns a single JSON object as the MCP text content.
- Refusals are legible results, not exceptions — an object carrying an
error(and often acodeandretryable), so an agent can branch on it. - Missing or rejected credential →
401with aWWW-Authenticatechallenge (error="invalid_token"when refused). A host that links per tool gets the challenge in-band under_meta["mcp/www_authenticate"]. - Money is in cents.
capCentsis whole cents;spentCents/remainingCentscarry up to four decimals (charged per call at 1/10,000 of a cent). The routing fee is included — never re-derive a figure by summing your own calls. Payment amounts inlist_paymentsare in the asset’s smallest unit (assetDecimals), not cents. - Error codes. Router refusals carry
BCK.ROUTER.*(Router guardrails); OAuth refusals carryBCK.OAUTH.*. Full catalogue: API error reference.