Bounded per call
- Fuel — a CPU budget it cannot exceed
- Linear-memory ceiling
- Optional wall-clock deadline via epoch interruption
Apache-2.0 · one binary · v0.2.0
MCPdef sits in the data path between your agents and the MCP servers they call. It brokers auth so servers never hold long-lived credentials, decides allow or deny per call, can run an untrusted server sandboxed under Wasmtime, and appends every decision to a tamper-evident ledger — before the call reaches anything.
your clients
agent · IDE
app · service
CI · script
mcpdef
one binary
in the path
deny by default
your MCP servers
stdio child process
Streamable-HTTP server
legacy HTTP+SSE server
untrusted .wasm (sandboxed)
Clients connect over stdio or Streamable HTTP with a bearer JWT. You declare
the servers to front in one mcpdef.toml. The boundary is the MCP
tool wire only — MCPdef never sits between an agent and a model
provider, so each layer keeps a crisp threat model.
§01 — the gate pipeline
Every tools/call crosses the same pipeline before it reaches
a server. A call that is not explicitly allowed returns an MCP
tool-execution error — so the model can self-correct — and is
audited either way.
Last-Event-ID resumption. Carries the egress/SSRF guard: cloud metadata always blocked, DNS-pinned.
WWW-Authenticate challenge.
upstream-timeout rather than hanging.
Safety and audit are never paywalled. The complete data path — transport bridging, allowlists, the ledger, token brokering, RBAC, policy enforcement and the WASM sandbox — ships in the free binary.
§02 — the audit ledger
One JSON line per governed call, appended before dispatch. Editing or deleting any interior record breaks every hash downstream. These are real records from the quickstart below — an allow and a deny, chained.
seq 0 — allowed
seq 1 — denied, and still recorded
audit verify on its own proves internal consistency. It
cannot detect tail-truncation or wholesale file replacement, because a
shorter valid chain is still a valid chain. Catching that needs a
(head, count) pair sealed out-of-band and checked with
audit verify --head <h> --count <n>. If a page tells
you a hash chain alone is tamper-proof, it is selling you something.
§03 — untrusted servers
An upstream can be a .wasm server that MCPdef executes itself,
in-process under Wasmtime — no child process, no shell, no ambient
access. Every call is bounded, and the same allowlist, RBAC and audit apply
as to any other upstream.
Bounded per call
Path A — core module
transport = "wasm" runs against an empty linker. Zero ambient capability: no filesystem, no network, no clock. A module that imports WASI simply fails to load.
Path B — wasip2 component
transport = "wasm-component" runs the mcpdef:server WIT world under capability-scoped WASI that grants nothing by default. Its only possible host capability is outbound TCP.
Egress, deny-all
That TCP grant is gated per destination by wasm_allow_egress, default deny-all, reusing the same IP classification as the main egress guard — so cloud metadata and special-use ranges stay blocked.
§04 — see it working
Real output. The demo upstream is the mock server that ships for the
integration tests: it exposes a harmless echo and a
delete_repo to exercise the deny path. Point the same config at
any real stdio or HTTP MCP server.
Point Claude Code or Cursor at it over stdio with mcpdef run
--config mcpdef.toml, or any Streamable-HTTP client at
/mcp. Turn on [gateway.admin] — off by
default, on a separate port from the data path — for a read-only
status UI, Prometheus /metrics and a small JSON API, with no
external stack required.
§05 — supply chain
A gateway that sees every tool call has no business asking to be trusted on its word. Every release is signed and every crate ships a bill of materials.
4
Platforms per release — x86_64 and aarch64, on linux-musl and macOS.
10
CycloneDX SBOMs, one per crate, attached to the release.
100%
Of release artefacts carry a Sigstore signature and certificate.
152
Tests — unit, transport bridge, egress, pin, rate-limit, OAuth/RBAC, sandbox, injection scan, CLI.
Container
The image is signed too — the registry carries a cosign signature tag alongside it.
Binary
Source
The OSS engine is Apache-2.0 at the repository root. The paid governance plane lives under ee/ on BSL 1.1, its own workspace, never packaged into the public crates.
§06 — where it actually is
The MCP governance category is under eighteen months old and crowding fast. Here is the state of this one, without the roadmap dressed up as the product.
[server.env], so a client's bearer is never passed through.*-linux-musl build has to be validated against it — the
JIT path may fall back to glibc. That is why this page does not promise a
blanket fully-static binary. For locked-down hosts that forbid W^X pages
there is a fully static, no-JIT profile using the Pulley
interpreter.
Built against MCP spec 2025-11-25, forward-planning the stateless 2026-07-28 RC. MCPdef governs the tool wire and explicitly does not route model traffic; a vendor private-MCP tunnel solves reachability, not governance, and the two compose — terminate the tunnel locally and hand its JSON-RPC to MCPdef.
Apache-2.0
The engine is open source and complete on its own. Nothing about safety or audit is held back to sell you something.