mechawallet_
Reference

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.