MCPSentry

MCPSentry

The MCP bridge that audits your routes before exposing them to LLMs and blocks prompt-injection at runtime.

Category
Visit Server

README

<h1 align="center">πŸ›‘οΈ MCPSentry</h1>

<p align="center"> <strong>The MCP bridge that audits your routes before exposing them to LLMs β€” and blocks prompt-injection at runtime.</strong><br/> <em>One line to expose. One line to verify. One line to guard.</em> </p>

<p align="center"> <a href="https://pypi.org/project/mcpsentry/"><img src="https://img.shields.io/pypi/v/mcpsentry?color=blue&label=PyPI" alt="PyPI"></a> <a href="https://github.com/miloudbelarebia/mcpsentry/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-MIT-green.svg" alt="License"></a> <a href="https://github.com/miloudbelarebia/mcpsentry/stargazers"><img src="https://img.shields.io/github/stars/miloudbelarebia/mcpsentry?style=social" alt="Stars"></a> </p>


from fastapi import FastAPI
from mcpsentry import MCPSentry

app = FastAPI()
# ... your existing routes ...

bridge = MCPSentry(app)                    # Your app now speaks MCP.

report = bridge.audit()                    # Pre-flight security audit.
if report.has_blockers():
    report.print_text()                    # πŸ”΄ CRITICAL: /api/admin exposed, /api/auth/login exposed…
    raise SystemExit(1)

bridge.enable_guardrails(policy="block")   # Runtime prompt-injection blocking.

MCPSentry = a one-line FastAPI β†’ MCP bridge plus a pre-flight security auditor plus a runtime guardrail that scans every tools/call for prompt-injection. Because handing an LLM root access to your API by accident is no longer hypothetical.


Why MCPSentry exists

A FastAPI β†’ MCP bridge alone isn't enough. The hard problem isn't exposing routes β€” it's making sure you only expose the routes you meant to.

When LLMs become callers of your API, three things go wrong silently:

Risk What happens MCPSentry catches it
Admin endpoints exposed /api/admin/users/delete becomes an MCP tool the LLM can call πŸ”΄ CRITICAL β€” refuses to start by default
PII leaks in responses /api/users/me returns email, phone, ssn β€” now in LLM context 🟠 HIGH β€” flags PII-named fields
Auth flows accessible to LLM /api/auth/login callable with arbitrary credentials πŸ”΄ CRITICAL β€” refuses to start
Missing docstrings LLM guesses what each tool does β†’ calls the wrong one 🟠 HIGH β€” fail the audit
Untyped params Path param is str, LLM sends "; rm -rf /" πŸ”΅ LOW β€” flag for explicit typing
Destructive DELETE/PUT/PATCH LLM mutates data without confirmation 🟑 MEDIUM β€” informational

Other libraries give you a bridge. MCPSentry gives you a bridge and a security checklist that fails the build if you got it wrong.


Quick Start

pip install mcpsentry
from fastapi import FastAPI
from mcpsentry import MCPSentry

app = FastAPI(title="My App")

@app.get("/api/users/{user_id}")
async def get_user(user_id: int):
    """Get a user by their ID."""
    return {"id": user_id, "name": "Alice"}

bridge = MCPSentry(app)            # Auto-discovers routes, mounts /mcp
print(bridge.summary())

# Always audit before deploying
report = bridge.audit()
report.print_text()

if report.has_blockers():
    raise SystemExit(1)

Your app now exposes:

  • GET /mcp β€” Server info and tool listing
  • POST /mcp β€” MCP JSON-RPC endpoint (Streamable HTTP transport)

Any MCP client (Claude, ChatGPT, Gemini, Cursor, Codex) can connect.


The audit, explained

bridge.audit() walks every exposed tool and runs 7 checks. Sample output:

πŸ›‘οΈ  MCPSentry audit report
   13 tools from 13 routes
   πŸ”΄ 2 critical Β· 🟠 4 high Β· 🟑 3 medium Β· πŸ”΅ 1 low

   πŸ”΄ [CRITICAL] POST   /api/auth/login  β€”  Authentication endpoint exposed to LLM clients
      ↳ Add '/api/auth/login' to exclude_paths
   πŸ”΄ [CRITICAL] DELETE /api/admin/users/{user_id}  β€”  Admin / internal endpoint exposed to LLM clients
      ↳ Exclude this route from MCP exposure
   🟠 [HIGH    ] GET    /api/users/me  β€”  Response may leak PII fields: email, phone, address
      ↳ Mask PII before returning, or restrict this route from MCP exposure
   🟠 [HIGH    ] POST   /api/internal/run  β€”  No docstring β€” an LLM will guess this tool's purpose
      ↳ Add a clear docstring or `summary=` to the route decorator
   🟑 [MEDIUM  ] DELETE /api/recipes/{recipe_id}  β€”  Destructive DELETE β€” an LLM call can mutate/delete data
      ↳ Document the consequences in the docstring; consider requiring confirmation
   πŸ”΅ [LOW     ] GET    /api/search  β€”  3 parameters fall back to 'string' β€” LLMs may send malformed inputs
      ↳ Annotate parameters with explicit types (int, bool, list[str], Pydantic models)

