MCP tools#
JSON-RPC 2.0 over streamable HTTP at https://api.mechawallet.com/mcp.
Authorization: Bearer mw_live_...
tools/list needs no auth — a host can see what's on offer before anyone connects. Everything that touches your account does.
Setup for Claude specifically: Connect Claude.
Seller tools#
create_checkout#
The one that matters. Same object as POST /v1/checkouts.
| Argument | |
|---|---|
title |
required |
price_usd |
required, decimal string |
pay_to |
your payout wallet. Optional — omit it and your account's standing payout wallet for each chain is used |
description |
|
fulfillment |
inline | relay | mcp | webhook — inferred if omitted |
payload / origin_url |
the goods, or your endpoint |
origin_method, origin_auth_type, origin_auth_value, origin_auth_header |
how we reach your endpoint |
mcp_tool |
mcp only — sell ONE named tool; omit to sell the whole server |
calls |
sell a package. relay and mcp only, minimum $1.00 |
expires_in_minutes |
|
input_schema, output_schema |
offer card |
example_input, example_output |
offer card |
freshness, coverage, source, constraints |
offer card |
content |
makes it a gated article — see Pay to Read |
Returns the checkout including its url — the thing to share.
Mode is not an argument. With a mw_ key the key decides. Over an OAuth
connection (Claude, and anything else without a key) it creates an unarmed
checkout — every face rehearses, so an agent working through a repo can mint a
dozen without any of them arriving able to take real money. go_live is the
one deliberate step that arms one, and an agent should ask before calling it.
The result carries url and test_url — the same id with /test appended.
The test face settles simulated forever, armed or not.
max_deliveries is still accepted as an old name for calls, but the schema
no longer advertises it: two names for one number is a question with only one
right answer.
reusable is not advertised either, and defaults to true. A checkout an
agent creates is a published product — an API, a tool, a payload — and a
product is not spent by its first buyer. One-shot is the invoice case: still
reachable by passing reusable: false, but not a question worth stopping a
create for, and not the axis a seller means when they say "single". That axis
is calls — one call, or a package of them.
go_live#
Arm an unarmed checkout for real money. Takes checkout_id.
Arms in place — same id, same URL. Nothing new is minted: the link already
shared is the one that now takes real payments. The URL in a script, a README
or a colleague's terminal is safe for a different reason than before — the
rehearsal address is the same checkout's /test face, which can never be
armed, and the response says so: it returns the checkout (same id) plus a
rehearsal block naming where rehearsals continue.
Idempotent: calling it twice returns the same checkout, unchanged the second time.
Offer-card fields are commercial claims
An agent should propose freshness, coverage and source for the seller to approve, never infer and publish them. A buyer relies on them.
get_content · update_content#
The mini CMS, for agents. get_content returns a gated article as the seller
wrote it — paid body, teaser, the whole declaration (owner only).
update_content edits it in place: payload is the article text, content
replaces the whole declaration, so read first, change one field, send it
all back. Same id, same URL; edits are live for the next read, including
readers already holding passes. An ordinary checkout's payload is refused —
goods a buyer was quoted stay frozen.
Fix the typo in the second paragraph of my latest article and tighten the teaser.
get_content_snippet#
| Argument | |
|---|---|
checkout_id |
required, a cnt_ id |
The block the seller pastes where the paid body used to be: the free teaser, Google's paywalled-content JSON-LD, and a plain link to the payable URL. Static HTML, so a crawler that never runs JavaScript still finds a price where the content is missing and can buy instead of leaving empty-handed.
Returns snippet, gate_url, teaser, jsonld and price_usd. Read-only:
it creates nothing and costs nothing to call twice.
issue_content_grant#
| Argument | |
|---|---|
checkout_id |
required, a cnt_ id |
subject |
required, who it is for in your own terms |
scope |
seller (default) or content |
ttl_seconds |
capped at 31 days |
Let a reader you have already authenticated read a gated article without paying: your subscribers, your staff, a comped reader. You decide who is entitled; this mints the pass.
list_mcp_tools#
Ask the seller's own MCP server which tools it advertises.
{origin_url}, plus the same optional origin_auth_* fields, returns
{origin_url, tools: [{name, description, input_schema}]}.
Call it before create_checkout with fulfillment: "mcp". Nothing is
stored — it is not a catalogue. It exists because a guessed tool name creates a
checkout that takes the money and then fails on a tool the server never had,
and the only person who can discover that is a buyer who already paid.
Then either sell the whole server for one price and let the buyer name the tool
at call time, or set mcp_tool to sell exactly one. The pin is checked on every
call rather than by the payment signature, because a package key is a bearer
token presented with unsigned query parameters.
list_checkouts · get_checkout#
Yours, and one in detail. get_checkout takes checkout_id.
list_receipts · get_receipt#
Payments received. A receipt carries the payer, the split, tx_hash and the delivery outcome.
create_webhook#
{url} → registration plus the signing secret, shown once.
get_storefront#
No arguments. The blocks for your own website: store is the live
storefront (one div + the embed script — your whole catalogue, rendered in
the page's own style, buyers paying in place), html the static list alone,
well_known the discovery file. Identical to what the dashboard's "Your
website" section copies, because it is the same handler.
Also on the server#
whoami (which account, test or live), get_analytics, get_payout_history,
list_awaiting_fulfilment and mark_fulfilled (the webhook-mode pair),
and get_embed_settings · set_embed_settings (the frame-origin allowlist,
so standing up an embedding site never has to leave the MCP flow).
tools/list is always the authority on what exists.
Escrow tools#
The whole lifecycle, without leaving MCP.
| Tool | |
|---|---|
get_escrow · list_escrows |
One escrow's state; the dispute queue for an agent working it |
escrow_action |
One buyer/seller action (release, pause, dispute…) — accountless: returns calldata, and the escrow contract authorises by msg.sender, so only the right wallet can use it |
escrow_submit |
Broadcast a signed escrow action on our gas — the second half of the gasless pair, on BOTH chains: Solana takes the signed transaction, Base takes the EIP-712 {v, r, s, deadline}. A buyer never needs native currency to act |
resolve_escrow |
Prepare an arbiter's ruling. Returns an unsigned transaction — the arbiter's own wallet signs, this connection is not that wallet |
resolve_escrow_submit |
Broadcast a platform arbiter's signed Solana ruling on our gas |
get_escrow_settings · set_escrow_settings |
Wraps GET/PUT /v1/account/escrow — the B2B2X setup an agent standing up a marketplace must be able to do from here: sub-seller escrow creates are refused until the platform's arbiter is named. arbiter="payouts" copies the payout wallets as arbiters (snapshot, not link); check_balances=true on the get reports whether they can rule today — EVM rulings cost gas |
Spending tools#
Every spending tool takes chain (base or solana), and none requires
it: with one wallet on the account the chain is picked for you, with none
the default chain is used, and with wallets on both the tool asks you to
say which. The two chains are equal in every tool.
The rail an agent buys with: a wallet mechawallet generates and holds the key to, so a connected agent can pay an x402 challenge without holding crypto. Real money moves, so a live connection is required; a test key is refused.
| Tool | |
|---|---|
list_spending_wallets |
The wallets by branch, with their addresses, so the agent can say where to send USDC. Never reads the chain |
spending_wallet_balance |
{wallet?, chain?}. What the wallet holds now, read from the chain. Warns above $999: this is a float we hold the key to, not somewhere to keep money |
pay_x402 |
{url, max_usd?, wallet?, chain?, branch?, params?, method?, body?}. Pays any x402 URL, not only ours, and returns the goods; a POST endpoint takes method: "POST" and its JSON body. The wallet's balance is the budget; max_usd caps one call; branch lets a branch's rule pick the wallet. A checkout's /test URL is a free rehearsal that needs no funds |
spending_budget |
{wallet?, chain?}. The facts to read first: the wallet's balance is the budget (no standing limits), the fee rule, the free payments left, and any step that needs a person |
spending_wallet_events |
{wallet?, chain?}. What happened, newest first: created, funded, spent (amount, URL, tx), revealed, flagged, burned, revoked, with who did it. Carries no secret |
spending_open_wallet |
{chain?, branch?, label?}. Opens a fresh wallet in Main or a branch: one wallet per job. Needs a live key and the account holder's acknowledgement; otherwise the answer's needs_person says what and where. Opens empty; the person funds it. The connection never sees its key |
spending_burn |
{wallet?, chain?}. What is left goes to the burn address the account holder set (wallet, branch or account level), less the one-cent settlement; the receipts stay, the wallet is closed. Needs a live key. The destination is never the agent's to choose |
spending_branches |
The branches: Main and the ones opened for jobs, each with its rule and its wallets |
spending_open_branch |
{name, rule?}. Opens a branch: a named group of wallets that pays through one rule (lifo, fifo, ranked). Needs a live key |
spending_set_branch |
{branch, name?, rule?, order?}. Rename, change the rule, or set the ranked order (wallet ids, first pays first). Main cannot be renamed |
spending_branch_balance |
{branch}. Every wallet in the branch and the total, read from the chain |
spending_burn_branch |
{branch}. Burns every wallet in the branch, then the branch. Needs a live key; Main cannot be burned |
spending_costs |
The price list as sentences (wallets, payments, funding, transfers, burn) and this account's fee history with monthly totals |
spending_signup |
{chain?, label?}, no credential. Opens an account and a wallet for the agent itself and returns the wallet, its key and a funding page. Until a person claims it the account holds one wallet and can receive and pay only, and gets no free wallets: the wallet owes the opening fee from its first dollar. REST twin: POST /v1/spending-wallets/signup |
spending_claim |
{email}. Emails a person the claim for an account opened with spending_signup; they sign in with that address and become its owner, their own account untouched. REST twin: POST /v1/spending-wallets/claim |
switch_account |
account (slug or id; empty for your own) |
org_members |
none (switch to the organization first) |
org_invite |
email, role (manager or spender) |
spending_statement |
{month?}. One month's statement, numbered and itemised (payments, fees, funding, transfers, burns, each with its receipt) with totals and CSV and print links; without a month, the months that have one. REST twin: GET /v1/spending-wallets/statements/{month} |
spending_stats |
{wallet?}. Spent, payments, fees, last paid: one wallet, or every wallet, every branch and the account total, with a CSV link per wallet |
spending_funding_link |
{wallet?, amount_usd?}. The wallet's Send money to link for an amount: a checkout anyone pays (a browser wallet on its page, or an agent with pay_x402) that lands the amount in the wallet; the sender pays one cent more. Also the plain address and URI |
spending_transfer |
{to, amount_usd, wallet?}. Move money between the account's own wallets on the same chain by paying the target's funding link: one cent, never a purchase |
wallet names one by id, label, address, or a chain name when the account
has one wallet on that chain; chain is the same thing. Omit both when the
account has one wallet.
Acting for an organization. Every tool takes an optional account:
the handle of an organization the connected person belongs to. The call
then runs on the organization's wallets under the person's role (spender
pays and reads; manager also opens and burns; owner also acknowledges the
first wallet). whoami lists memberships and, with account, reports
acting_for.
Connecting with a wallet key or a branch key. The dashboard shows each
wallet's own key (mw_wallet_…) and each branch's (mw_branch_…). Connect
with one and every tool above is bound to it: a wallet key needs no wallet
argument and may not name another; a branch key's pay_x402 goes through the
branch's rule unless it names a wallet in the branch, list_spending_wallets
shows the branch's wallets, and spending_open_wallet opens into the branch
only. Opening or burning a branch, and everything on the receiving side that
creates or mints, is refused for both. whoami reports the binding.
needs_person. Four things are a person's alone, in the dashboard:
acknowledging how spending wallets work (once), setting a burn address
per chain (once), funding a wallet, and revealing a key or a phrase. When a tool hits
one, its answer carries a needs_person block, or a refusal that starts
with "needs a person": the step, why an agent cannot do it, and the link.
spending_budget also reports the onboarding state and what is still open.
There is no reveal tool, ever: an MCP connection is exactly the credential
that spends, and the credential that spends must not be the credential that
exfiltrates. Getting money out is spending_burn, which can only pay the
burn address the person set, or the dashboard's Reveal key and phrase. See
the spending wallets guide.
Support tools#
Any of the account's keys reaches the desk, a wallet key included: the agent that just had a payment refused is the one that needs to ask. Threads only; nothing here moves money.
support_open_thread#
Opens a thread on the account. subject (3 to 120 characters) and body (up to 4000). A person answers in the thread and by email to the account (for an organization, to the member who opened it). Twenty open threads per account at most. REST twin: POST /v1/support/threads.
support_threads#
The account's threads with their messages, newest activity first. Optional status: open (the account wrote last), answered (a person wrote back), closed. REST twin: GET /v1/support/threads.
support_reply#
Writes in a thread; thread is the id or its first eight characters. A closed thread takes no replies. REST twin: POST /v1/support/threads/{thread}/messages.
Buyer tools#
Buyer tools need no account and no key — a buyer holds a wallet, not
one of our credentials. quote_checkout, pay_test_checkout,
report_checkout and the buyer-side escrow actions all run
unauthenticated; where an on-chain action results, the escrow contract
authorises by msg.sender, so the tool reveals nothing and produces a
transaction only the right wallet can use.
inspect_endpoint#
Look before paying. {url, method?} answers whether the URL is an x402
endpoint (it answered a 402 with a price), the price and network it quoted,
whether it is listed in the directory (with its page and reviews), and
whether its origin publishes llms.txt, openapi.json or
.well-known/x402. Nothing is paid or signed; the probe uses the pinned
client, so a private address is never reached. Needs any of the account's
credentials, because it makes requests on your behalf. next names the
pay_x402 call when there is one. REST twin: POST /v1/inspect.
search_endpoints#
What an agent can buy right now: our live checkouts and reviewed third-party
x402 endpoints, with verified prices. {query?, chain?, max_price_usd?,
category?, limit?, offset?}; every argument is optional and the tool needs
no account. Pages: limit up to 200, and the answer's total and
next_offset walk the whole list. Rows
carry name, url, price_usd, total_usd, chains, category,
verified, status and pay, which is the pay_x402(url) call that buys
the row. Third-party prices are re-read from each endpoint's own 402 on a
timer; a row that stops answering 402 is flagged (status: not_402 or
unreachable), never silently dropped. The same directory is
GET /v1/directory and, for people, /explore.
quote_checkout#
Read any checkout's price and offer card without paying. Takes a checkout URL or id; returns the total, the fee, and what you'd be buying.
Use it before deciding. It spends nothing. A …/test URL is quoted as the
rehearsal face — testnet rails, simulated settlement — and either way the
answer names where the rehearsal lives.
report_checkout#
Say a checkout failed you — the agent-native half of the abuse/failure channel. Buyers here are overwhelmingly agents with no account and no inbox; this is their recourse, and reports reach the seller's dashboard and mechawallet's own review.
review_endpoint#
Rates a directory endpoint this account has paid: rating 1 to 5, an optional body up to 600 characters, and the row named by url or entry_id from search_endpoints. Needs a receipt: a paid call to that URL from this account (a /test rehearsal does not count). One review per account per endpoint; a second replaces the first. Reviews show on search_endpoints rows, /v1/directory and /explore. REST twin: POST /v1/directory/{entry_id}/reviews.
pay_test_checkout#
Rehearse any checkout end to end — on its test face, always. Whatever URL
you pass (live face, /test face, armed or not), the payment settles
simulated on /c/{id}/test: no funds, no key, no signature. Exists so an
agent can prove the whole loop — challenge, settle, receipt, goods — before
real money is involved. Rehearsals never consume the sale.
URLs on any of the three faces are accepted — /c/, /e/ and /x/ — because
all three are addresses we publish. Rehearsing a gated article also returns
grant, grant_scope and grant_expires_in: the pass is the product there,
so a rehearsal that returned only the body would not be rehearsing the thing
being sold.
There is no pay_live_checkout tool
Deliberate. Live spending happens through a client the buyer controls — pay402, with its required max_usd ceiling — not through a tool an agent can call in a loop.
Calling it directly#
curl -X POST https://api.mechawallet.com/mcp \
-H "content-type: application/json" \
-H "Authorization: Bearer $MW_KEY" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"create_checkout","arguments":{
"title":"Financials","price_usd":"0.10","pay_to":"0x..."}}}'
The transport is a plain JSON-RPC POST: one request object in, one JSON object
back. There is no SSE stream, no GET /mcp and no session header, so the
accept header changes nothing and a bare curl is a complete client.
Notifications are the exception — notifications/* messages carry no id and
get an empty 202 rather than a result.
OAuth#
For hosts that connect on a user's behalf:
| Endpoint | |
|---|---|
/.well-known/oauth-protected-resource |
Which server guards /mcp |
/.well-known/oauth-authorization-server |
Registration, authorize, token |
POST /oauth/register |
Dynamic client registration — nothing to pre-arrange |
GET /oauth/authorize |
Consent screen |
POST /oauth/token |
Code → token, PKCE required |
POST /oauth/token with grant_type=refresh_token |
A fresh access token and a fresh refresh token; the old refresh token is spent. A connection that is used at all never has to be redone; one idle for six months does |
Every tool here is a thin wrapper over the REST API in the API reference. Nothing is reachable through MCP that isn't reachable with curl.