Policy Management MCP
Officialby Zetrix-Chain
README.md
# Policy Management MCP
An MCP server that lets the owner of a Zetrix agentic wallet manage that wallet's **spending policy** from their own agent:
read it, check a draft, and write, update or remove it. It carries none of the wallet's payment, transfer, identity or
credential tools.
Status: 0.1.0, not yet published to npm.
## Tools
| Tool | What it does |
|---|---|
| `policy_status` | Which wallet this server manages, on which network, and how owner approval works on this client |
| `account_details` | The wallet's address, DID, public key, activation and ZTX/JMYR balances: what is safe to share. Never the password |
| `create_holder_account` | Creates a wallet account when the user has none. Never a second one. Free |
| `backup_account` | Saves a copy of the account file, password included, to the wallet's `backups` folder for the user to move to safe storage. Returns the path, never the password |
| `get_policy_template_schema` | The policy templates on offer and the attributes each declares. Free |
| `get_my_policy` | The wallet's deployed policies. Free |
| `write_policy` | Deploys a policy. Pays a fee (JMYR) or network gas (ZTX) |
| `update_policy` | Replaces a policy's rules. Pays a fee or gas |
| `remove_policy` | Removes a policy, lifting every limit it set. Free |
| `check_policy_write` | Finishes a write that has already been paid for. Free |
| `policy_preflight` | Checks a draft, and says in plain words what it would mean. Free |
The full text each agent reads is in [docs/TOOLS.md](docs/TOOLS.md). `check_policy_decision` is not offered: a permitted answer
reserves the owner's budget for 15 minutes, and a server that manages the policy never spends.
## Owner approval
A change made through `write_policy`, `update_policy` or `remove_policy` with `confirm: true` is classified before anything is
paid:
- **Only tightens** (lowers a cap, or adds a cap other than `perTransactionMax`, with everything else unchanged): goes through.
- **Anything else** (a new policy, a removal, adding `perTransactionMax`, raising or dropping a cap, changing a window, scope,
allow-list or the validity window, or collecting a write that was already paid for): shown to the owner in an approval prompt
(MCP elicitation), which the MCP client is meant to show to the person. Declined, or a client that cannot show prompts, means
`state: "refused"` with `ownerApproval` set and nothing paid or changed.
Adding `perTransactionMax` needs approval however low it is: it is what makes a policy govern its asset, and a governed asset
loses the wallet's default per-payment cap. An approval covers one exact change (its values, template and the policy version it
was compared against) and is used up by the call it was given for. Everything taken from the agent's request is shown in the
prompt on lines of its own, quoted, with line breaks and control characters removed, below a fixed warning.
**This is not a security boundary yet.**
- The wallet's HSM password, which authorises a policy write, is in this server's environment or the wallet's account file, so
an agent that can read either, or that also has the wallet MCP's own write tools, can go around this gate.
- The prompt is only as good as the client: one set to accept prompts automatically, or an agent loop that answers them itself,
defeats it. It has been checked with the MCP SDK's own client, not yet with Claude Code, Claude Desktop or OpenClaw.
Real owner control needs a server-side check in ms-zetrix and Wallet BE.
## Setup
**Not on npm yet.** Build it from a checkout of this repo (Node 18 or later):
```
npm ci
npm run build
```
This makes `packages/policy-management-mcp/dist/server-bundle.cjs`, which is both the MCP server and the command-line tool. The
commands below are run from the checkout. Once the package is on npm, `npx policy-management-mcp <command>` will do the same
as `node packages/policy-management-mcp/dist/server-bundle.cjs <command>`.
The server uses the wallet account saved for the network in `~/.agentic-wallet-mcp/account.<network>.json`, the same file the
Zetrix agentic wallet uses, or `ZETRIX_ADDRESS` and `HSM_PASSWORD` if they are set. A user with no account gets one in either
of two ways:
- **From the agent:** start the server anyway. It starts without an account, and `create_holder_account` makes one and switches
to it at once.
- **From a terminal:** `node packages/policy-management-mcp/dist/server-bundle.cjs create-account` (add
`--network zetrix:mainnet` for mainnet).
Either way the password is generated (192 random bits): nobody chooses, types or sees it, and it is saved in that file. A
second account is never created for a network. Then:
1. **Back up the account.** The password is the only thing that can sign for the wallet, and it cannot be reset. Ask the agent
to run `backup_account`, or run `node packages/policy-management-mcp/dist/server-bundle.cjs backup-account`: either saves
a copy of the account file (password included) to `~/.agentic-wallet-mcp/backups/`, for you to move to a password manager
or an offline drive. To restore, copy it back to `~/.agentic-wallet-mcp/account.<network>.json`. To see the password
itself, run `node packages/policy-management-mcp/dist/server-bundle.cjs export-credentials` in a terminal (it refuses to
run piped or redirected; no tool returns it).
2. **Fund the address** (`account_details` shows it): ZTX for network gas, JMYR for the sponsored policy write fee.
```json
{
"mcpServers": {
"zetrix-policy": {
"command": "node",
"args": ["/path/to/policy-management-mcp/packages/policy-management-mcp/dist/server-bundle.cjs"],
"env": { "ZETRIX_NETWORK": "zetrix:testnet" }
}
}
}
```
| Variable | Default | |
|---|---|---|
| `ZETRIX_NETWORK` | `zetrix:testnet` | `zetrix:testnet` or `zetrix:mainnet` |
| `ZETRIX_WALLET_STATE_DIR` | `~/.agentic-wallet-mcp` | Shared with the wallet, so both see the same account, receipts and in-flight writes |
| `ZETRIX_ADDRESS`, `HSM_PASSWORD` | from the account file | Both, or neither |
| `MAX_PAYMENT_AMOUNT` | 1 JMYR | Cap on the sponsored write fee |
| `GAS_PREFERENCE` | `sponsored` | `sponsored` or `self` |
| `WALLET_BE_URL`, `ZETRIX_NODE_HOST`, `ZETRIX_NODE_PORT`, `ZETRIX_NODE_SECURE`, `POLICY_REGISTRY_ADDRESS`, `POLICY_TEMPLATE_ADDRESS`, `POLICY_TEMPLATE_PUBLISHER`, `POLICY_WRITE_URL`, `POLICY_CAP_BYPASS` | per network | As in the agentic wallet |
If it cannot start (an unreadable account file, an older `account.json` it cannot place, `ZETRIX_ADDRESS` without
`HSM_PASSWORD`), it stays up and every tool says why. It does not offer to create an account in those cases, because what is
there may already be the user's wallet.
## Development
```
npm ci
npm test # both packages
npm run typecheck # sources
npm run build # packages/policy-management-mcp/dist/server-bundle.cjs
npm run docs:tools # regenerate docs/TOOLS.md after changing a tool
```
| Package | |
|---|---|
| `packages/policy-core` | The policy tools, copied from the agentic wallet MCP 0.19.0 with their tests. See [its PROVENANCE.md](packages/policy-core/PROVENANCE.md) |
| `packages/policy-management-mcp` | The server: startup, owner approval, tool list |
`npm run typecheck:tests` reports 22 errors in test files copied unchanged from the wallet, where the same errors exist; the
tests themselves pass.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues