Skip to main content

🛡️ Warden

PyPI Python License: Apache 2.0

Drop-in security middleware for MCP. Point your AI client at Warden instead of the raw tool-server — one line of config, zero code changes — and every tool call is logged tamper-evidently, allowed/denied/gated by policy, held for human approval when it's dangerous, and scanned for prompt-injection and secret/PII exfiltration.

Everyone's building agents. Warden makes them safe to run.

How it works

AI client ──MCP──▶  WARDEN  ──MCP──▶  downstream MCP servers
                   policy · audit · approval · guard       (filesystem, github, payments, …)

Warden is an MCP server to your client and an MCP client to each real server. It aggregates their tools (namespaced server__tool) and routes every tools/call through:

policy → audit(request) → guard(args) → [deny | approve | allow] → forward → guard(result) → audit(response)

Quickstart

uvx warden-mcp init                 # write a starter warden.yaml
uvx warden-mcp run --config warden.yaml
uvx warden-mcp audit verify         # prove the audit log wasn't altered

Rug-pull defense (TOFU tool-definition pinning) is on by default — a downstream tool whose definition changes after you first approved it is quarantined until you re-approve it.

Optional: tamper-evidence against a hostile operator

The plain audit log detects edits-without-rechain. To make tampering detectable even by someone with write access to the host, enable forward-secure sealing (stdlib, no extra deps):

uvx warden-mcp audit setup-keys --out warden.seed   # prints a VERIFICATION SEED — store it OFF-box
uvx warden-mcp run --seal-state warden_seal_state.json --anchor heads.jsonl
uvx warden-mcp audit verify --log warden_audit.jsonl --seed warden.seed   # verifies the seals

A record sealed before a compromise cannot be forged or rewritten afterward — the key that sealed it is ratcheted forward and destroyed. (Tamper-evident, not tamper-proof: deletion is always possible, you detect it via the off-box anchored heads.)

Point your client at it (e.g. .mcp.json / Claude Desktop / Cursor):

{ "mcpServers": { "warden": { "command": "uvx", "args": ["warden-mcp", "run"] } } }

Policy (warden.yaml)

mode: allow            # allow (log all, gate listed) | strict (deny unless allowed)
servers:
  filesystem:
    cmd: ["npx","-y","@modelcontextprotocol/server-filesystem","/work"]
    tools:
      read_file:  { action: allow }
      write_file: { action: gate, reason: "file write" }
      delete_*:   { action: deny }
  payments:
    url: "http://localhost:9001/mcp"
    tools: { "*": { action: gate } }
sensitive_actions: [transfer, send, delete, purchase, grant, deploy]
rules:
  - id: dangerous-shell
    match: { arg_regex: "rm\\s+-rf|DROP\\s+TABLE" }
    action: deny
  - id: secret-egress
    match: { direction: result, contains: ["BEGIN PRIVATE KEY", "password="] }
    action: redact_and_flag

Starter policies in policies/: paranoid · balanced · dev.

Cross-server dataflow: the lethal-trifecta defense

Per-call rules can't see an attack that spans a session — read untrusted content from one server, get steered by an injected instruction, exfiltrate via another. Tag the ends and Warden tracks the flow: once an untrusted source has returned content into the session, any sink that can exfiltrate is denied (or gated):

flow:
  on_violation: gate        # gate (ask a human) | deny (default, fail closed)
  sources: ["web__*", "email__read*"]      # tools whose results are untrusted content
  sinks:   ["email__send*", "http__post", "slack__*"]   # tools that can send data out

"Untrusted-content-touched context may not reach an exfil-capable tool without a human in the loop."

Remote deployment: HTTP gateway + OAuth 2.1

Run Warden as a deployable HTTP MCP gateway (streamable transport) instead of stdio:

pip install "warden-mcp[http,auth]"
uvx warden-mcp run --http --host 0.0.0.0 --port 8080 --config warden.yaml

With an auth: block, Warden is an OAuth 2.1 Resource Server — every request to the /mcp endpoint must carry a valid bearer token or it's rejected before reaching any tool with 401 + a WWW-Authenticate challenge. It validates per the MCP authorization spec: RFC 9728 Protected Resource Metadata (served at /.well-known/oauth-protected-resource), RFC 8707 audience binding (a token minted for another service is rejected), JWKS signature verification (asymmetric only — no alg:none), and scope enforcement.

auth:
  resource: https://warden.example/mcp
  issuer: https://auth.example/
  jwks_uri: https://auth.example/.well-known/jwks.json
  required_scopes: [mcp:call]

(stdio is a local single-user trust boundary and needs no token; --http without an auth: block serves openly — put it behind your own boundary.)

Remote approvals (Telegram)

In headless / --http mode there's no terminal, so gated calls would fail closed. Approve them from your phone instead — pip install "warden-mcp[telegram]" and add:

approval:
  channel: telegram
  bot_token_env: WARDEN_TELEGRAM_TOKEN   # token read from the environment, never the file
  chat_id: "123456789"

Each gated call sends a message with inline Approve / Deny buttons; timeout or any error fails closed.

mcp-scan — audit a server before you trust it

Warden guards tool calls at runtime; mcp-scan is the static, pre-install companion. Point it at an MCP server and it inspects every tool definition for tool-poisoning / prompt-injection hidden in descriptions, secrets in schemas, dangerous capabilities, and the lethal-trifecta combination (a server that can both read untrusted content and exfiltrate). Exits non-zero on risk, so it gates CI.

mcp-scan --command npx --arg -y --arg @some/mcp-server   # or --url https://…/mcp, or --config .mcp.json
warden scan --config .mcp.json --json                    # same, as a warden subcommand

It reuses Warden's own guard corpus, pin fingerprints, and dataflow taxonomy — the static half of the same engine. (Fills the gap left when Invariant's mcp-scan was acquired and closed.)

Why it's trustworthy

  • Tamper-evident audit — hash-chained JSONL; warden audit verify detects any edit/insert/delete. Add forward-secure sealing to catch even a hostile operator who rewrites and re-chains the log.
  • Rug-pull defense — TOFU pinning quarantines a tool whose definition changes after approval.
  • Fail closed — approval timeout, no channel, redaction-without-a-guard, or any non-yes ⇒ blocked.
  • Defense in depth — the guard hard-denies an unambiguously destructive payload (rm -rf, mkfs, DROP TABLE) and redacts leaked secrets (provider keys, JWTs, private keys) even when policy says allow. direction: result rules can deny a response that leaks (e.g. a private key).
  • Untrusted-by-default downstream — tool metadata is namespaced + validated + stripped, never passed through raw; a malicious downstream can't shadow another or inject via tool descriptions.
  • Zero egress — the core proxy + guard make no network calls of their own. The guard is pure local regex — no LLM in the request path (deterministic, fast, nothing leaves the box).

Layout

warden/
  schemas.py      shared contract (closed-enum decisions, hash-by-default audit)
  proxy.py        MCP upstream server + downstream clients + namespacing + pin check
  interceptor.py  the policy→audit→approval→guard pipeline (+ REDACT + result rules)
  policy.py       YAML → allow/deny/gate/redact/redact_and_flag (request + result direction)
  guard.py        prompt-injection corpus + secret/PII + shell/SQL/path detection
  audit.py        hash-chained tamper-evident log + verify (+ forward-secure seals)
  sealing.py      forward-secure sealing + external anchoring (hostile-operator defense)
  pinning.py      TOFU tool-definition pinning (rug-pull defense)
  auth.py         OAuth 2.1 Resource Server — RFC 9728/8707, JWKS, scopes (extra: [auth])
  http.py         deployable HTTP MCP gateway + bearer-auth middleware (extra: [http])
  flow.py         cross-server dataflow / lethal-trifecta defense (session taint tracking)
  scan.py         mcp-scan — static pre-install risk audit of an MCP server's tools
  scan_cli.py     the `mcp-scan` console script + `warden scan` subcommand
  approval/       human-in-the-loop — CLI (/dev/tty) + Telegram (headless/remote, extra: [telegram])

Apache-2.0 · built by Always Ready Allies LLC. Security contact: see SECURITY.md.

Download files

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

Source Distribution

warden_mcp-0.2.0.tar.gz (111.6 kB view details)

Uploaded Source

Built Distribution

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

warden_mcp-0.2.0-py3-none-any.whl (93.4 kB view details)

Uploaded Python 3

File details

Details for the file warden_mcp-0.2.0.tar.gz.

File metadata

  • Download URL: warden_mcp-0.2.0.tar.gz
  • Upload date:
  • Size: 111.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for warden_mcp-0.2.0.tar.gz
Algorithm Hash digest
SHA256 7c008e4e6b01d884861a25472d052b44f95be8bd3238646eca2670f99cfa8b44
MD5 d90052195429fcc31fa66d661a1a93c0
BLAKE2b-256 a40cf304a73c21866b0a371769007875162e62affb51e0d1c0047040f235c2a1

See more details on using hashes here.

File details

Details for the file warden_mcp-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: warden_mcp-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 93.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for warden_mcp-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2ad7c914a1ea9772a81dc3436f301663c4ee17491c8f947edc615b57bef7498f
MD5 1133ffa9d3c74da1f2270aed532e5cb4
BLAKE2b-256 a777b7c822d5e4ca1f2768dd46ad605266aa7f76ce213a8df12228f2f8562c90

See more details on using hashes here.

Release history Release notifications | RSS feed

0.2.1

2 files

This release

0.2.0 This release

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

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