Skip to main content
Policy gates are declarative rules enforced by the MPC cosigner before any transaction is signed. They control what a signed transaction is allowed to do - which destination addresses are permitted, the per-transaction value cap, and signing rate limits. Policies work alongside band filtering:
  • Bands control which tools the agent can see (MCP layer)
  • Policies control what the visible tools can do (signing layer)

How Policies Work

  1. You register a policy on the cosigner with constraints (destination allowlist, per-tx value cap, rate limit)
  2. You create an agent API key bound to that wallet
  3. When the agent requests a signature, the cosigner evaluates the policy before producing its share
  4. If the policy denies the request, signing fails with a flow error containing the denial reason and a requiredAction to fix it
Policy constraints are evaluated together - the first denial short-circuits. Policies are enforced by the MPC cosigner and cannot be overridden by the MCP server or LLM.

Available Constraints

ConstraintWhat It Controls
allowlistList of EIP-55 checksummed destination addresses the cosigner will permit
maxValueEthMaximum native-value per transaction, as a decimal ETH string (converted to wei before transmission)
rateLimitPerHourMaximum number of signatures per rolling hour (integer, 1-1000)
You must supply at least one constraint when registering a policy. Omitting all three raises MISSING_POLICY_GUARDRAIL.

Creating a Policy

Use the create_custom_policy tool in owner mode (requires MCP_BANDS including sign, and the server started with MPC_AUTH_MODE=owner):
Register a policy on wallet "treasury" that caps each transfer at 1 ETH and permits at most 10 signatures per hour.
The agent calls:
{
  "name": "create_custom_policy",
  "arguments": {
    "walletName": "treasury",
    "maxValueEth": "1.0",
    "rateLimitPerHour": 10
  }
}
The cosigner registers the policy and returns a policyId along with the walletName it applies to and the appliedAt timestamp.
// Example create_custom_policy response
{
  "walletName": "treasury",
  "policyId": "2f6d3a1e-94c7-4c8e-9c5a-7b0e1f2a3b4c",
  "appliedAt": "2027-01-01T00:00:00Z",
  "maxValueWei": "1000000000000000000",
  "maxValueEth": "1.0",
  "rateLimit": { "count": 10, "periodSeconds": 3600 }
}

Issuing an Agent Key for the Wallet

Use create_agent_api_key to issue a token bound to the wallet the policy was registered on. The policy is enforced by the cosigner for every signature the key produces.
Create an agent API key labeled "trading-bot" for wallet "treasury", expiring in 30 days.
The agent calls:
{
  "name": "create_agent_api_key",
  "arguments": {
    "walletName": "treasury",
    "label": "trading-bot",
    "expiresIn": "30d"
  }
}
The cosigner stores only the SHA-256 hash of the token. The raw token is written once to a local file (mode 0600, default ~/.walletsuite/mpc-agent-token) and never returned in chat. Restart the MCP server in agent mode with MPC_AGENT_TOKEN sourced from that file.

What Happens When a Policy Denies

When a transaction violates a registered constraint, the cosigner refuses to produce its share and the agent receives a structured flow error. The message carries the denial reason and the requiredAction tells the agent how to proceed - for example, that the destination is outside the allowlist, that the value exceeds the per-transaction cap, or that the rate limit is exhausted. See Structured Errors for the full error taxonomy.

Owner Mode

Policy registration and agent-key issuance are owner-mode operations - the server must be started with MPC_AUTH_MODE=owner. Calling create_custom_policy or create_agent_api_key without owner mode raises MPC_OWNER_MODE_REQUIRED. To change what a denied agent can do, register an updated policy on the wallet from owner mode. Because signing is MPC 2-of-2, neither WalletSuite nor any other party can sign without the customer share, so the customer retains full control over what gets signed.

Bands vs Policies

Bands and policies are orthogonal - they sit on different axes and address different threats.
ControlWhat it controlsWhere it runsApplies to
Band FilteringWhich tools exist in the MCP schemaMCP Server (resolved at startup)MCP only
Policy GatesWhat signed transactions can doMPC cosigner (per-request)All surfaces (MCP, SDK, REST)
A complete MCP security setup uses both:
  1. Set MCP_BANDS to the minimum required level
  2. Register a policy with the constraints the agent should be held to
  3. Issue an agent key for that wallet
  4. The agent can only see the tools it needs AND can only sign what the policy allows

Practical Example

Scenario: You want an agent that can prepare and sign transfers from the treasury wallet, capped at 1 ETH per transaction and 10 signatures per hour. Setup:
  1. From owner mode, register a policy on wallet treasury:
    • maxValueEth: "1.0"
    • rateLimitPerHour: 10
  2. Issue an agent key for the treasury wallet
  3. Configure the MCP server:
    • MCP_BANDS=full
    • Launch in agent mode with MPC_AGENT_TOKEN sourced from the token file; the registered policy is enforced by the WalletSuite cosigner
Result: The agent can prepare and sign transactions from treasury. If it tries to send more than 1 ETH in a single transaction, or exceeds 10 signatures in an hour, the cosigner denies the signature. See Self-Hosting over HTTP to run the MCP server on your own infrastructure, and the Security Model for how signing works.