MM by Escrow MCP
Escrow for deals between people or AI agents. The buyer's USDC waits in Coinbase's audited escrow contract on Base until delivery is checked, then goes to the seller or back to the buyer. Checks domains, GitHub repos, NFTs and web pages on its own; disputes go to a panel of AI models. Card and bank deals through Stripe.
Barındırılan MCP Sunucusu
npx add-mcp 'https://escrowmcp.org/mcp'Claude Code, Codex, Cursor ve daha fazlasına kurulur
Dokümantasyon
MM by Escrow MCP — guide for AI agents
MM is an escrow middleman for deals between strangers, people or AI agents. The buyer locks USDC on Base in Coinbase's audited Commerce Payments escrow contract (AuthCaptureEscrow, 0xf96815976523E00e65Be8f34cA5e64b4f41EB19c). From there it can only go to the seller once delivery is confirmed, or back to the buyer. MM checks delivery itself where the proof is public and settles disputes with a panel of AI models from different labs. An agent can run a whole deal without a person: open it, accept it, fund it from its own wallet, deliver, verify and get paid.
Connect
- MCP (Streamable HTTP, stateless, no account, no API key):
https://escrowmcp.org/mcp- Claude Code:
claude mcp add --transport http escrowmcp https://escrowmcp.org/mcp - Any client:
{"mcpServers": {"escrowmcp": {"type": "http", "url": "https://escrowmcp.org/mcp"}}} - MCP Registry name:
org.escrowmcp/mm· Server Card: https://escrowmcp.org/mcp/server-card · AI Catalog: https://escrowmcp.org/.well-known/ai-catalog.json
- Claude Code:
- HTTP/JSON (same actions): OpenAPI 3.1 at https://escrowmcp.org/openapi.json
- Each deal has two private tokens, one per side. Every call carries yours (MCP:
tokenargument; HTTP:x-mm-tokenheader). Whoever holds a token acts as that side, so pass the counterparty's token only to the counterparty.
Networks
base-sepolia— test USDC (free, for practice) on Base Sepolia (testnet), deals $1–$1,000,000, open- Card / bank / wire in US dollars through Stripe (test mode):
payment_rail: "card_or_bank". A person completes the Stripe pages.
Practice first: use network: "base-sepolia". Free test USDC: https://faucet.circle.com or the Coinbase developer faucet.
A deal, start to finish (USDC)
- Open —
mm_create_dealwith your role, title, price, terms and (ideally) a delivery check. Keepyour_token; givecounterparty_tokento the other agent. - Accept — the other side calls
mm_accept_terms. The seller passespayout_address(the wallet to be paid). Either side canmm_change_termsbefore funding; the other side accepts again. - Fund — the buyer calls
mm_get_funding_requestwithpayer_address, signs the returned EIP-712 message with that wallet, and callsmm_submit_funding_signature. No gas: MM submits the transaction. The signature only authorizes this exact payment into this escrow, and it expires in 2 hours. - Deliver — the seller calls
mm_mark_deliveredwith proof (a note, links, and for token deliveries the transaction hash). - Get paid — an automatic check passes, or the buyer calls
mm_accept_delivery, or the inspection window ends. MM releases the payment to the seller's wallet minus its fee. - If something is wrong —
mm_open_dispute, then both sidesmm_add_evidence(setready_for_rulingwhen done). A panel of independent models rules on the split;mm_respond_to_rulingaccepts it or appeals once to a larger panel.
Every deal view tells you whose move it is: your_move (plain words), your_move_tool (which tool makes it) and waiting_on (you, them, mm or none). Poll mm_get_deal, or set a webhook with mm_set_webhook.
Signing the funding message
mm_get_funding_request returns typed_data (EIP-712, ERC-3009 ReceiveWithAuthorization for USDC), typed_data_v4 (ready for eth_signTypedData_v4) and digest (the 32-byte EIP-712 hash, for signers that only sign raw hashes).
JavaScript (viem):
const fr = /* mm_get_funding_request result */;
const t = fr.typed_data_v4;
const { EIP712Domain, ...types } = t.types;
const signature = await account.signTypedData({
domain: { ...t.domain, chainId: Number(t.domain.chainId) }, types, primaryType: t.primaryType,
message: { ...t.message, value: BigInt(t.message.value), validAfter: BigInt(t.message.validAfter), validBefore: BigInt(t.message.validBefore) },
});
// then: mm_submit_funding_signature { deal_id, token, signature }
Python (eth-account):
from eth_account import Account
from eth_account.messages import encode_typed_data
signed = Account.sign_message(encode_typed_data(full_message=fr["typed_data_v4"]), private_key)
signature = "0x" + signed.signature.hex()
Raw-hash signers (KMS, HSM, MPC): sign digest directly with secp256k1, no message prefix, and send the 65-byte r‖s‖v signature.
Delivery checks MM runs itself
Set check on mm_create_deal. Objective checks release payment with no one clicking anything.
| check.type | MM confirms | Releases by itself |
|---|---|---|
domain (domain) | the buyer's one-time code appears in the domain's public DNS | yes |
github (repo, buyer_login) | the repository's new owner on GitHub | yes |
nft (chain, contract, token_id) | the buyer's wallet holds the token | yes |
token_tx (chain, token, amount) | a transfer from the seller to the buyer after funding (single use) | yes |
url (url, mode: control or contains, text) | a proof code or agreed text on the page | control mode |
file (expected_sha256) | the delivered file's fingerprint | no |
ai_review | MM reads the delivery against the terms | no (the buyer decides) |
manual | the buyer accepts, or the inspection window ends | — |
A check that was already true when the money was locked never pays out instantly; it starts the inspection window instead.
Webhooks
mm_set_webhook (or webhook_url on create): MM POSTs every deal event as JSON. Verify header x-mm-signature = hex HMAC-SHA256 of the raw body, keyed by sha256("mm-party:" + your token) in hex.
Fees
- USDC deals: 1% of the price, paid by the buyer, the seller, or split (
fee_paid_by). MM is paid only on money released to the seller; a refund costs nothing. - Card / bank deals: 3.5% + $4 per deal (the flat part covers Stripe's fixed costs).
- Launch limit on real money: deals up to $2,500 for now; it rises after 25 real deals close cleanly (0 so far). Test-network deals have no launch limit.
mm_quotereturns exact amounts before you open a deal.
Rules MM follows
- The escrow contract lets MM do only two things with locked money: pay the seller named in the signed payment, or refund the buyer.
- The fee is capped inside the buyer's signature and paid to one fixed address.
- If the buyer doesn't dispute before the inspection window ends, MM pays the seller.
- If the seller misses the delivery deadline, MM refunds the buyer (plus any seller bond).
- After the on-chain expiry the buyer can call
reclaim()on the contract directly;GET /api/deals/{id}/receiptreturns that exact call. - Every event goes into a hash-chained log:
GET /api/deals/{id}/log.
Tools
mm_info · mm_quote · mm_create_deal · mm_get_deal · mm_accept_terms · mm_change_terms · mm_get_funding_request · mm_submit_funding_signature · mm_mark_delivered · mm_check_delivery_now · mm_accept_delivery · mm_open_dispute · mm_add_evidence · mm_respond_to_ruling · mm_refund_buyer · mm_cancel_deal · mm_send_message · mm_set_webhook · mm_get_payment_link · mm_get_payout_setup_link · mm_buy_usdc_link
Errors
MCP tool errors come back as isError: true with a plain-English reason ("That signature does not match this payment…"). HTTP errors return {"error": "…"} with a 4xx status. Nothing is half-done on an error; fix the input and call again.
Trust and contact
- How the money is protected, and how a buyer reclaims without MM: https://escrowmcp.org/protection
- Every finished real-money deal, no names: https://escrowmcp.org/record (JSON: https://escrowmcp.org/api/record)
- Site terms (version 2026-11-10, recorded on every deal): https://escrowmcp.org/terms · Privacy: https://escrowmcp.org/privacy · Not allowed: https://escrowmcp.org/prohibited
- A person to write to: support@escrowmcp.org
More: https://escrowmcp.org/agents (human-readable) · https://escrowmcp.org/research (the agent-escrow landscape)