Skip to main content

mcp-assure

ci PyPI License

Open-source security CLI + runtime for MCP-style agent tool calls.

The model proposes. The gate decides. Receipts remember.

mcp-assure is a local control plane you put in front of tool execution: policy catalog, argument constraints, optional resource/audience binding checks, velocity and blast limits, freeze mode, proactive campaign scoring, and hash-chained decision receipts. It is not a full SOC, not a hosted vuln scanner, and not a claim that all agent misuse is impossible.

Built by Alex Price / StellarRequiem. Apache-2.0. Zero runtime dependencies (core).
v0.3.0 — security CLI surface (status / check / evaluate) aligned with the open-security-CLI moment, without cloning cloud scanners. See docs/VS_CODEX_SECURITY.md.

Public page: xclusivexo.com/mcp-assurance/#mcp-assure

Why this exists

MCP hosts give agents tools. Tools are power. Under MCP 2026-07-28, more security responsibility sits with implementers. Code scanners help at build time; runtime authorization is still required at the moment of tools/call. Open security CLIs that only find bugs in git trees leave the live agent loop ungated — this project fills that layer.

Install

pip install mcp-assure
# optional FastMCP middleware:
pip install "mcp-assure[fastmcp]"
# from git (development tip):
pip install "git+https://github.com/StellarRequiem/mcp-assure"
# from a checkout:
pip install -e ".[dev,fastmcp]"

Security CLI (local, no API key)

mcp-assure status                 # what this is / is not
mcp-assure check                  # purple + synthetic campaign detector (CI entry)
mcp-assure evaluate --tool echo --args-json '{"text":"hi"}' --pack baseline
mcp-assure evaluate --tool read_file --args-json '{"path":"/proc/self/environ"}' --adaptive
mcp-assure purple
mcp-assure campaign
mcp-assure packs
mcp-assure verify-receipts ./mcp-assure-receipts.jsonl
mcp-assure demo

mcp-assure check exits non-zero if control-plane fixtures fail — use it in CI the way other security CLIs use scan, but for gate health, not SAST.

Real host demo (local)

Simulates an MCP host tools/call path with AssuredToolDispatcher:

python examples/host_demo.py

Expect: ALLOW for allowlisted tools, DENY for unknown tools / smuggled args, receipts verify.

60-second integration

from mcp_assure import (
    AssureEngine,
    AssuredRunner,
    ToolCall,
    ToolPolicy,
    ToolPolicyRegistry,
)

registry = ToolPolicyRegistry([
    ToolPolicy(
        name="read_file",
        required_args=("path",),
        allowed_args=("path",),
        forbidden_args=("token", "password"),
        max_blast=1,
    ),
])

engine = AssureEngine(registry, receipts_path="./mcp-assure-receipts.jsonl")

def read_file(args):
    # your real implementation
    return open(args["path"], encoding="utf-8").read()

runner = AssuredRunner(engine, handlers={"read_file": read_file})

out = runner.invoke(ToolCall(tool="read_file", arguments={"path": "README.md"}))
# out["executed"] is True only if the gate ALLOWed
# out["verdict"]["receipt_hash"] is the audit seal for this decision

Property: on DENY / DRY_RUN, the handler is never called.

What it enforces (tested)

ID Property
P1 Unknown tool → DENY
P2 Empty catalog → DENY
P3–P4 DENY/DRY_RUN never invoke handlers
P5–P6 Velocity / blast limits
P7 lab_only tools require lab_mode
P8 Model notes cannot flip DENY→ALLOW
P9 Receipt chain verifies; tamper fails
P10 Freeze mode blocks non-allowlisted tools
P11 Forbidden / disallowed args → DENY
P12 Resource/audience mismatch → DENY when configured

See THREAT_MODEL.md and CLAIMS.md.

Policy from JSON

import json
from mcp_assure import AssureEngine, ToolPolicyRegistry

with open("examples/policy.example.json") as f:
    reg = ToolPolicyRegistry.from_mapping(json.load(f))
engine = AssureEngine(reg)

MCP-shaped payloads

from mcp_assure.mcp_types import tool_call_from_mcp
from mcp_assure import AssureEngine, ToolPolicy, ToolPolicyRegistry

engine = AssureEngine(ToolPolicyRegistry([ToolPolicy(name="echo")]))
call = tool_call_from_mcp({"name": "echo", "arguments": {"text": "hi"}})
print(engine.evaluate(call).as_dict())

Policy packs

from mcp_assure import AssureEngine, load_pack

engine = AssureEngine(load_pack("baseline"))
# also: mcp_authz_boundaries, strict_local
python -m mcp_assure packs

