Skip to article
Browse documentation +
BUILD ON IT / ELPIS

Agents & MCP

Give an agent the treasury as a tool over MCP, with scopes that make the dangerous calls impossible.

One treasury, many agents

You create one treasury, and one dashboard for it. Each agent you run gets its own API key inside that treasury, carrying only the scopes it needs.

What it isHow many
TreasuryThe money and the rules. One dashboard, shared by your team.One per business
AgentAn API key with scopes. It reads and proposes; it cannot approve unless you give it that scope.As many as you run
PoolA share of the money with its own limits — Operating, Reserve, Vendors.Several per treasury
PersonA member with a role, who decides the things an agent must not.As many as you invite

The limits belong to the treasury, not to the key. Five agents spending on the same day are bounded together, and every one of their payments lands in the same ledger, the same approvals queue and the same ceiling — which is the point. You set the bounds once, and they hold for everything you point at them.

The MCP endpoint

Elpis speaks the Model Context Protocol at POST /api/mcp (JSON-RPC 2.0), so any MCP-capable agent can call the treasury as a tool — no bespoke integration.

mcp config
{
  "mcpServers": {
    "elpis": {
      "url": "https://elpis.devilabs.dev/api/mcp",
      "headers": { "authorization": "Bearer $ELPIS_API_KEY" }
    }
  }
}
Every tool is gated by the key’s scope. A read + propose key cannot approve anything — so an agent can suggest, but a person still decides.

The tools

The treasury tools, and the settle-on-proof tools. Same rules for both: a tool returns a decision, never a fabricated success.

ToolScopeWhat it does
get_statereadTreasury state: accounts, balances, reserves, custody, what is settling.
list_actionsreadRecent actions and their outcomes.
get_actionreadOne action, with its rules, condition, window and receipt.
evaluate_paymentreadDry-run a payment; persists nothing.
propose_paymentproposeRuns every control and returns the decision. Never sends money.
submit_evidenceproposeSettles a staged payment against its condition.
approve_paymentapproveRecords a human decision. Not available to agent keys.
draft_conditionproposeDraft an acceptance condition from what has already settled.
settle_jobproposeSettle a committed job: release, refund, or hold.
replay_decisionreadRe-run a settled decision and confirm it reproduces the attestation.
get_attestationreadThe reproducible settlement receipt.
No tool both decides and executes. propose_payment and settle_job are separate from approve_payment, so an agent key that can suggest cannot also authorise.

A minimal call

tools/call — propose_payment
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "propose_payment",
    "arguments": {
      "accountId": "acc_vendors",
      "amount": "250.00",
      "address": "0x…",
      "label": "Acme",
      "documentRef": "INV-1042",
      "idempotencyKey": "invoice-1042"
    }
  }
}

The tool result is the decision, in the same shape the REST API returns — including blockedBy when a rule refused it, so the agent can explain itself rather than guess.

Two rules for the agent

  • Pass an idempotency key. Retries then reuse the same intent instead of creating a second payment.
  • Read the outcome. An agent should never treat a proposal as a payment. STAGED, APPROVAL_REQUIRED and BLOCKED are all successful tool calls describing different realities.