Everything you need to install the proxy, configure guardrails, and connect to estoppl cloud.
# npm (recommended)
npm install -g estoppl
# Homebrew (macOS / Linux)
brew tap estoppl/tap && brew install estoppl
# Cargo (Rust)
cargo install estoppl
# Or try without installing
npx estoppl# Initialize config and signing keys
estoppl init --agent-id my-agent
# Auto-wrap Claude Desktop or Cursor
estoppl wrap
# Restart your MCP client, then live-stream tool calls
estoppl tailestoppl wrap discovers your MCP client configs and rewrites them to route tool calls through the proxy. The proxy runs as a subprocess — your MCP client starts it automatically. Restart your client after wrapping for changes to take effect.
Sign up at app.estoppl.ai and grab your API key during onboarding. Then uncomment the [ledger] section in estoppl.toml:
[ledger]
cloud_api_key = "sk_your_key"
org_id = "your_org_id"Cloud sync starts automatically. Events appear in your dashboard within seconds. The remote kill switch and human review also activate when org_id is set.
| Command | Description |
|---|---|
estoppl init | Initialize config, keypair, and database |
estoppl start | Start stdio proxy (wraps a local MCP server) |
estoppl start-http | Start HTTP proxy (reverse proxy for remote MCP) |
estoppl wrap | Auto-wrap MCP client configs (Claude Desktop, Cursor). Use --client claude or --client cursor to wrap a specific client. |
estoppl unwrap | Restore original MCP client configs |
estoppl audit | View audit log with filters (--tool, --decision, --since) |
estoppl audit --verify | Verify hash chain integrity |
estoppl tail | Live-stream tool calls as they happen |
estoppl stats | Tool call volume, latency, per-tool breakdown |
estoppl dashboard | Local web dashboard at http://127.0.0.1:4200 |
estoppl bench | Measure proxy overhead (p50/p95/p99 latency) |
estoppl report | Generate HTML activity report |
estoppl init generates estoppl.toml in the current directory:
[agent]
id = "my-agent"
version = "0.1.0"
[rules]
block_tools = ["delete_*", "drop_*"]
# human_review_tools = ["wire_transfer"]
# max_amount_usd = 50000.0
# rate_limit_per_minute = 30
# Connect to estoppl cloud (https://app.estoppl.ai)
[ledger]
# cloud_api_key = "sk_your_key"
# org_id = "your_org_id"| Rule | What it does | Example |
|---|---|---|
| Allow list | Only listed tools are permitted | allow_tools = ["read.*"] |
| Block list | Always rejected (overrides allow list) | block_tools = ["rm_rf.*"] |
| Human review | Pauses until a human approves | human_review_tools = ["wire_transfer"] |
| Amount threshold | Blocks calls exceeding a USD limit | max_amount_usd = 50000.0 |
| Rate limiting | Blocks after N calls per minute | rate_limit_per_minute = 30 |
When cloud_api_key is set in estoppl.toml, the proxy automatically syncs events to the cloud. The endpoint defaults to https://api.estoppl.ai/v1/events.
Events always persist locally first. Cloud sync is best-effort with exponential backoff, gap detection, and automatic reconciliation.
When org_id is also set, two additional features activate:
Base URL: https://api.estoppl.ai. All requests require Authorization: Bearer <token>.
/healthNo authReturns {"status": "ok"} if the server and database are reachable.
/v1/eventsAPI key (scope: sync)Ingest a batch of signed events from a proxy. Verifies chain integrity (sequence gaps, batch hash, prev_hash continuity).
Returns {"accepted": N} on success, or 409 with {"gap_from_sequence": N} if a gap is detected.
/v1/policy/{orgID}API keyReturns the current policy for the org. Proxies poll this every 5 seconds and hot-reload rules when the version changes.
/v1/verify/{attestationID}API key (scope: verify)Verify that a tool call was governance-checked by estoppl. Returns agent ID, org, tool name, decision, and chain integrity status. Used by upstream MCP servers to verify the X-Estoppl-Attestation header.
/v1/reviewAPI keySubmit a tool call for human review. The proxy calls this when a HUMAN_REQUIRED decision is made. Returns review ID and expiry.
/v1/review/{eventID}API keyPoll the status of a pending review. Status: pending, approved, denied, expired.
/v1/review-action?token=...&action=approveSigned token (no login)One-click approve or deny a review via a signed link. Sent in Slack and webhook notifications. Single-use.
These endpoints power the web dashboard at app.estoppl.ai. Auth: Clerk JWT or API key.
/v1/dashboard/eventsClerk JWT or API keyList events with optional filters: limit, tool, decision, agent, since.
/v1/dashboard/statsClerk JWT or API keySummary stats: total events, allowed/blocked/human review counts, unique tools, unique agents, time range, and top_tools — top 10 tools by call count with per-tool decision breakdown.
/v1/dashboard/policyClerk JWT or API keyGet the current policy with version number.
/v1/dashboard/policyClerk JWT or API keyUpdate policy rules. Accepts any combination of block_tools, allow_tools, human_review_tools, max_amount_usd, custom_rules, agent_rules. Proxies pick up changes within 5 seconds.
/v1/dashboard/exportClerk JWT or API keyDownload a signed compliance evidence pack. Optional from and to date filters. Verify offline with estoppl audit --verify-export.
/v1/dashboard/receipt/{eventID}Clerk JWT or API keyDownload a cryptographic receipt for a single event. Verify offline with estoppl audit --verify-receipt.
/v1/dashboard/reviewsClerk JWT or API keyList reviews. Optional status=pending filter.
/v1/dashboard/review/{eventID}Clerk JWT or API keyApprove or deny a review. Body: {"action": "approved", "reason": "Client confirmed details"} or {"action": "denied", "reason": "Suspicious amount"}. The reason field is recommended for compliance audit trails.
/v1/dashboard/api-keysClerk JWT or API keyList API keys for the org.
/v1/dashboard/api-keysClerk JWT or API keyCreate an API key. Scopes: sync, verify, admin.
/v1/dashboard/api-keys/{keyID}Clerk JWT or API keyRevoke an API key.
/v1/dashboard/notificationsClerk JWT or API keyGet notification settings (email, Slack webhook URL, custom webhook).
/v1/dashboard/notificationsClerk JWT or API keyUpdate notification settings. Email, Slack, and webhook are fully supported.
Define arbitrary conditions on tool arguments:
{
"custom_rules": [
{
"name": "Large transfers need approval",
"tool": "wire_transfer",
"condition": {"field": "amount", "operator": "gt", "value": 10000},
"action": "human_review"
}
]
}Tool patterns: wire_transfer (exact), wire_* (prefix), * (all tools)
Operators: gt, lt, gte, lte, eq, neq, contains, not_contains
Actions: block, human_review, allow
Nested fields: Use dot notation — payment.total extracts from {"payment": {"total": 5000}}
Override org-wide rules for specific agents. Fields not specified fall back to org-wide defaults:
{
"agent_rules": {
"analytics-bot": {
"allow_tools": ["read_*", "get_*"],
"block_tools": ["wire_transfer"]
}
}
}Configure in estoppl.toml (proxy-side):
[rules]
redact_fields = ["ssn", "credit_card", "password"]Redacted fields are replaced with [REDACTED] before syncing to the cloud.
When a tool call requires human review, estoppl sends notifications to all configured channels with one-click approve/deny links:
Configure via Settings in the dashboard or the notifications API endpoint.
All API errors return JSON: {"error": "description"}
| Status | Meaning |
|---|---|
| 400 | Bad request (invalid JSON, missing fields) |
| 401 | Unauthorized (missing or invalid token) |
| 403 | Forbidden (wrong org) |
| 404 | Not found |
| 409 | Conflict (chain gap detected) |
| 500 | Internal server error |
Questions? Email tina@estoppl.ai or book a call.