mcp_authz_boundaries encodes runtime gates for resource/audience-style failures (the class of bugs mcp-bench measures in scanners) — call-time enforcement, not a scanner replacement.

Host / FastMCP integration

from mcp_assure.integrations import AssuredToolDispatcher, assure_callable
# See mcp_assure/integrations/fastmcp_notes.py for patterns.

Dispatcher is the usual host hook for tools/call. Decorators wrap kwargs-style tool functions before registration.

FastMCP middleware (on_call_tool)

Requires pip install "mcp-assure[fastmcp]" (FastMCP ≥2.9):

from fastmcp import FastMCP
from mcp_assure import AssureEngine
from mcp_assure.packs import load_pack
from mcp_assure.integrations import build_assure_middleware

engine = AssureEngine(load_pack("baseline"), receipts_path="receipts.jsonl")
mcp = FastMCP("secured")
mcp.add_middleware(build_assure_middleware(engine))

@mcp.tool
def echo(text: str) -> dict:
    return {"echo": text}

On DENY the middleware raises ToolError and does not call the tool handler.
Demo: python examples/fastmcp_assured.py

Proactive campaign watch (adaptive)

Static allowlists are necessary but not sufficient: agentic campaigns hide in volume and shape. Wrap the engine with AdaptiveGate:

from mcp_assure import AssureEngine, AdaptiveGate, ToolCall
from mcp_assure.packs import load_pack

engine = AssureEngine(load_pack("agent_eval_strict"), freeze_path="./FREEZE")
gate = AdaptiveGate(engine, auto_freeze=True)
out = gate.evaluate(ToolCall(tool="echo", arguments={"text": "ok"}))
print(out.snapshot.recommendation, out.verdict.code)
  • Pre-block: path/IMDS, template/RCE-class, gzip+base64 packer markers → PROACTIVE_ARG_BLOCK
  • Window score: swarm sources, tool spray, unknown-tool burst, probe-dominated traffic
  • Adapt: escalate (human before execute) or freeze (touch freeze file; only freeze-allow tools)
python -m mcp_assure campaign-demo

See docs/PROACTIVE_DEFENSE.md.

Purple stress suite

Synthetic adversarial sequences (no network), including adaptive fixtures:

python -m mcp_assure purple

Optional verity hook

If verity-core is installed, claim-like tool results can be soft-checked:

from mcp_assure.verity_hook import maybe_verify_tool_result
maybe_verify_tool_result({"accuracy": 0.99, "sample_size": 5})

Not required; no-ops cleanly when verity is absent.

CLI

python -m mcp_assure demo
python -m mcp_assure packs
python -m mcp_assure purple
python -m mcp_assure verify-receipts ./mcp-assure-receipts.jsonl

Adversarial stance

This package is designed to survive hostile review:

  • Explicit threat model and claim gate
  • Properties P1–P12 locked to unit tests
  • No runtime deps in the TCB surface
  • Residual risk documented (host must not bypass the runner)
pytest -q

What this is not

  • Not a replacement for OAuth authorization servers
  • Not host EDR / network IDS
  • Not “stops all prompt injection”
  • Not a full enterprise SOC platform

Related work (StellarRequiem)

  • mcp-bench — do scanners catch authz-logic bugs?
  • scope-gate — deny-by-default research authorization
  • verity-core — refuse bad claims; audit chains

License

Apache-2.0. Copyright 2026 Alex Price / StellarRequiem.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mcp_assure-0.3.0.tar.gz (47.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mcp_assure-0.3.0-py3-none-any.whl (46.6 kB view details)

Uploaded Python 3

File details

Details for the file mcp_assure-0.3.0.tar.gz.

File metadata

  • Download URL: mcp_assure-0.3.0.tar.gz
  • Upload date:
  • Size: 47.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.5

File hashes

Hashes for mcp_assure-0.3.0.tar.gz
Algorithm Hash digest
SHA256 fbc6ec4ebe971d94f1d835a91dd5078b0bc39371fea73f16e324de8b1a717711
MD5 e8f8b85b2d3831f47b568b72ab424c88
BLAKE2b-256 5fa5c14f5310425cc00b65007710ca5c40fe1c5eceb54669bb934bf77cf5fad7

See more details on using hashes here.

File details

Details for the file mcp_assure-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: mcp_assure-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 46.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.5

File hashes

Hashes for mcp_assure-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f000f2a8530d8238e12097ed20dda193ba116605631fb52422347abbfcdd33da
MD5 10a403bcdc1dfb2520422af4cbf46a0a
BLAKE2b-256 965c28ff20fb4cdd59420d2ab01c76aee9431d42b9de059822392cf0cb4848e0

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page