sanjibani

mcp-shield

Community sanjibani
Updated

Security primitives for MCP servers — isError-compliance, JSONL audit, JSON-schema input validation, output sanitization, OAuth 2.1 scope enforcement. MIT, stdlib-only.

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.

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)

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)

# 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 — 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 — $25K / $60K / $120K+ tiers.

Other vertical MCPs in this portfolio:

Maintainer

Sanjibani Choudhury [email protected] · github.com/sanjibani

MCP Server · Populars

MCP Server · New

    Cassette-Editor

    Oh My Cassette: Chat Your Raw Clips Into a Finished Cut

    你的随身 AI 剪辑搭档 | Pocket AI co-editor for video montage — AI video editing plugin & MCP server for Claude Code, Codex, Hermes & OpenCode

    Community Cassette-Editor
    trendsmcp-ai

    Trends MCP

    MCP server for live trend data. Query Google Search, YouTube, TikTok, Reddit, Amazon, Wikipedia, News sentiment, Web Traffic, App Downloads, Steam, npm and more. Works with Claude, Cursor, VS Code, GitHub Copilot, ChatGPT, Windsurf, Cline, Raycast and any MCP-compatible.

    Community trendsmcp-ai
    jacob-bd

    Gemini Notebook (formerly Google NotebookLM) CLI & MCP Server

    Programmatic access to Gemini Notebook - via command-line interface (CLI), Model Context Protocol (MCP) server, and AI agent skills.

    Community jacob-bd
    PxyUp

    Fitter — web data for AI agents

    New way for collect information from the API's/Websites

    Community PxyUp
    kayhendriksen

    foehn

    Download MeteoSwiss Open Government Data — weather stations, radar, hail, forecasts and climate series — via Python API, CLI, or MCP server, as DataFrames, Parquet, xarray Datasets or Zarr stores

    Community kayhendriksen