Skip to main content
MCP-ATTEST — the conformance harness for MCP agent access control. Policy says deny, the gateway allowed it: nine checks replay your trace against your own rules.

Prove that your MCP policy actually enforces.

Two input files · nine checks · zero runtime dependencies · MIT

Install · Run it · The nine checks · CI · Specification · Website · Русский

CI Latest release MIT license PyPI version Python 3.10+

mcp-attest check output on a recorded trace: C6 policy denied the call but the gateway allowed it, C9 tool definition changed after approval, summary critical=7 high=6

Real output from examples/session.jsonl. Exit code 1 means a blocking finding. Examples · Why this exists.

mcp-attest is a conformance harness for MCP agent access control. It takes the policy you wrote and the trace of what actually happened, and reports every point where they disagree.

It is not a gateway. It does not sit on the request path, and it never holds a credential for the upstream server. It reads evidence that already exists.

Why mcp-attest?

  • It catches the accepted-but-not-enforced rule. C6 re-evaluates your policy locally against every recorded call. A call your policy denies but the gateway allowed is invisible in every dashboard, because dashboards show what the gateway believed.
  • Evidence, not opinion. Every finding carries the exact tool, arguments and decision that produced it, and the fix.
  • Offline by construction. No network calls, no telemetry, no account. Traces carry payloads and stay where they are.
  • Exit codes, not vibes. 0 clean, 1 blocking finding, 2 bad input. It is a CI gate without a wrapper script.
  • Zero dependencies. Python 3.10+ and the standard library.
  • Tamper-evident receipts. Optional hash-chained, HMAC-signed receipts for every allowed call.
mcp-attest flow: the policy and the trace are replayed locally and compared, producing findings, an exit code and a receipt chain

Nothing is proxied. The trace is the evidence. Full specification.

Website · Specification · Research notes · MIT license

Install

pipx install mcp-attest          # isolated CLI
uvx mcp-attest check --help      # one-shot
pip install mcp-attest           # into a virtualenv

From source:

git clone https://github.com/Balanov/mcp-attest.git
cd mcp-attest
python -m pip install -e ".[dev]"
python -m unittest discover -s tests -v

Run it

attest init                                            # write a starter policy
attest check --policy examples/policy.json --trace examples/session.jsonl
!! [CRITICAL] C6 Policy denies 'shell__exec' but the gateway allowed it
          Local evaluation of the policy says deny (tool is on the deny list); the trace
          records allow ('argument-conditioned rule matched'). This is the 'policy accepted
          but not enforced' failure mode — a rule that is registered but never applied.
          fix: Replay the call against the gateway with the same arguments and fix
               the rule binding, then add this call as a regression case in CI.

summary: critical=7, high=6

Exit code 1 means a blocking finding exists. --json prints machine-readable findings; --strict treats high findings as blocking as well.

Command Purpose
attest init Write a starter policy
attest check Check a trace against a policy
attest receipts Build and verify a hash-chained receipt trail
attest shadow List the servers an agent can reach outside the gateway
attest rules List the enforced rules

The nine checks

ID Rule The failure it catches
C1 default-deny An unset allowlist silently meaning "allow everything"
C2 list/call parity A tool hidden from tools/list but callable by name
C3 narrowing only A per-request control widening a client's grant
C4 credential separation The client's token replayed upstream verbatim
C5 fail closed A call allowed because the policy check errored
C6 enforcement parity The policy says deny, the gateway allowed it
C7 shadow MCP A server the agent can reach outside the gateway
C8 receipt chain Allowed calls with no verifiable receipt, or a broken chain
C9 description integrity A tool definition changed after approval (rug pull)

Input files

Policy

{
  "version": 1,
  "default_decision": "deny",
  "clients": {
    "ci-bot": {
      "tools": {
        "allow": ["fs__read_file", "fs__list_directory"],
        "deny": ["fs__write_file", "fs__delete_everything"],
        "conditional": [
          {
            "tool": "fs__write_file",
            "allow_when": { "path": { "starts_with": "./out/" } },
            "action": "allow",
            "reason": "writes are allowed only inside ./out/"
          }
        ]
      },
      "egress_hosts": ["api.internal.example.com"]
    }
  },
  "gateway": { "mode": "routed", "fail_closed": true, "passthrough_credentials": false },
  "receipts": { "required": true, "key_env": "MCP_ATTEST_KEY" }
}

