DOCS / GIVE YOUR AGENT HANDS

Give your agent hands

Every agent framework is bolting on a wallet. None of them want to carry the liability of letting a language model write calldata. Pantessa already solved that — so connect your agent over MCP and it gets money-hands that can't steal: it plans in plain sentences, deterministic guarded builders write every transaction, and a human (or the agent's own key, under caps) is the only signer. Nothing this surface hands your agent can execute by itself.

A real desk session — two agents, one human signature

Two doors

Both talk in sentences and links — never calldata, typed data, or deposit addresses. Pick by whether your agent needs to hear back.

  • The hands MCP — fire-and-forget. Your agent scans a wallet, plans an action, and mints one sign link to hand its human. Free, no key, instant. Best when a human is in the loop and your agent just needs to produce the link.
  • The desk MCP — stateful. Your agent opens an intent, negotiates funding routes, hands off, and then polls back (broker_status) to learn whether its human actually signed — the feedback loop the fire-and-forget hands lacks. It also carries the agent-signed path (broker_execute) for sequenced flows the agent drives with its own key, and broker_send to address an intent straight to a wallet or @handle's inbox (they open it and sign — no link to pass, they never had to ask).

Connect in five minutes

The hands MCP — one line in Claude Code (or any MCP client that speaks Streamable HTTP):

claude mcp add --transport http pantessa-hands https://hands-mcp.yeetful.com/mcp

The desk MCP — the stateful sibling:

claude mcp add --transport http pantessa-desk https://www.pantessa.com/api/broker/mcp

Any MCP client works — point it at the same URLs. Start by calling what_pantessa_can_do (hands) or broker_capabilities (desk): each returns the capability map and the handoff contract before you do anything else.

The loop

  1. Scan — scan_wallet reads a wallet's movable money across Base, Arbitrum, Optimism, and Ethereum (gas-reserve aware; Arc and Robinhood Chain are funded FROM those), so your plan is grounded in what the human actually holds.
  2. Plan — decide what should happen and phrase it as one plain sentence (“Buy $12 of AAPL”, “Swap $5 of ETH to USDC on Base”, “Protect my HYPE long with a 5% stop”). See what Pantessa can build.
  3. Hand off — prepare_handoff (hands) or broker_handoff (desk) mints a /i/<slug> sign link. Give it to your human: they connect their own wallet, Pantessa rebuilds and guard-checks the ask from scratch, and only their signature moves anything.
  4. Hear back (desk only) — poll broker_status for the server-truth funnel: opened → connected → built → signed → settled, with the signed USD. Or skip the poll: pass a callback_url to broker_open and Pantessa POSTs you a signed webhook the moment your human signs or the move settles (X-Pantessa-Signature = HMAC-SHA256 of the body under a secret returned once at open). broker_status stays the fallback.

The agent-signed path

When your agent holds the funds and the key, it does not need a human at all. broker_execute compiles a sequenced ask (fund → wait for settlement → act) into a job owned by the agent's own wallet, and hands back the job id plus a capability token. The agent then fetches each leg from the job API as the runner builds it — guarded, policy-checked, one at a time — signs and broadcasts it with its own key, and posts completion. The wait legs verify arrival on-chain before the next leg is built. Round-trip across every settlement boundary, batched within one.

This is live (proven 2026-09-23), and the SDK is the whole loop in one call — pantessa@1.1.0, entry point pantessa/desk:

import { openAndExecute, driveJob } from 'pantessa/desk'
import { privateKeyToAccount } from 'viem/accounts'

const signer = privateKeyToAccount(process.env.AGENT_KEY as `0x${string}`)
const base = 'https://www.pantessa.com'

const { jobId, token } = await openAndExecute({
  base,
  ask: 'Fund Hyperliquid with $15 from Base, then 2x long $12 of HYPE',
  signer,
  agentKey: process.env.DESK_KEY!,
})

await driveJob({
  base, jobId, token, signer,
  rpc: { 8453: process.env.BASE_RPC! },
  onLeg: (leg) => console.log(`leg ${leg.seq} · ${leg.kind} · ${leg.summary}`),
})

driveJob handles every shape the runner offers so your agent does not have to: one EVM transaction; a transaction chain (approve → swap) where the step carrying a re-quote recipe is rebuilt server-side right before it is signed; a Hyperliquid L1 action, with its one-time builder-fee cap and leverage pre-step; and a batch of those actions — signed in one pass, submitted in order inside a single settlement boundary, stopping at the first refusal so the runner re-offers from exactly there. A leg whose build has aged out is rebuilt, never re-signed. A shape it does not recognize — a CoW or Seaport order, which has its own submit endpoint — fails closed, by name. And a transaction that reverts is never posted as a completed leg. Pass dryRun: true to see every leg classified without signing or broadcasting anything — on a wallet that cannot fund a leg it comes back with the guard's own sentence instead of a stall.

Because this path has no human in the loop, it runs under a tighter fence: it requires a bound identity (agent_key, refused by name without one), proof of the wallet (wallet_signature — a personal_sign over the desk's consent text for that intent id + wallet; the desk recovers the signer, so nobody can compile a job into a wallet they don't hold), a per-intent notional cap, and a desk-level kill switch. Completion is advancement, not proof — the runner re-verifies on-chain, so a leg result the chain disagrees with fails the job closed one leg later. And the desk MCP surface itself still carries no transaction material: the signable bytes travel on the job API, over the capability token minted at execute.

What it costs

The desk is free to call by default — Pantessa earns the link-tier fee on the signed volume it clears, not on the calls. When an operator turns on the paid door, the value tools (broker_open, broker_execute, broker_send, broker_tile) cost a few cents in USDC per call over x402, while capabilities, status, and close stay free. broker_capabilities always advertises the current price, so an agent knows before it calls. Your x402 payer address is your desk identity — the same address that carries your caps and your track record.

The safety contract

This is the whole point, so it is mechanical, not a promise: the desk re-checks that no reply carries transaction bytes, and the deterministic guarded builders — not any model — write every transaction on the sign side. Read the trust model for how a build is guarded, priced, capped, and receipted before anyone signs.