mcp-assure
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.
Grok Build / cannot-bypass host
python examples/grok_host_wire.py
# AdaptiveGate + AssuredToolDispatcher(adaptive=True): handlers only via call_tool
from mcp_assure.integrations import AssuredToolDispatcher
host = AssuredToolDispatcher(engine, handlers, adaptive=True, source="grok-build")
Grok skill: ~/.grok/skills/mcp-assure/SKILL.md (/mcp-assure).
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) orfreeze(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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mcp_assure-0.3.2.tar.gz.
File metadata
- Download URL: mcp_assure-0.3.2.tar.gz
- Upload date:
- Size: 49.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1cf2f16bdf4be1195497482efa9eab9c062e9d11ea2247e18a2aecebf017154c
|
|
| MD5 |
0758d5a132fa5e80eeda8647778143a9
|
|
| BLAKE2b-256 |
6fd47debb1afcbf03f71581dc99e8a06ec81326c731bcc1c4132d522c0fe65e2
|
File details
Details for the file mcp_assure-0.3.2-py3-none-any.whl.
File metadata
- Download URL: mcp_assure-0.3.2-py3-none-any.whl
- Upload date:
- Size: 47.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fd6c760c4f3ddf7775fd2e0e8f3523e200ddb94f89f7046c4b7fcfd0ea7071cf
|
|
| MD5 |
20906eb133b11484db2cca2d89b43a34
|
|
| BLAKE2b-256 |
17da15e779131f86b1da2c60e502f539de6a0ba761ad0fea9f25c7c4aa5b952e
|