mcp-shield
# mcp-shield
**Security primitives for the Model Context Protocol.**
The Blackwell Systems 2026-06 audit scanned 54 production MCP servers and found **20 bugs** in 9 of them. The 2026-03-05 MCP roadmap named audit trails, SSO, and machine-readable server discovery as the four blockers keeping MCP out of regulated enterprises. **mcp-shield** is the missing security layer — five drop-in primitives that address every bug class from the audit, MIT-licensed, stdlib-only, no SaaS dependency.
```bash
pip install mcp-shield
```
## Why this exists
If you're running an MCP server — yours or someone else's — you have four problems mcp-shield solves:
1. **Tool errors return as success.** `except E: return _format_error(e)` leaves FastMCP's `isError` flag unset, so the agent retries forever. MCPTox benchmark (arXiv:2508.14925) flags this across 26+ Python MCPs.
2. **No audit trail.** SOC2 procurement requires per-call records. Building one yourself is a Friday you'll never get back.
3. **Tool output can hijack the agent.** OWASP #1 LLM vulnerability (Context Poisoning, >100K sites hit in 2025). Tool descriptions and outputs are the attack surface.
4. **No input validation.** Malformed calls from the agent crash your handler with `KeyError`, `TypeError`, etc. — not a typed error the model can correct.
## The five primitives
| Primitive | Bug class | Drop-in usage |
|---|---|---|
| `shield_tool` decorator | 1 — isError-compliance | `@shield_tool(name="my_tool", schema={...})` |
| `audit_tool_call` | 3 — JSONL audit | `with audit_tool_call("my_tool", args): ...` |
| `validate_input` | 4-adj — JSON-schema input | `validate_input(args, schema={...})` |
| `sanitize_output` | 2 — prompt-injection scrub | `sanitize_output(text, strict=True)` |
| `require_scope` | 4 — OAuth 2.1 scope | `require_scope("admin")` |
Plus: a standalone MCP server exposing `shield_audit_tail`, `shield_audit_summary`, `shield_red_team`, `shield_scan_input`, `shield_patterns_list`, `shield_sanitize_preview`, `shield_version` — register it alongside any other MCP to inspect what's happening.
## Quick start (decorator)
```python
from mcp.server.fastmcp import FastMCP
from mcp_shield import shield_tool
mcp = FastMCP("my-server")
@mcp.tool()
@shield_tool(
name="search_things",
schema={
"type": "object",
"required": ["query"],
"properties": {"query": {"type": "string", "minLength": 1, "maxLength": 200}},
"additionalProperties": False,
},
sanitize_strict=False, # redact matched patterns; True raises
required_scopes="read",
)
async def search_things(query: str) -> str:
result = await upstream.search(query)
return json.dumps(result)
```
That's it. You now have:
- JSON-schema validation (rejects malformed calls with typed errors)
- JSONL audit log per call (stderr default, override with `MCP_SHIELD_AUDIT_LOG`)
- Output sanitization with 15 high-precision patterns from MCPTox + OWASP
- isError-compliance (FastMCP sets `isError: true` automatically)
- OAuth scope check
## Quick start (operational MCP server)
```bash
# Audit logs go to stderr by default
mcp-shield
# Or to a file
MCP_SHIELD_AUDIT_LOG=/var/log/mcp/audit.jsonl mcp-shield
# Or disable audit entirely (for unit tests)
MCP_SHIELD_AUDIT=0 mcp-shield
```
Then ask your MCP client: *"what was the error rate over the last hour?"* or *"run the red-team suite against my MCP."*
## What's in the box
```
src/mcp_shield/
├── __init__.py # public surface
├── audit.py # JSONL audit log (stdlib-only, fail-open, secret-redacting)
├── exceptions.py # typed exception hierarchy (ShieldError, ShieldAuthError, ...)
├── sanitize.py # prompt-injection scrubber (15 curated patterns)
├── server.py # standalone MCP server exposing ops tools
├── shield.py # @shield_tool decorator + ShieldedTool class + require_scope
└── validate.py # JSON-schema input validation (Draft 7 subset)
```
## Engineering standards
Every line of code in this repo follows patterns documented in the [engineering playbook](~/.mavis/agents/mavis/memory/engineering-playbook.md) — the same playbook used by hawksoft-mcp, ezyvet-mcp, practicepanther-mcp, and the rest of the sanjibani MCP portfolio.
- **ruff**: full rule set (E/F/W/I/N/UP/B/A/C4/DTZ/T20/PT/Q/RET/SIM/TID/ARG/PTH/ERA/PL/RUF)
- **mypy --strict**: clean
- **pytest**: 53 tests, all passing, covering every primitive + edge cases
- **py.typed**: ships the marker for downstream `mypy` to type-check us
- **stdlib-only**: audit + sanitize + validate need no extra deps; only `mcp[cli]`, `httpx`, `pydantic`, `structlog` for the wrapper
- **fail-open**: a broken audit sink never breaks the tool (SOC2 baseline)
- **JSON-RPC safe**: audit goes to stderr (or file), never stdout
## Cross-promo footer
If you ship an MCP server, drop the shield on it in 5 minutes. If you don't ship one and just need to harden the ones you use, add the operational MCP server to your fleet.
If you'd rather have someone build a custom MCP server (vertical SaaS, internal tool, anything with a REST/GraphQL/SOAP API), see the [engagement page](https://sanjibani.github.io/mcp-services/) — $25K / $60K / $120K+ tiers.
Other vertical MCPs in this portfolio:
- [hawksoft-mcp](https://github.com/sanjibani/hawksoft-mcp) — independent insurance AMS
- [open-dental-mcp](https://github.com/sanjibani/open-dental-mcp) — dental practice
- [ezyvet-mcp](https://github.com/sanjibani/ezyvet-mcp) — veterinary practice
- [jobber-mcp](https://github.com/sanjibani/jobber-mcp) — home service trades
- [practicepanther-mcp](https://github.com/sanjibani/practicepanther-mcp) — legal practice mgmt
## Maintainer
Sanjibani Choudhury <schoudhury1991@gmail.com> · [github.com/sanjibani](https://github.com/sanjibani)
TDQS
Scored across 7 tools
Each tool has a clearly distinct purpose: auditing (summary and tail), pattern management (list and test), sanitization preview, input validation, and version info. No overlap.
All tool names use snake_case and follow a verb_noun pattern (audit_summary, audit_tail, patterns_list, red_team, sanitize_preview, scan_input). Even 'version' fits as a simple noun command.
With 7 tools, the surface is well-scoped for a security/audit server. It covers auditing, pattern introspection, testing, preview, input validation, and version info without bloat.
Covers core workflows: auditing (summary + tail), pattern listing, red team testing, sanitization preview, and input validation. Minor gaps like dynamic pattern updates or configuration are absent but not critical for the stated purpose.