AgentStack
MCP verified MIT Self-run

Assay

mcp-rul1an-assay · by Rul1an

Policy-as-code for MCP agents: deny risky tool calls before they run, prove what ran with verifiable evidence, and enforce egress in the kernel (eBPF/LSM, Linux). Deterministic, offline-first, bounded claims.

No reviews yet
0 installs
11 views
0.0% view→install

Install

$ agentstack add mcp-rul1an-assay

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v3.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v3.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Assay? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Assay

Policy-as-code for MCP agents: enforce what a tool call can do, prove what it did, stay honest about what you can't. A deterministic, fail-closed gate for MCP tool calls — with real kernel-level (eBPF/LSM) enforcement on Linux and offline-verifiable evidence. CI-native, no backend, bounded by design.

Quickstart · How it works · See it work · MCP example · OWASP MCP Top 10 · Discussions


Agents got real tool access through MCP — and tool poisoning, rug pulls, and confused-deputy OAuth came with it. Most tools scan a server or filter a prompt. Assay sits at the tool-call boundary and does three things, in order.

Enforce, prove, stay honest

  • Enforce. A deterministic, fail-closed gate decides every tools/call before it runs, with the precise reason for each allow or deny. On Linux it adds real kernel enforcement — an eBPF/LSM IPv4/TCP connect-egress block and a Landlock TCP-connect port allowlist, both opt-in and fail-closed. A policy it cannot express exactly is refused, never half-applied.
  • Prove. Each decision and observed effect becomes an offline-verifiable, tamper-evident evidence bundle: the verdict, the pre-call establish journey, and declared-vs-observed conformance — all reviewable in CI, with no hosted backend.
  • Stay honest. Every claim carries its basis (verified, self_reported, inferred, absent), and a gate refuses to let a claim exceed what was observed. A tool returning "success" is the provider's assertion, never proof. Assay ships no single safety score and never claims more than it can prove.

Quickstart

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
❌ DENY   read_file  path=/tmp/outside-demo.txt      reason=path_constraint_violation
❌ DENY   exec       cmd=ls                          reason=tool_denied

Wire it into Cursor, Claude Code, or Codex in one line with assay mcp config-path . Python SDK: pip install assay-it. CI: GitHub Action. No hosted backend, no API keys for core flows, deterministic by design. New to the threat model? The [OWASP MCP Top 10 mapping](docs/security/OWASP-MCP-TOP10-MAPPING.md) lays out, per risk, what Assay covers and what it deliberately does not.

What ships

| Output | What it is | |--------|------------| | Policy gate | assay mcp wrap — deterministic allow/deny before tools run, with the reason. | | Evidence bundle | Offline-verifiable, tamper-evident archive for audit and replay. | | Trust Basis / Trust Card | Canonical trust-basis.json (bounded claim classification) plus review-friendly trustcard.{json,md,html}. | | External receipts | Eval outcomes, runtime decisions, and model inventory as bounded receipts with JSON Schema contracts. | | Tool-decision surface | Each privileged tools/call recorded as assay.tool_decision_surface.v0 — sensitive ids hashed, raw arguments never stored. | | SARIF / CI | GitHub Action, Security-tab integration, policy gates on PRs. | | Attestation | Export a bundle as an in-toto / DSSE statement (v0), anchor-pluggable. |

  Agent ──► Assay ──► MCP Server
              ├─ ✅ ALLOW / ❌ DENY  (policy, with reason)
              ├─► 📋 Evidence bundle (offline-verifiable)
              └─► 📊 Trust Basis → Trust Card → SARIF / CI

New in 3.30.0: an evidence event can carry an optional soft semantic_digest (with its digest_profile) beside the hard content_hash — a correlation/equivalence overlay for grouping records by canonical content across producers or points in time, computed via the [assay-canonical](crates/assay-canonical/) crate (RFC 8785 / JCS). It is never part of content_hash, never on the verify or admission path, and never substitutes integrity. [CHANGELOG.md](CHANGELOG.md) and release notes remain the authority for what is public; crates.io publication is separate from merge state.

Is this for me?

Yes if you already have eval output, runtime decisions, inventory artifacts, or MCP tool-call tests, and you want a small reviewable CI artifact instead of a dashboard — bounded auditability, not a scalar trust badge.

Not yet if you need Assay to judge model correctness for you, want a hosted dashboard as the product, or want a compliance claim rather than a bounded evidence boundary. Assay is not a trust-score engine, a generic eval dashboard, or a hosted observability product — see [what it is and is not](docs/concepts/scope.md).

See it work

An agent tries a privileged action — github.add_deploy_key — through the enforcing proxy, decided per call before it forwards, offline against a local mock (no real credentials):

cd examples/privileged-action-gate && ./run.sh

A deny is fail-closed caution, not a verdict on intent; an allow is the decision to forward, never proof the action happened. Declared-vs-observed conformance is recorded beside the verdict, never as a gate. Full walkthrough: [privileged-action-gate](examples/privileged-action-gate/).

Pick your path

