The firewall for MCP tool calls — with a replayable audit trail.
See It Work · Quick Start · CI Guide · Discussions
Your MCP agent calls read_file, exec, web_search — but should it?
Assay sits between your agent and its tools. It intercepts every MCP tool call, checks it against your policy, and blocks what shouldn't happen. Every decision produces an evidence trail you can audit, diff, and replay.
Agent ──► Assay ──► MCP Server
│
├─ ✅ ALLOW (policy match)
├─ ❌ DENY (blocked, logged)
└─ 📋 Evidence bundle
No hosted backend. No API keys. Deterministic — same input, same decision, every time.
The average MCP server scores 34/100 on security. Assay gives you the policy gate and audit trail to fix that. Covers 7 of 10 OWASP MCP Top 10 risks.
cargo install assay-cli
mkdir -p /tmp/assay-demo && echo "safe content" > /tmp/assay-demo/safe.txt
assay mcp wrap --policy examples/mcp-quickstart/policy.yaml \
-- npx @modelcontextprotocol/server-filesystem /tmp/assay-demo✅ ALLOW read_file path=/tmp/assay-demo/safe.txt reason=policy_allow
✅ ALLOW list_dir path=/tmp/assay-demo/ reason=policy_allow
❌ DENY read_file path=/etc/passwd reason=path_constraint_violation
❌ DENY exec cmd=ls reason=tool_denied
Then inspect the audit artifact Assay can hand to security or compliance:
assay evidence show demo/fixtures/bundle.tar.gzThe bundle is tamper-evident and cryptographically verifiable. If your run includes signed mandate events, the same bundle also carries the Ed25519-backed authorization trail for high-risk actions.
Yes, if you:
- Build with Claude Desktop, Cursor, Windsurf, or any MCP client
- Ship agents that call tools and you need to control which ones
- Want a CI gate that catches tool-call regressions before production
- Need a deterministic audit trail, not sampled observability
Not yet, if you:
- Don't use MCP (Assay is MCP-native; other protocols are on the roadmap)
- Need a hosted dashboard (Assay is CLI-first and offline)
Assay ships a helper that finds your local Cursor MCP config path and prints a ready-to-paste entry:
assay mcp config-path cursorIt generates JSON like:
{
"filesystem-secure": {
"command": "assay",
"args": [
"mcp",
"wrap",
"--policy",
"/path/to/policy.yaml",
"--",
"npx",
"-y",
"@modelcontextprotocol/server-filesystem",
"/Users/you"
]
}
}The same wrapped command works in other MCP clients:
- Cursor: paste the generated entry into
mcpServers - Windsurf: paste the same
mcpServersentry into~/.codeium/windsurf/mcp_config.json - Zed: paste the wrapped command into
context_serversin your settings JSON
See MCP Quick Start for client-specific examples.
version: "2.0"
name: "my-policy"
tools:
allow: ["read_file", "list_dir"]
deny: ["exec", "shell", "write_file"]
schemas:
read_file:
type: object
additionalProperties: false
properties:
path:
type: string
pattern: "^/app/.*"
minLength: 1
required: ["path"]Already have a legacy constraints: policy? Assay still reads it, warns once, and ships assay policy migrate to write the v2 JSON Schema form.
Or don't write one — generate it from what your agent actually does:
assay init --from-trace trace.jsonlSee Policy Files for the full YAML schema.
Already tracing with Langfuse or an OTel-enabled agent stack? Keep that pipeline. Assay ingests OpenTelemetry JSONL, turns it into replayable traces, and gives you deterministic policy gates plus exportable evidence bundles.
assay trace ingest-otel \
--input otel-export.jsonl \
--db .eval/eval.db \
--out-trace traces/otel.v2.jsonlThen run assay ci on the converted trace or export an Evidence Bundle for audit handoff. See OpenTelemetry & Langfuse.
# .github/workflows/assay.yml
name: Assay Gate
on: [push, pull_request]
permissions:
contents: read
security-events: write
jobs:
assay:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: Rul1an/assay-action@v2PRs that violate policy get blocked. SARIF results show up in the Security tab.
On the M1 Pro/macOS fragmented-IPI harness, Assay's protected tool-decision path measured:
- Main protection run:
0.771msp50 /1.913msp95 - Fast-path scenario:
0.345msp50 /1.145msp95
These are tool-decision timings, not end-to-end model latency.
Assay already ships adapters for emerging agent protocols:
| Protocol | Adapter | What it maps |
|---|---|---|
| ACP (OpenAI/Stripe) | assay-adapter-acp |
Checkout events, payment intents, tool calls |
| A2A (Google) | assay-adapter-a2a |
Agent capabilities, task delegation, artifacts |
| UCP (Google/Shopify) | assay-adapter-ucp |
Discover/buy/post-purchase state transitions |
Each adapter translates protocol-specific events into Assay's canonical evidence format. Same policy engine, same evidence trail — regardless of which protocol your agent speaks.
The agent protocol landscape is fragmenting (ACP, A2A, UCP, AP2, x402). Assay's bet: governance is protocol-agnostic. The evidence and policy layer stays the same even as protocols come and go.
| Deterministic | Same input, same decision, every time. Not probabilistic. |
| MCP-native | Built for MCP tool calls. Adapters for ACP, A2A, UCP. |
| Evidence trail | Every decision is auditable, diffable, replayable. |
| Offline-first | No backend, no API keys. Runs on your machine. |
| Measured | 0.771ms p50 / 1.913ms p95 in the main M1 Pro/macOS tool-decision harness. |
| Tested | 3 security experiments, 12 attack vectors, 0 false positives. |
cargo install assay-cliIn CI: use the GitHub Action directly.
Python SDK: pip install assay-it
- MCP Quickstart — full walkthrough with a filesystem server
- Policy Files — current YAML schema for
assay mcp wrap - OpenTelemetry & Langfuse — turn existing traces into replay and evidence
- CI Guide — GitHub Action setup
- OWASP MCP Top 10 Mapping — how Assay addresses each risk
- Evidence Store — push bundles to S3, B2, or MinIO
- Security Experiments — 12 vectors, 0 false positives
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warningsSee CONTRIBUTING.md. Join the discussion.