Skip to content
MANDATE owl logoMANDATE

MCP

@0xgks/mandate-mcp is a thin stdio wrapper around @0xgks/mandate-sdk, published for MoonPay Agent, Claude Desktop, Codex, and other MCP-compatible clients.

Overview

MCP (Model Context Protocol) is an open standard that lets AI agents discover and call external tools in a structured, interoperable way. By publishing a dedicated MCP server, MANDATE ensures that any MCP-compatible agent can connect to the policy enforcement layer without modification to the agent itself.

The server reimplements no proving, commitment, Merkle, or submission logic of its own — every tool is a thin wrapper around the same MandateClient from @0xgks/mandate-sdk documented on the SDK page.

Installation

npm install @0xgks/mandate-mcp

Or run the published binary directly, without installing:

npx -y @0xgks/mandate-mcp@0.1.0

The repository's npm run local:start writes a complete, ready-to-paste config to .local/moonpay-agent-mandate.json automatically — see Quickstart — MCP local setup.

Client configuration

A redacted configuration example, adaptable to any MCP client that reads an mcpServers map (this shape matches MoonPay Agent, Claude Desktop, and Codex):

mcp config (redacted)
{
  "mcpServers": {
    "mandate": {
      "command": "npx",
      "args": ["-y", "@0xgks/mandate-mcp@0.1.0"],
      "env": {
        "MANDATE_RPC_URL": "<RPC_ENDPOINT>",
        "MANDATE_SEQUENCER_URL": "<SEQUENCER_ENDPOINT>",
        "MANDATE_AUCTION_ADDRESS": "<AUCTION_CONTRACT_ADDRESS>",
        "MANDATE_REGISTRY_ADDRESS": "<REGISTRY_CONTRACT_ADDRESS>",
        "MANDATE_AGENT_ID": "<REGISTERED_AGENT_ID>",
        "MANDATE_SESSION_KEY": "<SESSION_PRIVATE_KEY — SECRET, NEVER COMMIT>",
        "MANDATE_CIRCUIT_PATH": "<PATH_TO_circuits/policy_check>",
        "MANDATE_WHITELIST_ROOT": "<WHITELIST_MERKLE_ROOT>",
        "MANDATE_MAX_ORDER_NOTIONAL": "1000000",
        "MANDATE_MAX_POSITION": "<MAX_POSITION>",
        "MANDATE_MAX_DAILY_LOSS": "<MAX_DAILY_LOSS>",
        "MANDATE_POLICY_SALT": "<POLICY_SALT — SECRET, NEVER COMMIT>"
      }
    }
  }
}

This is more environment variables than the product overview shows

The product-overview PDF's redacted example lists seven MANDATE_* variables. The actual server (packages/mandate-mcp/src/config.ts) requires five more — MANDATE_CIRCUIT_PATH, MANDATE_WHITELIST_ROOT, MANDATE_MAX_ORDER_NOTIONAL, MANDATE_MAX_POSITION, and MANDATE_MAX_DAILY_LOSS — because PolicyParamsis a required field of the SDK's config and the server has no way to recover that plaintext from the chain (only its commitment is on-chain). This page follows the repository implementation.

Environment variables

VariableRequiredDescription
MANDATE_AGENT_IDYesThis agent's identity — Poseidon2(session pk, salt), as a 0x bytes32 or decimal integer.
MANDATE_SESSION_KEYYesThe session private key used to sign submitOrder transactions. Secret — never commit or log.
MANDATE_AUCTION_ADDRESSYesDeployed BatchAuction contract address.
MANDATE_REGISTRY_ADDRESSYesDeployed MandateRegistry contract address.
MANDATE_CIRCUIT_PATHYesFilesystem path to the policy_check Noir circuit project (containing Nargo.toml), used for proving.
MANDATE_WHITELIST_ROOTYesPlaintext mandate parameter — root of the approved-markets Merkle tree. Part of the policy commitment opening.
MANDATE_MAX_ORDER_NOTIONALYesPlaintext mandate parameter — maximum notional (quantity × limit price) per order.
MANDATE_MAX_POSITIONYesPlaintext mandate parameter — maximum post-fill absolute position.
MANDATE_MAX_DAILY_LOSSYesPlaintext mandate parameter — maximum realized daily loss.
MANDATE_POLICY_SALTYesPlaintext mandate parameter — random salt binding the policy commitment. Secret — never commit or log.
MANDATE_RPC_URLNoJSON-RPC endpoint for the target chain. Defaults to http://127.0.0.1:8545 (local Anvil).
MANDATE_SEQUENCER_URLNoSequencer HTTP base URL. Defaults to http://127.0.0.1:8787.
MANDATE_NARGO_PATHNoOverride path to the nargo binary. Defaults to $NARGO_BIN or "nargo" on PATH.
MANDATE_BB_PATHNoOverride path to the bb (Barretenberg) binary. Defaults to $BB_BIN or "bb" on PATH.
MANDATE_MARKET_MAPNoOptional JSON object mapping market symbols (e.g. "ETH/USDC") to numeric circuit market ids, merged over the built-in defaults.