| You have | What you get | Start here | |---|---|---| | Promptfoo JSONL from CI evals | Eval outcome receipts + verified bundle + Trust Basis diff | [Promptfoo JSONL](docs/use-cases/evidence-receipts-from-promptfoo-jsonl.md) | | OpenFeature EvaluationDetails | Decision receipt + verified bundle | [OpenFeature](docs/use-cases/openfeature-evaluationdetails-to-ci-review-artifact.md) | | CycloneDX ML-BOM model component | Inventory receipt + verified bundle | [CycloneDX ML-BOM](docs/use-cases/cyclonedx-mlbom-model-to-inventory-receipt.md) | | MCP tool calls | Allow/deny audit trail + observed-behavior evidence | [MCP Quick Start](examples/mcp-quickstart/) | | A GitHub PR gate | Trust Basis diff, gate status, SARIF/JUnit-ready output | [CI Guide](docs/guides/github-action.md) | | A Runner archive / coverage annotation | Coverage descriptors + claim-class cells + a claimed-vs-observed check | [Coverage-honesty walkthrough](examples/coverage-honesty-walkthrough/) |

The workflow stays small: import or record a bounded outcome, bundle and verify it, compile trust-basis.json, gate the Trust Basis diff. Assay doesn't make the upstream tool the source of truth; it makes the evidence boundary inspectable. For privileged tool actions, the MCP proxy records each tools/call as a structured [tool-decision surface](docs/reference/tool-decision-surface.md) — keeping the asserted-versus-verified line honest.

Policy is simple

version: "2.0"
name: "my-policy"
tools:
  allow: ["read_file", "list_dir"]
  deny: ["exec", "shell", "write_file"]
schemas:
  read_file:
    type: object
    properties:
      path: { type: string, pattern: "^/app/.*" }
    required: ["path"]

Generate one from observed behaviour with assay init --from-trace trace.jsonl, or migrate a legacy constraints: policy with assay policy migrate. See [Policy Files](docs/reference/config/policies.md).

Why Assay

| | | |---|---| | Canonical evidence | Assay's evidence model is the stable contract; OpenTelemetry and protocol adapters (ACP / A2A / UCP) map into it. | | Deterministic | Same input, same decision — not probabilistic. | | Bounded claims | Explicit about verified vs visible vs absent — no score-first UX. | | Offline-first | No backend required for core enforcement and bundle verification. |

Learn more

  • [MCP Quickstart](examples/mcp-quickstart/) · [Editor MCP recipe](docs/guides/editor-mcp-recipe.md) — policy-enforcing MCP in Cursor / Claude Code / Codex
  • [Coding-agent governance](docs/guides/coding-agent-governance.md) · [OpenTelemetry & Langfuse](docs/guides/otel-langfuse.md) — observed runs → evidence
  • [Evidence Receipts in Action](docs/notes/EVIDENCE-RECEIPTS-IN-ACTION.md) — Promptfoo / OpenFeature / CycloneDX receipt families
  • [CI Guide](docs/guides/github-action.md) · [Evidence Store](docs/guides/evidence-store-aws-s3.md) (S3 / B2 / MinIO)
  • [OWASP MCP Top 10 mapping](docs/security/OWASP-MCP-TOP10-MAPPING.md) · [Security experiments](docs/architecture/SYNTHESIS-TRUST-CHAIN-TRIFECTA-2026q2.md)
  • Positioning: [ADR-033](docs/architecture/ADR-033-OTel-Trust-Compiler-Positioning.md) · [RFC-005](docs/architecture/RFC-005-trust-compiler-mvp-2026q2.md)

Evidence epistemology, latency, and the internal Runner

Trust claims use explicit epistemology, not a single safety score: verified (direct evidence or offline verification), self_reported (emitted without independent corroboration), inferred (bounded, documented rules), absent (no trustworthy evidence). Assay ships no aggregate trust score or safe/unsafe badge as the main output — see [ADR-033](docs/architecture/ADR-033-OTel-Trust-Compiler-Positioning.md).

Tool-decision path latency on an M1 Pro fragmented-IPI harness: main protection 0.771ms p50 / 1.913ms p95; fast-path 0.345ms p50 / 1.145ms p95. These are tool-decision timings, not end-to-end model latency.

[Assay-Runner](docs/reference/runner/index.md) is an internal measured-run subsystem behind the delegated Linux/eBPF acceptance path — publish = false, not a standalone product, no release commitment.

Ecosystem

Repositories that compose with Assay's evidence layer:

  • assay-action — GitHub Action: verify bundles, PR summaries, SARIF (Marketplace).
  • Assay-Harness — recipe, gate, and report layer over canonical evidence artifacts.
  • observed-effect-v0 — worked examples of the bounded observed-effect evidence record and its neutral carriers (in-toto, SCITT, MCP evidenceRef).
  • gateway-evidence-replay — deterministic offline replay verifier for gateway-path evidence bundles.
  • RGE-Bench — a neutral, externally reproduced conformance kit for evidence reviewability, maintained separately under its own machine-checked neutrality guard.

Contributing

cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings

See [CONTRIBUTING.md](CONTRIBUTING.md) and GitHub Discussions.

License

[MIT](LICENSE)

Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v3.1.0 Imported from the upstream source.