MCPSentry
The MCP bridge that audits your routes before exposing them to LLMs and blocks prompt-injection at runtime.
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/callfor 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 listingPOST /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:
- Auto-discovery β 13 Mealie routes β 13 MCP tools
- Pre-flight audit β runs before the server starts
- 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
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
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.
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.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
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.
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.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
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.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.