Available tools

The server exposes exactly three tools — this is a deliberate design decision, not an incomplete API. There is no mandate_preview_order or dry-run tool: the SDK exposes no such method, so none was invented for the server either.

Implemented

mandate_get_epoch

Read-only

Implemented

mandate_get_portfolio

Read-only

MVP

mandate_submit_order

Execution (proof-gated)

Tool schemas

mandate_get_epoch

Reads the current MANDATE batch-auction epoch, phase (commit/reveal), and circuit-breaker bit directly from the auction contract. Read-only; does not submit anything.

Input schema

{}

Example response

{
  "epoch": "396",
  "phase": "commit",
  "breaker": false
}

mandate_get_portfolio

Reads this agent's current anchored portfolio state: position, daily PnL, and the Merkle root anchored on-chain for this agent, cross-checked against the on-chain state root. Read-only; does not submit anything.

Input schema

{}

Example response

{
  "agentId": "0x2c4fd536018985d83870a4ed4a18dc1a4ded2c3343f7c3da46af50a92846b420",
  "position": "0",
  "dailyPnl": "0",
  "stateRoot": "0x...",
  "onchainStateRoot": "0x...",
  "stateRootMatches": true,
  "whitelistIndex": 0
}

mandate_submit_order

Generates a real zero-knowledge compliance proof (Noir/UltraHonk) for this order and submits the proof-gated commitment through MANDATE. This is the only path that can put an order in the batch auction — there is no separate execution or signing tool. A mandate-violating order cannot be proven: it is rejected here, before it ever reaches the chain, with the circuit's rejection reason. This performs real proving (nargo execute + bb prove) and, on success, a real on-chain transaction — it is not a preview or simulation.

Input schema

{
  market: string,      // e.g. "ETH/USDC", "ETH", or a numeric circuit market id
  side: "buy" | "sell",
  amount: string,      // positive whole-number string, no sign, no decimals
  limitPrice: string,  // positive whole-number string, no sign, no decimals
}

Example response

// compliant order
{
  "status": "submitted",
  "submitted": true,
  "orderCommitment": "0x12a254be...5e74d89",
  "epoch": "396",
  "txHash": "0xdee28569...9a60bc01"
}

// non-compliant order
{
  "status": "rejected",
  "submitted": false,
  "reason": "order notional exceeds mandate maximum"
}

Example interaction

An end-to-end walkthrough, exactly as documented in the repository README:

StepPrompt / actionExpected result
1“What is the current epoch?” → mandate_get_epochEpoch: 396, Phase: commit, Circuit breaker: false
2“Show me the portfolio.” → mandate_get_portfolioPosition: 0, PnL: 0, State root match: true
3“Buy 250 units at 3,500.” → mandate_submit_orderProof generated, order submitted, tx hash returned
4“Buy 10,000 units at 3,500.” → mandate_submit_order“order notional exceeds mandate maximum” — rejected, nothing submitted

Security considerations

Limiting the tool surface area is itself a security property: an agent cannot do something the MCP server does not expose, regardless of what it is instructed to attempt. All chain/sequencer/circuit/key material is sourced only from server-side environment variables — never from MCP tool arguments — so a client can request an order but can never redirect the server at a different RPC endpoint, sequencer, signer, or circuit.

Never combine mandate_submit_order with unrestricted execution tools

Do not give the same agent unrestricted wallet, swap, transfer, or trading tools alongside mandate_submit_order. Proof-gating only works if it is the only execution path available to the agent. Session keys and policy salts are secrets — never commit them to version control, chat logs, or shared documents.