Skip to main content
Glama
sanjibani

mcp-shield

by sanjibani

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

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 schoudhury1991@gmail.com · github.com/sanjibani

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sanjibani/mcp-shield'

If you have feedback or need assistance with the MCP directory API, please join our Discord server