Condition operators: eq, not_eq, starts_with, ends_with, contains, in, not_in, gt, gte, lt, lte, glob, regex. A bare string ending in / is a prefix; a bare string containing * is a glob.

Trace

Newline-delimited JSON, one event per line. Any proxy, agent harness or CI step can produce it.

{"type":"tools_list","actor":"ci-bot","tools":[{"name":"fs__read_file","description_sha256":"a1b2…"}]}
{"type":"tool_call","actor":"ci-bot","tool":"fs__read_file","args":{"path":"/srv/README.md"},"decision":"allow","upstream":true,"reason":"tool is on the allow list"}
{"type":"client_servers","client":"claude-code","servers":["fs","git"]}
{"type":"gateway_route","server":"fs","tools":["read_file","list_directory"]}

Full specification: SPEC.md.

Receipts

export MCP_ATTEST_KEY=…
attest receipts --trace examples/session.jsonl --out receipts.jsonl
# chain: ok (6 receipts, key=yes)

Each receipt commits to the previous one, so removing or reordering a receipt breaks the chain. With MCP_ATTEST_KEY set, every receipt is additionally signed with HMAC-SHA256, so an auditor can detect edits without access to the gateway.

This is deliberately not a PKI. It answers the question an incident responder actually asks: did this session really contain these calls, in this order, and has anything been altered since?

Use it in CI

- uses: Balanov/mcp-attest@v0
  with:
    policy: .attest/policy.json
    trace: .attest/trace.jsonl

The action fails the job on any critical or high finding, so "our agent policy is enforced" becomes something the pipeline proves instead of something a security questionnaire asks about.

What mcp-attest is not

  • Not a gateway, proxy or enforcement point. It cannot block a call.
  • Not a scanner. It does not connect to your MCP server and sends no probe traffic.
  • Not a PKI. A receipt chain and an HMAC prove order and integrity, not identity.
  • Not a policy editor. It reads the policy you already have.
  • Not a hosted service. No account, no network calls, no telemetry.

Development

python -m pip install -e ".[dev]"
python -m unittest discover -s tests -v

CI runs the suite on Python 3.10–3.13 and publishes the package to PyPI from a tagged release through trusted publishing, with no API token in the repository.

License

MIT. Fork it, modify it, embed it, ship it.

Metadata

Release files for mcp-attest 0.1.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mcp-attest 0.1.4
File Size Uploaded Provenance Actions
mcp_attest-0.1.4.tar.gz 22.5 kB With provenance Details for mcp_attest-0.1.4.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for mcp-attest 0.1.4
File Interpreter ABI Platform Actions
mcp_attest-0.1.4-py3-none-any.whl Python 3 none any Details for mcp_attest-0.1.4-py3-none-any.whl

Total release size: 43.0 kB

Release files / mcp_attest-0.1.4.tar.gz

Download URL mcp_attest-0.1.4.tar.gz
Size 22.5 kB
Tags Source
SHA-256 checksum
How to use checksums
81e7175c5e3e49ed7ad4e34a498bc9dc6f42c98cda82ed450e00e7d15a87fb7c
BLAKE2b-256 checksum
How to use checksums
e19cbfd08f7530c37b4e146ec8d961a0e403580b40d841bff15d673aa98de2d7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 13, 2026.

Transparency log

Release files / mcp_attest-0.1.4-py3-none-any.whl

Download URL mcp_attest-0.1.4-py3-none-any.whl
Size 20.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c4f7762da162154e1c835fb3b6957fe87f21e956cceb0585093b35d58b608fa3
BLAKE2b-256 checksum
How to use checksums
72a811a1922ada5c49198848d7501e36571aab47bd503412c6f79d6bd8bb6e24
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 13, 2026.

Transparency log

Security for mcp-attest 0.1.4

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for mcp_attest-0.1.4.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 13, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page