Programmatic use

report = bridge.audit()

# Counts
report.critical_count           # β†’ 2
report.high_count               # β†’ 4

# Structured access (CI/CD, dashboards, reporting)
import json
print(json.dumps(report.to_dict(), indent=2))

# Iterate
for finding in report.findings:
    if finding.severity == Severity.CRITICAL:
        send_to_security_team(finding)

Use it in CI

# .github/workflows/mcp-audit.yml
- run: python -c "from myapp import bridge; r = bridge.audit(); r.print_text(); exit(1 if r.has_blockers() else 0)"

🎯 Real-world findings β€” see case-studies/

We ran bridge.audit() against the official examples of tadata-org/fastapi_mcp (the most popular FastAPIβ†’MCP library, 11.9k ⭐).

Example πŸ”΄ Crit 🟠 High 🟑 Med πŸ”΅ Low Verdict
01_basic_usage_example 0 0 2 0 βœ…
02_full_schema_description 0 0 2 0 βœ…
04_separate_server 0 0 2 0 βœ…
08_auth_token_passthrough 0 1 2 0 βœ…
09_auth_example_auth0 3 6 0 1 ❌ BLOCK

Headline: the official Auth0 example exposes /oauth/authorize, /oauth/register, and /.well-known/oauth-authorization-server to LLM clients. MCPSentry catches all three and refuses to start the server. Full breakdown in case-studies/01-fastapi-mcp-examples.md.


Advanced configuration

bridge = MCPSentry(
    app,
    name="My Recipe Manager",
    description="Search recipes, plan meals",
    include_paths=["/api/*"],                          # Only expose API routes
    exclude_paths=["/api/admin/*", "/api/auth/*"],     # Hide sensitive endpoints
    max_tools=30,                                      # Limit context window usage
    mcp_endpoint="/mcp",
)

# Refine specific tools for better LLM understanding
bridge.tool("/api/recipes/search", description="Find recipes by name or ingredients")
bridge.exclude("/api/internal/*")

Live demo: Mealie Recipe Manager

The examples/mealie_demo/ directory contains a working demo that simulates Mealie (11.5K ⭐), a popular self-hosted recipe manager built with FastAPI.

git clone https://github.com/miloudbelarebia/mcpsentry
cd mcpsentry
pip install -e .
python examples/mealie_demo/app.py

What you'll see:

  1. Auto-discovery β€” 13 Mealie routes β†’ 13 MCP tools
  2. Pre-flight audit β€” runs before the server starts
  3. Server starts at http://localhost:9925/mcp (only if audit passes)

Connect from Claude Desktop:

{
  "mcpServers": {
    "mealie": { "url": "http://localhost:9925/mcp" }
  }
}

Then ask Claude: "What's for dinner tonight?" β€” it'll search your recipes, propose a meal plan, build a shopping list.


How it works

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  Your FastAPI app                    β”‚
β”‚                                                     β”‚
β”‚   @app.get("/api/recipes")     ← Existing routes    β”‚
β”‚   @app.post("/api/recipes")                         β”‚
β”‚   @app.delete("/api/admin/...")  ← BAD              β”‚
β”‚                                                     β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚   β”‚            MCPSentry (embedded)              β”‚   β”‚
β”‚   β”‚                                             β”‚   β”‚
β”‚   β”‚  1. Introspect routes at startup            β”‚   β”‚
β”‚   β”‚  2. Extract Pydantic schemas + type hints   β”‚   β”‚
β”‚   β”‚  3. ⚑ Pre-flight security audit             β”‚   β”‚
β”‚   β”‚     ↳ refuse to start on CRITICAL findings  β”‚   β”‚
β”‚   β”‚  4. Generate MCP tool definitions           β”‚   β”‚
β”‚   β”‚  5. Serve MCP JSON-RPC on /mcp              β”‚   β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                     β”‚
β”‚   POST /mcp  ← LLM clients connect here             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚  Claude   β”‚ β”‚  ChatGPT  β”‚ β”‚  Gemini   β”‚ β”‚ Cursor  β”‚
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Comparison with other tools

