# Rightshold MCP Guard

A local proxy between your agent and any MCP server: it pins tool definitions, enforces your policy, catches payment demands and gives every call a tamper-evident receipt. One file, no dependencies beyond Node 18. Free.

## Pins every tool definition

The first time the guard sees a server's tools it pins each one: name, description, input schema and annotations. If a definition later changes (the classic rug pull: a harmless tool quietly rewritten to exfiltrate), or a tool appears that was never announced, the guard withholds it from your agent and refuses its calls until you review it and start once with --approve.

## Enforces your policy

A small JSON file: tools to allow and deny (with * wildcards), what to do when a definition changes, what to do when a server asks for payment, and a calls-per-minute ceiling. Refusals reach your agent as ordinary tool errors that say why.

## Catches payment demands

When a tool answers with HTTP 402, a JSON-RPC 402 error or x402 payment requirements, the guard records the demand (amount, asset, network, recipient) and either passes it on to your agent or, under "payments": "block", refuses it. The guard never pays, holds no wallet and touches no money.

## Gives every call a receipt

Each call, refusal, definition change and payment demand becomes a receipt in your Rightshold record: hash-chained, timestamped and committed to the public ledger, so nobody, including us, can quietly edit it later.

## Install

```
curl -fsSL --create-dirs -o ~/.rightshold/mcp-guard.mjs https://www.rightshold.com/cli/mcp-guard.mjs
curl -fsSL https://www.rightshold.com/cli/mcp-guard.sha256
shasum -a 256 ~/.rightshold/mcp-guard.mjs
node ~/.rightshold/mcp-guard.mjs --help
```

Version 1.0.0, SHA-256 7e16af57622c5b1313f557883b41810083376cd51a6ce3f007678b14f2b9fc0f. The two hashes must match before you run it.

## Put it in front of a server

Wrap the command your client already runs. The guard starts the server itself and passes everything through.

### Claude Desktop (claude_desktop_config.json)

```
{
  "mcpServers": {
    "files": {
      "command": "node",
      "args": ["/Users/you/.rightshold/mcp-guard.mjs", "--name", "files", "--", "npx", "-y", "@modelcontextprotocol/server-filesystem", "/Users/you/Documents"],
      "env": { "RIGHTSHOLD_API_KEY": "<your key>" }
    }
  }
}
```

### Claude Code (terminal)

```
claude mcp add files -e RIGHTSHOLD_API_KEY=<your key> -- node /Users/you/.rightshold/mcp-guard.mjs --name files -- npx -y @modelcontextprotocol/server-filesystem /Users/you/Documents
```

### Cursor (~/.cursor/mcp.json)

```
{
  "mcpServers": {
    "files": {
      "command": "node",
      "args": ["/Users/you/.rightshold/mcp-guard.mjs", "--name", "files", "--", "npx", "-y", "@modelcontextprotocol/server-filesystem", "/Users/you/Documents"],
      "env": { "RIGHTSHOLD_API_KEY": "<your key>" }
    }
  }
}
```

### VS Code (.vscode/mcp.json)

```
{
  "servers": {
    "files": {
      "type": "stdio",
      "command": "node",
      "args": ["/Users/you/.rightshold/mcp-guard.mjs", "--name", "files", "--", "npx", "-y", "@modelcontextprotocol/server-filesystem", "/Users/you/Documents"],
      "env": { "RIGHTSHOLD_API_KEY": "<your key>" }
    }
  }
}
```

### A remote MCP server (any client)

```
"command": "node",
"args": ["/Users/you/.rightshold/mcp-guard.mjs", "--name", "remote", "--url", "<server-url>/mcp", "--header", "Authorization: Bearer <that server's token>"]
```

No Rightshold key yet? Add --accept-terms once: the first receipt opens a free account (terms at https://www.rightshold.com/terms) and the guard keeps its key in its state directory. Or add --no-record to pin and enforce locally and send nothing.

## Policy

```json
{
  "allow": ["read_*", "search_*", "premium_search"],
  "deny": ["delete_*", "send_*"],
  "on_change": "block",
  "payments": "block",
  "max_calls_per_minute": 60
}
```

Pass it with --policy policy.json. Without a policy everything is allowed except changed or unannounced tools. Deny wins over allow.

## What leaves your machine

Per receipt, only:

- the action type (mcp.tool_call, mcp.call_refused, mcp.definitions_changed, mcp.payment_demanded or mcp.payment_refused) and its outcome
- a one-line summary: the label you gave the server and the tool's name
- the SHA-256 of the full local record, and an event id derived from it

What stays in the local log (~/.rightshold/mcp-guard/log/):

- the arguments your agent sent and the results it got back
- payment amounts, assets and recipients
- the server's tool descriptions and schemas
- your policy and your pins

Each log line holds the full record and its SHA-256. To prove what a call contained, hand someone that one record: they hash it (canonical JSON, keys sorted, no whitespace) and compare the hash with the receipt.

## What it does not prove

A receipt proves what was recorded and when, and that it has not changed since. It does not prove that a tool did what it said. The guard sees only the traffic that passes through it, and pinning is trust on first use: review a server's tools the first time you run it.
