estoppl
See what your AI agent is doing. Stop it when it goes wrong.
estoppl is a transparent proxy for MCP (Model Context Protocol) that gives you full visibility into every tool call your agent makes — and lets you set guardrails so it can't do things it shouldn't.
stdio mode:
┌──────────────┐ ┌─────────────┐ ┌──────────────┐
│ Agent Host │ ── stdin ──────▶ │ estoppl │ ── stdin ──────▶ │ MCP Server │
│ (Claude, │ ◀── stdout ───── │ │ ◀── stdout ───── │ (local) │
│ LangChain) │ │ intercept │ └──────────────┘
└──────────────┘ │ guardrails │
│ log + sign │
HTTP mode: └──────┬──────┘
┌──────────────┐ ┌──────┴──────┐ ┌──────────────┐
│ MCP Client │ ── POST/SSE ──▶ │ estoppl │ ── POST/SSE ──▶ │ MCP Server │
│ │ ◀── JSON/SSE ── │ :4100 │ ◀── JSON/SSE ── │ (remote) │
└──────────────┘ └──────┬──────┘ └──────────────┘
│
┌──────▼──────┐
│ audit log │
│ (signed, │
│ chained) │
└─────────────┘
Why
AI agents call tools autonomously. Without visibility, you don't know what your agent did, how many times it called an API, or whether it tried something it shouldn't have. You find out when something breaks — or when you get the bill.
Estoppl fixes this:
- Visibility — every tool call is logged with timestamps, inputs (hashed), outputs (hashed), and latency
- Guardrails — block specific tools, set amount thresholds, flag sensitive operations for human review
- Tamper-evident audit trail — signed, hash-chained events that prove what happened and when
One config line. Zero code changes. Sub-millisecond overhead.
Install
Homebrew (macOS and Linux):
npm (any platform with Node.js):
# or install globally
Cargo (Rust toolchain):
Binary download (no dependencies):
# macOS Apple Silicon
|
# macOS Intel
|
# Linux x86_64
|
# Linux ARM64
|
Quick start
# Initialize config, keypair, and database
# Start the proxy — stdio mode (wraps a local MCP server process)
# Start the proxy — HTTP mode (reverse proxy for remote MCP servers)
# See what your agent has been doing
# Generate an HTML report
MCP client configuration
stdio mode (local MCP servers)
Drop the proxy into your MCP client config — one change, zero code modifications:
HTTP mode (remote MCP servers)
For MCP servers running over HTTP (Streamable HTTP transport), run the proxy as a reverse proxy:
# Start the proxy (listens on 127.0.0.1:4100 by default)
# Point your MCP client at the proxy instead of the upstream server
The HTTP proxy supports the full MCP Streamable HTTP transport: POST (JSON-RPC requests, including batches), GET (SSE streams for server-initiated messages), and DELETE (session termination). Session IDs and auth headers are forwarded transparently.
Your agent doesn't know estoppl is there. Every tool call passes through transparently.
Configuration
estoppl init generates an estoppl.toml:
[]
= "my-agent"
= "0.1.0"
[]
# Block these tools entirely — they never reach the MCP server
= []
# Flag these for human review (call goes through, logged as HUMAN_REQUIRED)
= ["wire_transfer", "execute_trade"]
# Block any tool call where the amount exceeds this value
= 50000.0
# Where to find the amount in tool arguments (supports dot notation)
= "amount"
# Max calls per tool per minute (0 = unlimited). Prevents runaway agents.
# rate_limit_per_minute = 30
# Per-tool rate limit overrides
# [rules.rate_limit_tools]
# "stripe.create_payment" = 5
# "execute_trade" = 10
[]
= ".estoppl/events.db"
# Cloud sync — stream signed events to the Estoppl cloud ledger
# cloud_endpoint = "https://api.estoppl.com/v1/events"
# cloud_api_key = "sk_your_key"
Guardrails
Block tools — tool calls matching these names are rejected before reaching the upstream server. The agent gets a JSON-RPC error. Supports wildcards: "stripe.*" blocks all Stripe tools.
Human review — tool calls go through but are flagged as HUMAN_REQUIRED in the audit log. Use this for sensitive operations you want visibility into.
Amount thresholds — tool calls with an amount field exceeding the limit are blocked automatically. Catches runaway agents before they do damage.
Rate limiting — cap how many times any tool (or a specific tool) can be called per minute. If an agent enters a loop calling Stripe 200 times, it gets cut off after the limit. Configure globally with rate_limit_per_minute or per-tool with rate_limit_tools.
Audit log
Every tool call produces a signed event:
EVENT TOOL DECISION TIMESTAMP LATENCY
a1b2c3d4 stripe.create_payment ALLOW 2026-03-05 14:23:01 2ms
e5f6g7h8 wire_transfer HUMAN_REQ 2026-03-05 14:23:03 1ms
i9j0k1l2 stripe.create_payment BLOCK 2026-03-05 14:23:05 0ms
Each event is:
- Signed with Ed25519 — proves the proxy produced it
- Hash-chained — each event links to the previous one; tampering breaks the chain
- Sequence-numbered — monotonically increasing per proxy instance; enables gap detection during cloud sync
- Zero-retention — only SHA-256 hashes of inputs/outputs are stored, never raw data
Verify the chain hasn't been tampered with:
# Hash chain INTACT — 847 events verified
Generate an HTML report to share with your team:
Cloud sync
Stream your signed audit events to the Estoppl cloud for centralized monitoring, alerting, and compliance evidence.
# Configure the cloud endpoint in estoppl.toml
# [ledger]
# cloud_endpoint = "https://api.estoppl.com/v1/events"
# cloud_api_key = "sk_your_key"
# Start the proxy with cloud sync enabled
The --sync flag starts a background task that:
- Polls local SQLite for new events every 5 seconds
- Batches events (up to 100) and POSTs them to the cloud endpoint
- Tracks a sync watermark so it picks up where it left off (survives restarts)
- Retries with exponential backoff on failures (1s → 2s → 4s → ... capped at 5min)
All events stay in the local audit log regardless of sync status. The cloud is additive — if the network is down, events queue locally and sync when connectivity returns.
Chain integrity under network partition
Every event carries a monotonically increasing sequence_number that is included in the event hash (tamper-evident). Each sync batch includes chain metadata:
- Sequence range (
first_sequence/last_sequence) — lets the cloud detect gaps (e.g., "I have 1-50, you sent 53-100, where are 51-52?") expected_prev_hash— the event hash the cloud should already have for the event before this batch, proving chain continuity across batch boundariesbatch_hash— SHA-256 of all event hashes in the batch, verifying nothing was tampered with in transit
If the cloud detects a gap, it responds with gap_from_sequence and the proxy automatically rewinds its cursor and re-sends the missing events. The local hash chain stays valid regardless of sync state — events are always chained correctly in SQLite first, then synced to cloud as a best-effort background operation.
Project structure
src/
├── main.rs CLI entry point (clap)
├── config/ Configuration loading and defaults
├── mcp/ MCP JSON-RPC type definitions
├── identity/ Ed25519 key management and signing
├── policy/ Rules-based policy engine
├── ledger/ Local SQLite storage with hash chaining
├── proxy/ stdio + HTTP/SSE proxy core
├── sync/ Cloud sync background task
└── report/ HTML compliance report generator
Roadmap
Current (v0.4)
- stdio proxy mode (transparent MCP interception)
- HTTP/SSE proxy mode (MCP Streamable HTTP transport — POST, GET SSE, DELETE)
- JSON-RPC batch support (mixed blocked + allowed in same batch)
- Guardrails: tool block/allow lists, amount thresholds, human review flags
- Ed25519 event signing
- Hash-chained local SQLite audit log
- CLI:
init,start,start-http,audit,report,tail,stats - HTML activity report
-
estoppl tail— live-stream tool calls in your terminal as they happen - Rate limiting / circuit breaker — block tools called more than N times per minute
-
estoppl stats— tool call volume, latency percentiles, per-tool and per-session breakdown - Audit filters —
--tool,--decision,--since - CI + prebuilt binaries (macOS, Linux) via GitHub Releases
-
--syncflag — stream signed events to cloud endpoint (bridge to cloud dashboard)
Next (v0.5)
- Homebrew tap (
brew install estoppl) - npm wrapper package (
npx estoppl— binary distribution, no Rust required) -
estoppl wrap— auto-detect and wrap existing MCP client configs (Claude Desktop, Cursor) in one command - Blocking human review —
HUMAN_REQUIREDtools pause and wait for explicit approval before forwarding -
estoppl dashboard— local web UI for browsing audit events, guardrail hits, and agent activity - OPA (Open Policy Agent) integration for enterprise policy management
Future
- Cloud dashboard with real-time event feed and alerting
- Cloud ledger with immutable WORM storage for regulated industries
- OpenAI function calling interception (beyond MCP)
- A2A (Agent-to-Agent) protocol interception for multi-agent delegation chains
- Framework-agnostic compliance report templates (EU AI Act, SEC, SOC 2)
- Agent Skill provenance logging
- Kubernetes sidecar deployment
- Cross-org agent trust verification
For regulated teams
If you're in financial services and need legally defensible audit records — immutable WORM storage (SEC 17a-4), regulatory evidence packs, cross-org trust verification — see estoppl.ai for the enterprise platform. This proxy is the open-source foundation; the cloud ledger is where compliance certification lives.
License
Apache 2.0