MCPSentry fastapi_mcp FastMCP from_fastapi() openapi-mcp-server
1-line setup βœ… βœ… βœ… ❌ (CLI + config)
Embedded (no separate process) βœ… βœ… βœ… ❌
Auto-discovers routes (no OpenAPI spec) βœ… βœ… βœ… ❌
Pre-flight security audit βœ… ❌ ❌ ❌
Refuses to start on CRITICAL findings βœ… ❌ ❌ ❌
Runtime prompt-injection detection βœ… ❌ ❌ ❌
Block / alert / log policy on tools/call βœ… ❌ ❌ ❌
Multi-framework (FastAPI + Flask + Django) 🚧 v0.4 ❌ partial (OpenAPI) spec-based

If you don't care about auditing what you expose or what comes back through it, fastapi_mcp and FastMCP are fine. If you do, MCPSentry is the only one that fails your build when you got it wrong β€” and your runtime when something looks off.


Runtime guardrails (v0.3)

The audit happens once, at startup. The guardrail runs on every single tools/call request while the server is alive.

It scans the call's arguments (recursively, in dicts and lists) against a curated catalogue of prompt-injection patterns:

Confidence Examples of what gets caught
πŸ”΄ HIGH ignore previous instructions, you are now …, developer/admin/jailbreak mode, chat-template control tokens (<|im_start|>), [[system]] markers
🟠 MEDIUM system prompt, act as …, pretend to be …, "reveal your instructions", "repeat everything above"
πŸ”΅ LOW exfiltration verbs (send your tokens to …), <script> payloads, embedded curl/wget https://…, base64 obfuscation

Aggregate decision:

  • any HIGH match β†’ BLOCK
  • 2+ MEDIUM matches β†’ BLOCK
  • 1 MEDIUM or LOW β†’ WARN
  • nothing β†’ ALLOW

Enable in one line

bridge = MCPSentry(app)
bridge.audit()                         # pre-flight
bridge.enable_guardrails(policy="block")   # runtime

Three policies, your call

bridge.enable_guardrails(policy="block")   # refuse the call (default)
bridge.enable_guardrails(policy="alert")   # let it through, log loudly + on_alert callback
bridge.enable_guardrails(policy="log")     # shadow mode β€” just observe

Plug your alerting in

def to_security_team(decision):
    slack.post(f"⚠️ MCPSentry blocked {decision.tool_name}: {decision.reason}")

bridge.enable_guardrails(policy="block", on_block=to_security_team)

Inspect what happened

bridge.guardrail.stats()
# β†’ {"total": 1284, "blocked": 7, "alerted": 23, "clean": 1254}

for entry in bridge.guardrail.recent(10):
    print(entry.tool_name, entry.decision.allowed, entry.decision.reason)

What an MCP client sees when blocked:

{
  "isError": true,
  "content": [{
    "type": "text",
    "text": "πŸ›‘οΈ Blocked by MCPSentry runtime guardrail.\nReason: Prompt-injection detected (HIGH:1 MEDIUM:0 LOW:0)\nTop matches: high instruction_override @ arguments.query"
  }]
}

Roadmap

  • [x] v0.1 β€” FastAPI introspection, MCP Streamable HTTP transport, examples
  • [x] v0.2 β€” bridge.audit() with 7 security checks, severity levels, JSON/text output
  • [x] v0.3 β€” Runtime guardrails: prompt-injection detection + block/alert/log policy + structured callbacks
  • [ ] v0.4 β€” Multi-framework: Flask + Django adapters (the real white space)
  • [ ] v0.5 β€” Custom audit & guardrail rules (decorators / config / plugins)
  • [ ] v0.6 β€” OAuth2 / API key auth passthrough, stdio transport
  • [ ] v1.0 β€” Smart tool grouping (collapse CRUD into fewer tools), policy-as-code

Contributing

git clone https://github.com/miloudbelarebia/mcpsentry
cd mcpsentry
pip install -e ".[dev]"
pytest

See CONTRIBUTING.md for guidelines.


License

MIT β€” see LICENSE.


<p align="center"> Built with ❀️ by <a href="https://github.com/miloudbelarebia">Miloud Belarebia</a><br/> <em>Securing the agentic web, one audit at a time.</em> </p>

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured