Install
$ agentstack add mcp-datascience-engineeringexperts-mcp-warden Open-source listing, not yet scanned by AgentStack. Follow the source repository for install instructions.
Security review
⚠ Flagged1 finding(s); flagged for manual review. · v0.1.0 How review works →
- • Prompt-injection patterns
- • Secret / credential exfiltration
- • Dangerous shell & filesystem operations
- • Untrusted network calls
- • Known-malicious package signatures
- high Pipes remote content directly into a shell (remote code execution).
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
mcp-warden
[](https://github.com/ernestprovo23/mcp-warden/actions/workflows/integrity-gate.yml) [](LICENSE) [](https://www.python.org/downloads/) [](https://github.com/ernestprovo23/mcp-warden/blob/main/action.yml) [](https://github.com/ernestprovo23/mcp-warden/releases)
mcp-warden is the lockfile and CI gate for stdio-transport MCP servers: it pins an MCP server's declared tool/resource/prompt surface into a signed warden.lock, then fails CI when that surface drifts from the approved baseline. v1 covers stdio-transport servers; HTTP/SSE transport is a documented v1.x roadmap item.
> ⚠️ Install mcp-warden-cli, not mcp-warden. The PyPI name mcp-warden is > an unrelated package by a different author — it is not this project. The > correct install is pip install mcp-warden-cli (the CLI command is still > mcp-warden). Or use the [GitHub Action](#github-action-one-step-drop-in) / a > git-pinned install.
If you already follow the published guidance — pin versions, hash tool definitions, alert on drift — mcp-warden is the deterministic tool that does it.
The mental model (analogy ladder):
package-lock.json/Cargo.lock— a committed, reproducible lock of what
you depend on. warden.lock is that, for an MCP server's declared surface.
gitleaksin CI — a deterministic, exit-non-zero gate wired into the
pipeline. mcp-warden check is that, for MCP surface drift (and ships the same SARIF → code-scanning integration).
Dependabot/ pin-then-review — a human approves an upstream change before
it lands. pin --approve + the drift gate force a human in the loop on any MCP rug-pull.
> Scope honesty — mcp-warden is an MCP supply-chain integrity gate, not a full > agent firewall. It verifies the declared surface returned by tools/list / > resources/list / prompts/list; it does not defend behavioral attacks > (T-BEHAVE) and makes no compliance/regulatory claim. The v0.3 guard proxy > adds runtime result inspection (ANSI/control escapes, echoed secrets, exfil > domains — deterministic, default-block), but definition-integrity is the core > job. Read the limits first: > [docs/THREAT_MODEL.md](docs/THREATMODEL.md), > [docs/THREAT_MODEL_V2.md](docs/THREATMODELV2.md), > [docs/GUARD_PROXY_V3.md](docs/GUARDPROXY_V3.md).
60-second quickstart
Copy-paste runnable against the fixtures shipped in this repo. Requires Python ≥ 3.11.
# 1. Install (from a clone of this repo)
uv venv .venv
uv pip install --python .venv/bin/python -e ".[dev]"
# 2. Pin a server's declared surface and approve it (TOFU baseline) -> writes the lock
.venv/bin/mcp-warden pin python tests/fixtures/clean_server.py \
--approve --approver you@example.com \
--lock warden.lock
# 3. Check the same surface against the lock -> exit 0 (no drift)
.venv/bin/mcp-warden check python tests/fixtures/clean_server.py --lock warden.lock
# 4. Prove the gate fires: a rug-pulled server drifts -> DRIFT DETECTED, exit 1
.venv/bin/mcp-warden check python tests/fixtures/mutated_server.py --lock warden.lock
Then wire it into CI with the official GitHub Action (point server-cmd at your server's launch argv, commit warden.lock):
# .github/workflows/mcp-integrity.yml
permissions:
contents: read
security-events: write # only needed when upload-sarif: true (the default)
jobs:
mcp-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ernestprovo23/mcp-warden@v0
with:
server-cmd: "node ./build/index.js"
lock: "warden.lock"
The Action runs check, fails the build on any drift, and (by default) uploads a SARIF report to GitHub code scanning. Full input table is in [GitHub Action](#github-action-one-step-drop-in) below.
Where mcp-warden fits — complements, not substitutes
MCP security splits into three different jobs that run at different times. They are complementary layers; running mcp-warden alongside a scanner and/or a gateway closes gaps none of them cover alone.
| Category | Example | When it runs | What it locks down | Use it when… | |----------|---------|--------------|--------------------|--------------| | Static tool-poisoning scanner | mcp-scan | pin-time / pre-flight | suspicious content in tool definitions (injection-style descriptions, known-bad patterns) | you want to catch a poisoned definition the first time you see it | | Runtime gateway / proxy | ContextForge, Lunar MCPX, TrueFoundry, Docker MCP Gateway | every live request | runtime mediation — auth, rate limits, request/response policy on calls in flight | you need to mediate or police live traffic between agent and server | | Lockfile + CI gate | mcp-warden | CI / pre-commit | drift — the declared surface changing after a human approved it (rug-pull / silent redefinition) | you want a reproducible, human-approved baseline that fails the build when the surface changes |
mcp-warden does not replace a scanner or a gateway — it adds the missing drift gate: a signed baseline plus a deterministic CI check that the surface you approved is the surface you still run. For the full, sourced breakdown of how these layers complement each other and when to use which, see the comparison page on the docs site.
Who it's for
Adoption compounds the way package-lock.json did — authors adopt, consumers benefit automatically — so the use cases are sequenced by leverage:
- MCP server author (flagship). Pin your own server's surface, commit
warden.lock,
fail any PR that alters it without re-approval, and ship the signed lock alongside releases as a badge of trust — you own the server + CI, so no auth/availability friction.
- Server consumer / app team. Pin a third-party server you depend on; CI (or the
pre-commit hook) fails when upstream silently redefines its surface — the core rug-pull defense.
- Security / platform engineer. Run the [Action](#github-action-one-step-drop-in)
across a fleet; SARIF → code scanning; signed locks = auditable human-approval evidence.
- Incident responder / auditor.
inspectan offline trace andwarden diffa suspect
lock against a known-good baseline — no live server required.
- Agent-framework integrator (post-launch). Enforce that only warden-locked servers
register in a LangGraph-style orchestrator — one integration locks an entire downstream ecosystem.
What it does
mcp-warden operates entirely on definitions — the (name, description, inputSchema) metadata returned by tools/list, resources/list, and prompts/list — never on runtime tool behavior or results.
| Threat class | Control | |--------------|---------| | Definition drift / rug-pull (MCP-DRIFT) | check re-captures and diffs the surface vs warden.lock; tool inputSchema changes are structurally classified (required dropped, enum widened/removed, type broadened, constraint relaxed, additionalProperties opened → WRD-DRIFT-SCHEMA-*) rather than flagged as one opaque change; any drift fails CI | | Dangerous capability surface (MCP-CAPSURF) | Deterministic WRD-CAP-* static checks (shell/exec, fs-write, fs-read, http, sql) | | Secret leakage in definitions (MCP-SECRET) | WRD-SEC-* regex + entropy checks; snippets are always redacted | | Unpinned supply-chain refs (MCP-SUPPLY) | WRD-SUP-* flags unpinned npx/uvx/pip, latest, and curl|sh launches | | Poisoned tool results (T-RESULT, v0.2/v0.3) | guard/inspect run the WRD-RES-* catalog on tool results: ANSI/control escapes, echoed secrets, exfil domains (deterministic BLOCK — default-on in v0.3), curated injection phrases (fuzzy MONITOR, opt-in) |
Reproducibility is the core guarantee: canonicalization is RFC 8785 (JCS) + SHA-256 (sha256:), so pin and check agree byte-for-byte. The v0.2 result-inspection catalog is defined once and run identically by guard (live) and inspect (offline).
Install
Requires Python ≥ 3.11.
> ⚠️ On PyPI the distribution name is mcp-warden-cli, not mcp-warden — > that name belongs to an unrelated package. The CLI command stays mcp-warden.
# from PyPI (distribution name `mcp-warden-cli`):
pip install mcp-warden-cli
# the CLI is then available as:
mcp-warden --help
# or from a clone of this repo (for development):
uv venv .venv
uv pip install --python .venv/bin/python -e ".[dev]"
.venv/bin/mcp-warden --help
Runtime dependencies: mcp (official MCP Python SDK), rfc8785, pydantic, typer, rich, pyyaml, anyio.
The pin / check CI demo
mcp-warden ships two fixture MCP servers under tests/fixtures/: a clean one and a mutated (rug-pulled) one. The end-to-end flow:
# 1. Pin the clean server's surface (TOFU baseline) -> writes warden.lock
.venv/bin/mcp-warden pin python tests/fixtures/clean_server.py \
--approve --approver ci-bot@example.invalid \
--sarif pin.sarif
# 2. Later, the upstream server is rug-pulled. Re-run check against it.
# (Same launch argv would be used in real CI; here we point at the mutated fixture.)
.venv/bin/mcp-warden check python tests/fixtures/mutated_server.py \
--sarif check.sarif
# -> prints DRIFT DETECTED, writes SARIF, EXITS NON-ZERO (fails the build)
check exits non-zero on any drift (added/removed/modified tool, capability change, server-identity change). Tool inputSchema changes are structurally diffed: each security-relevant mutation is reported per-fact and deterministically classified by severity (docs/WARDEN_LOCK_SCHEMA.md §6.2). A normalized schema skeleton is stored in the lock (schema_version 3); pre-skeleton (v1) locks fall back to a single high-severity schema-modified until re-pinned. The SARIF report (ruleId == the WRD-* / WRD-DRIFT-* check ID) uploads straight to GitHub code scanning.
GitHub Action (one-step drop-in)
The fastest way to add the integrity gate is the official reusable action:
# .github/workflows/mcp-integrity.yml
permissions:
contents: read
security-events: write # only needed when upload-sarif: true (the default)
jobs:
mcp-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ernestprovo23/mcp-warden@v0
with:
server-cmd: "node ./build/index.js"
lock: "warden.lock"
# upload-sarif: "false" # uncomment for private repos without GHAS
The action installs mcp-warden from the exact @ref you pin, runs check, uploads the SARIF report to GitHub code scanning (optional), and surfaces the raw exit code (0 = clean / 1 = drift / 2 = error) as an output for downstream steps. All runtime dependencies are hash-locked in action/requirements.lock so no transitive packages are fetched unpinned.
| Input | Default | Notes | |-------|---------|-------| | server-cmd | (required) | Whitespace-separated argv string (e.g. node ./build/index.js). No quoted arguments, no shell metacharacters (;, \|, &, $, ` `, \, , (, ), {, }, ', "). The guard step rejects any of these before expansion. | | lock | warden.lock | Baseline lock path (relative to working-directory) | | sarif | mcp-warden.sarif | SARIF output path | | upload-sarif | true | Set false for repos without GitHub Advanced Security | | category | mcp-warden | Code-scanning category; use distinct values per server | | python-version | 3.11 | Python version to use (>= 3.11 required) | | timeout | 30 | Capture timeout (seconds) | | working-directory | .` | Working directory for the check |
Outputs: exit-code (0/1/2), sarif (resolved absolute path).
> Set upload-sarif: false for fork pull requests or private repos without > GitHub Advanced Security — the security-events: write permission is not > available in those contexts.
Typical multi-step pattern (manual install)
- name: MCP integrity gate
run: |
.venv/bin/mcp-warden check node ./build/index.js --sarif warden.sarif
- name: Upload SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: warden.sarif
CI usage — drop-in gate for your own repo
Three steps to add mcp-warden as a CI integrity gate:
1. Pin once (run locally, commit the result):
pip install mcp-warden-cli # PyPI dist name is `mcp-warden-cli`; the command is `mcp-warden`
# Pin your server and record an approval
mcp-warden pin node ./build/index.js \
--approve --approver you@example.com \
--lock warden.lock
git add warden.lock && git commit -m "chore: pin MCP surface baseline"
2. Add the check step to your workflow (.github/workflows/integrity-gate.yml):
- name: Install mcp-warden
run: pip install mcp-warden-cli # PyPI dist `mcp-warden-cli`; CLI command `mcp-warden`
- name: MCP integrity gate (pass path — exits 0 when surface matches lock)
run: |
mcp-warden check node ./build/index.js \
--lock warden.lock \
--sarif warden.sarif
- name: Upload SARIF
if: always()
uses: actions/upload-artifact@v6
with:
name: mcp-warden-sarif
path: warden.sarif
3. On any upstream rug-pull, mcp-warden check exits non-zero and the build fails before the drifted server reaches your agents. Re-pin only after a human reviews and approves the new surface.
> This repo ships a live demo of this pattern in > [.github/workflows/integrity-gate.yml](.github/workflows/integrity-gate.yml): > the "pass path" step checks the clean fixture (exits 0) and the "blocking proof" > step checks the mutated fixture (exits 1, inverted to green) to show both sides > of the gate on every CI run.
pre-commit hook — the local pre-CI gate
mcp-warden ships a pre-commit hook so the same drift verdict runs locally on every commit, catching a rug-pulled MCP surface before it ever reaches CI. The hook reuses the identical capture → checks → drift path as mcp-warden check, so a local pass/fail can never disagree with CI.
Add this to your .pre-commit-config.yaml (a complete, copy-pasteable example):
repos:
- repo: https://github.com/ernestprovo23/mcp-warden
rev: v1.0.1 # pin to a release tag (supply-chain hygiene)
hooks:
- id: mcp-warden-check
# Everything after `--` is your MCP server launch argv.
# The `--lock` path is resolved relative to your git repo root.
args: [--lock, warden.lock, --, node, ./build/index.js]
Then pre-commit install once. The hook will re-capture your server's surface on every commit and block the commit on drift (exit 1) until you review and re-pin.
The -- separator (required)
pre-commit is file-triggered, but mcp-warden check takes an MCP server launch argv, not staged files (the hook sets pass_filenames: false). You tell the hook where your server command begins with the -- separator: everything after -- is launched as the server. Without it the hook exits 2 with guidance.
Behavior (clean / drift / server-unavailable)
| Situation | Default (non-strict) | --strict | |-----------|----------------------|------------| | Surface matches warden.lock | exit 0 (commit proceeds) | exit 0 | | Drift vs warden.lock | exit 1 (commit blocked) | exit 1 (commit blocked) | | warden.lock missing / invalid | exit 2 (commit blocked) | exit 2 | | Server can't spawn / times out | exit 0 + stderr WARNING (commit proceeds) | exit 2 (commit blocked) |
The default tolerates a locally unspawnable server (a teammate without the right runtime installed should not be blocked from committing) — drift always blocks in both modes, only infra-f
…
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: DataScience-EngineeringExperts
- Source: DataScience-EngineeringExperts/mcp-warden
- License: MIT
- Homepage: https://datascience-engineeringexperts.github.io/mcp-warden/
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.