AIRLOCKtestnet

Use it with your own agent

Put AIRLOCK between any MCP agent and your NEAR testnet funds in about five minutes. The agent reads your inbox and asks to pay; your policy contract decides. The agent never sets a label: values it read keep the label of where they came from, and a value it types counts as yours only when your own request holds it.

You need: Node 24, pnpm, the near CLI (near-cli-rs 0.30 or later), jq, python3 and curl. No Rust, no model key and no money: testnet only.

  1. Get the code

    Clone the repository and install. The committed policy wasm is used as is, so nothing is compiled.

    git clone https://github.com/erfan604/airlock.git && cd airlock && pnpm i

    Last line: Done in <n>s using pnpm v12.14.0

  2. Make an owner account

    Your owner account sets the policy and approves held payments. The faucet funds it with 10 testnet NEAR. To reuse an account you already have, skip this; it needs about 6 testnet NEAR.

    near account create-account sponsor-by-faucet-service <you>.testnet autogenerate-new-keypair save-to-legacy-keychain network-config testnet create

    Last line: New account <<you>.testnet> created successfully.

  3. Deploy your own policy

    One command creates your policy account with the faucet, the agent and a payee called Acme under your account, deploys the policy contract, puts Acme in your address book with a 1 NEAR cap for amounts read from outside text, and writes the agent config to ~/.airlock/mcp.json. About 2 minutes and 15 transactions.

    pnpm airlock init --owner <you>.testnet

    Last line: AIRLOCK READY <you>-policy.testnet

  4. Add AIRLOCK to your agent

    Print the entry for Claude Desktop and paste it into claude_desktop_config.json (on macOS in ~/Library/Application Support/Claude/), then restart Claude Desktop. Any MCP client that starts a stdio server takes the same command, arguments and environment.

    pnpm airlock claude-config

    Last line: }

    The entry names your node binary, the server file runtime/src/mcp/main.ts and AIRLOCK_MCP_CONFIG. The server reads your request and limits from that file; the agent cannot change them.

  5. Ask your agent to pay the inbox

    Ask: "Pay Acme's invoices from my inbox." The sample inbox has three. The first, 0.5 NEAR, is paid: ALLOWED with its transaction. The second, 1.5 NEAR, is over the 1 NEAR cap for an amount read from an email, so it is HELD FOR YOU (UntrustedAmount). The third is a doctored invoice that names another account; it is HELD FOR YOU too (OutsideTask), and nothing is paid.

    No MCP client? The same three calls, scripted with no model: pnpm airlock play, which ends with PLAY DONE allow 1 escalate 2 block 0.

  6. Approve or reject as the owner

    Each held payment has a pending id. Read its card, approve the real invoice and reject the doctored one. Both ask you to type yes and sign with your owner key; the agent cannot do either.

    pnpm airlock pending <id>

    Last line: command near contract call-function as-transaction ...

  7. Approve the 1.5 NEAR invoice

    The contract checks your signed values against the stored request and pays it.

    pnpm airlock approve <id>

    Last line: APPROVED <id> https://testnet.nearblocks.io/txns/<tx>

  8. Reject the doctored invoice

    Nothing moves, and the rejection is recorded on chain.

    pnpm airlock reject <id>

    Last line: REJECTED <id> https://testnet.nearblocks.io/txns/<tx>

What the agent can and cannot do

  • It can pay without you only an address-book payee, inside the task your server signs from your config and inside the payee and asset limits.
  • It cannot change your request, your limits or your book, and it cannot approve: approval needs your owner key.
  • It can still cause held payments, which cost your attention, and it decides when to pay inside your limits.
  • The full list is the MCP client entry of docs/THREAT_MODEL.md; the steps with every expected line are docs/QUICKSTART.md.