MM by Escrow MCP

Treuhandservice für Geschäfte zwischen Menschen oder KI-Agenten. Die USDC des Käufers bleiben im geprüften Escrow-Contract von Coinbase auf Base, bis die Lieferung überprüft wurde. Danach gehen sie an den Verkäufer oder zurück an den Käufer. Prüft Domains, GitHub-Repositories, NFTs und Webseiten automatisch; Streitfälle werden einem Gremium aus KI-Modellen vorgelegt. Kartenzahlungen und Bankgeschäfte über Stripe.

Gehosteter MCP-Server

npx add-mcp 'https://escrowmcp.org/mcp'

Installiert in Claude Code, Codex, Cursor und mehr

Dokumentation

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
  • 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: token argument; HTTP: x-mm-token header). 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)

  1. Open — mm_create_deal with your role, title, price, terms and (ideally) a delivery check. Keep your_token; give counterparty_token to the other agent.
  2. Accept — the other side calls mm_accept_terms. The seller passes payout_address (the wallet to be paid). Either side can mm_change_terms before funding; the other side accepts again.
  3. Fund — the buyer calls mm_get_funding_request with payer_address, signs the returned EIP-712 message with that wallet, and calls mm_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.
  4. Deliver — the seller calls mm_mark_delivered with proof (a note, links, and for token deliveries the transaction hash).
  5. 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.
  6. If something is wrong — mm_open_dispute, then both sides mm_add_evidence (set ready_for_ruling when done). A panel of independent models rules on the split; mm_respond_to_ruling accepts 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.typeMM confirmsReleases by itself
domain (domain)the buyer's one-time code appears in the domain's public DNSyes
github (repo, buyer_login)the repository's new owner on GitHubyes
nft (chain, contract, token_id)the buyer's wallet holds the tokenyes
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 pagecontrol mode
file (expected_sha256)the delivered file's fingerprintno
ai_reviewMM reads the delivery against the termsno (the buyer decides)
manualthe 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_quote returns 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}/receipt returns 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

More: https://escrowmcp.org/agents (human-readable) · https://escrowmcp.org/research (the agent-escrow landscape)