MCPSentry
Provides security auditing for FastAPI apps using Auth0 authentication, catching exposed auth endpoints and PII leaks.
Planned support for bridging Django views to MCP tools, extending MCPSentry to Django applications.
Bridges FastAPI routes to MCP tools, enabling LLMs to interact with any FastAPI-based API.
Planned support for bridging Flask routes to MCP tools, extending MCPSentry to Flask applications.
Demo integration with Mealie recipe manager, allowing LLMs to search recipes, plan meals, and build shopping lists via MCP tools.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@MCPSentryaudit my FastAPI routes for security issues"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
from fastapi import FastAPI
from mcp_rampart import MCPRampart
app = FastAPI()
# ... your existing routes ...
rampart = MCPRampart(app) # 1. Speak MCP.
report = rampart.audit() # 2. Audit what you'd expose.
if report.has_blockers():
report.print_text(); raise SystemExit(1)
rampart.enable_guardrails(policy="block") # 3. Block prompt-injection at runtime.TL;DR. MCP security tooling is fragmenting into layers. mcp-rampart is the only library that lives inside your MCP server — auditing the routes you're about to expose and scanning the arguments of every
tools/callrequest. Everything else (gateways, firewalls, config scanners) lives elsewhere on the wire.
The 4 layers of MCP security
MCP went from "experiment" to 97M+ installs per month in 2026. Security tooling caught up only recently, and most of it solves a different problem than the one you have. Here's the map:
┌─────────────────────────────────────────────────────────────────┐
│ Layer 1 — The LLM itself (Claude, GPT, Gemini) │
│ Worry: hallucination, jailbreaks at the model level │
│ → out of scope for everyone — model provider's problem │
└──────────────────────┬──────────────────────────────────────────┘
│
▼ (JSON-RPC over MCP transport)
┌─────────────────────────────────────────────────────────────────┐
│ Layer 2 — The MCP CLIENT (Claude Desktop, Cursor, agents) │
│ Worry: the LLM calls something risky or exfiltrates data │
│ Tools: pipelock, mcp-firewall, SecretiveShell/MCP-Bridge │
└──────────────────────┬──────────────────────────────────────────┘
│
▼ (HTTP / SSE)
┌─────────────────────────────────────────────────────────────────┐
│ Layer 3 — The GATEWAY / proxy in front of the MCP server │
│ Worry: who's allowed to talk to this server, with what auth │
│ Tools: apache/casbin-gateway, hyprmcp/mcp-gateway │
└──────────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Layer 4 — The MCP SERVER itself ← 🛡️ mcp-rampart │
│ Worry: did I expose dangerous routes? is an injection hiding │
│ inside the arguments of every tools/call? │
│ Tools: mcp-rampart (this project) │
└──────────────────────┬──────────────────────────────────────────┘
│
▼ (which servers are even installed?)
┌─────────────────────────────────────────────────────────────────┐
│ Layer 5 — The USER's MCP config (~/.mcp.json, etc.) │
│ Worry: am I installing a malicious server on my machine │
│ Tools: apisec-inc/mcp-audit, ModelContextProtocol-Security/ │
│ mcpserver-audit │
└─────────────────────────────────────────────────────────────────┘Layer | Question it answers | Representative tool |
1 | "Is the model itself safe?" | (model provider) |
2 | "Is my agent leaking / calling something risky?" | pipelock (583⭐) |
3 | "Who's allowed to talk to my server, with what auth?" | casbin-gateway (559⭐), hyprmcp/mcp-gateway (92⭐) |
4 | "Did I just hand a language model access to my admin endpoints? Is an injection sneaking into the args of every call?" | mcp-rampart |
5 | "Is this MCP server I'm installing actually safe?" | apisec mcp-audit (149⭐), mcpserver-audit (16⭐) |
You probably need more than one layer. mcp-rampart is the only library that operates at layer 4 — the layer that solves the MCP-server author's problem rather than the operator's or the user's.
Why "framework-aware", not "MCP-generic"
You'll notice every tool at layers 2, 3, and 5 is framework-agnostic — they intercept the wire (HTTP, JSON-RPC, config files) and don't care what's behind. That works for them because they don't need to.
mcp-rampart needs to look behind. The pre-flight audit literally cannot exist as a proxy:
What mcp-rampart can see | Why (it's installed in the app) |
| reads |
Pydantic response models declaring | introspects |
Missing docstrings on tool handlers | reads |
Untyped parameters that fall back to | reads |
Path patterns that look like | pattern-matches |
A proxy at layer 3 sees POST /mcp {"method":"tools/call","name":"delete_user","args":{...}}. It does not see @app.delete("/api/admin/users/{user_id}") three steps upstream. So it can't tell you "you're about to expose your admin to an LLM" — it can only tell you "someone just called delete_user".
The trade-off: mcp-rampart is currently FastAPI-only. We're paying that price on purpose for now, because deep introspection is what makes the audit valuable. Node.js and Flask/Django are next on the roadmap.
Where mcp-rampart is uniquely positioned
Five concrete cells where mcp-rampart is the only ✅:
mcp-rampart | pipelock | casbin-gw | apisec mcp-audit | hyprmcp | |
Runs inside your FastAPI app (no extra process) | ✅ | ❌ | ❌ | ❌ | ❌ |
Audits the routes you are about to expose (not someone else's) | ✅ | ❌ | ❌ | ❌ | ❌ |
Refuses to start the server on CRITICAL findings | ✅ | ❌ | ❌ | ❌ | ❌ |
Prompt-injection detection on every | ✅ | partial | ❌ | ❌ | ❌ |
Three-policy model ( | ✅ | ❌ | ❌ | ❌ | ❌ |
Different shape, different question, different price tag.
Quick start
pip install mcp-rampartfrom fastapi import FastAPI
from mcp_rampart import MCPRampart
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"}
rampart = MCPRampart(app) # auto-discovers routes, mounts /mcp
print(rampart.summary())
# Pre-flight audit — refuses to start the server on CRITICAL findings
report = rampart.audit()
report.print_text()
if report.has_blockers():
raise SystemExit(1)
# Runtime guardrail — every incoming tools/call is scanned
rampart.enable_guardrails(policy="block")Your app now exposes:
GET /mcp— server info and tool listingPOST /mcp— MCP JSON-RPC endpoint (Streamable HTTP transport)
Any MCP client (Claude Desktop, ChatGPT, Gemini, Cursor, Codex) can connect.
The pre-flight audit, in detail
rampart.audit() walks every exposed tool and runs 8 checks. Each finding gets a severity tag, a suggestion, and a category code you can match in CI.
Severity | Check | Triggers when… |
🔴 CRITICAL |
| route path matches |
🔴 CRITICAL |
| route path matches |
🟠 HIGH |
| no description → LLM will guess and call the wrong tool |
🟠 HIGH |
| parameter name contains |
🟠 HIGH |
| response schema declares fields like |
🟡 MEDIUM |
|
|
🔵 LOW |
| 3+ parameters falling back to |
🔵 LOW |
|
|
Sample output on a deliberately bad app:
🛡️ MCPRampart 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
…Use it in CI:
- run: python -c "from myapp import rampart; r = rampart.audit(); r.print_text(); exit(1 if r.has_blockers() else 0)"The runtime guardrail, in detail
The audit happens once, at startup. The guardrail runs forever — on every tools/call request.
It scans the call's arguments (recursively, in dicts and lists) against a curated catalogue of prompt-injection patterns:
Confidence | What gets caught |
🔴 HIGH |
|
🟠 MEDIUM |
|
🔵 LOW | exfiltration verbs ( |
Aggregate decision:
any HIGH match → BLOCK
2+ MEDIUM matches → BLOCK
1 MEDIUM or LOW → WARN (allowed, logged)
nothing → ALLOW
Enable in one line
rampart.enable_guardrails(policy="block") # default
rampart.enable_guardrails(policy="alert") # let through, log loudly, call on_alert
rampart.enable_guardrails(policy="log") # observability / shadow modePlug your alerting in
def to_security_team(decision):
slack.post(f"⚠️ mcp-rampart blocked {decision.tool_name}: {decision.reason}")
rampart.enable_guardrails(policy="block", on_block=to_security_team)Inspect what happened
rampart.guardrail.stats()
# → {"total": 1284, "blocked": 7, "alerted": 23, "clean": 1254}
for entry in rampart.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 MCPRampart runtime guardrail.\nReason: Prompt-injection detected (HIGH:1)\nTop matches: high instruction_override @ arguments.query"
}]
}🎯 Real-world findings — see case-studies/
We ran rampart.audit() against the official examples of tadata-org/fastapi_mcp (the most popular FastAPI→MCP library, 11.9k ⭐):
Example | 🔴 Crit | 🟠 High | 🟡 Med | 🔵 Low | Verdict |
| 0 | 0 | 2 | 0 | ✅ |
| 0 | 0 | 2 | 0 | ✅ |
| 0 | 0 | 2 | 0 | ✅ |
| 0 | 1 | 2 | 0 | ✅ |
| 3 | 6 | 0 | 1 | ❌ BLOCK |
Headline: the official Auth0 example exposes /oauth/authorize, /oauth/register, and /.well-known/oauth-authorization-server to LLM clients. mcp-rampart catches all three and refuses to start the server. Full breakdown in case-studies/01-fastapi-mcp-examples.md.
How it works
┌─────────────────────────────────────────────────────┐
│ Your FastAPI app │
│ │
│ @app.get("/api/recipes") ← Existing routes │
│ @app.post("/api/recipes") │
│ @app.delete("/api/admin/...") ← BAD │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ mcp-rampart (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. Mount JSON-RPC at /mcp │ │
│ │ 6. 🛡️ Scan every tools/call for injection │ │
│ │ ↳ block / alert / log per policy │ │
│ └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
│
▼
┌───────────┐ ┌───────────┐ ┌───────────┐ ┌─────────┐
│ Claude │ │ ChatGPT │ │ Gemini │ │ Cursor │
└───────────┘ └───────────┘ └───────────┘ └─────────┘Roadmap
v0.1 — FastAPI introspection, MCP Streamable HTTP transport, examples
v0.2 —
rampart.audit()with 7 security checks, severity levels, JSON/text outputv0.3 — Runtime guardrails: prompt-injection detection + block/alert/log policy + structured callbacks
v0.4 — 56-test pytest suite, GitHub Actions CI (py 3.10/3.11/3.12 + ruff + build), SECURITY.md, +1 audit check (
WILDCARD_RESPONSE), +11 injection patterns (27 total: 10 HIGH / 8 MEDIUM / 9 LOW), issue & PR templates, FUNDINGv0.5 — Node.js / TypeScript port (
mcp-rampart-jsfor Hono / Express / Fastify). Half of new MCP servers in 2026 ship in JS.v0.6 — Flask + Django adapters (the rest of the Python web ecosystem)
v0.7 — Custom audit & guardrail rules (decorators / config / plugins) + tunable confidence thresholds
v0.8 — Auth passthrough (OAuth2 / API keys / JWT), stdio transport
v1.0 — Smart tool grouping (collapse CRUD into fewer tools), policy-as-code, OpenAPI/Asyncapi spec ingestion
FAQ
Why not just be a generic MCP proxy that works with any framework? Because the audit needs to read your code — Pydantic models, decorators, type hints, docstrings. A proxy on the wire can't see those. See Why framework-aware.
Is this the same as pipelock / casbin-gateway / hyprmcp / apisec mcp-audit? No. They live at layers 2, 3, and 5. mcp-rampart lives at layer 4. See The 4 layers of MCP security.
Do I still need a gateway / firewall if I use mcp-rampart? Probably yes. mcp-rampart catches code-side issues and runtime injection. A gateway adds auth + rate-limiting + network policy. They're complementary.
What happens if mcp-rampart blocks a legitimate call?
The MCP client receives an isError: true response with the diagnostic in the response body. Switch to policy="alert" while you tune patterns. You can also bypass per-route with rampart.exclude(...).
Can I add my own rules?
Custom rules land in v0.6. Until then, subclass Auditor or InjectionDetector and pass it via custom_detector=.
Contributing
git clone https://github.com/miloudbelarebia/mcp-rampart
cd mcp-rampart
pip install -e ".[dev]"
pytestSee CONTRIBUTING.md for guidelines.
License
MIT — see LICENSE.
This server cannot be installed
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
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/miloudbelarebia/mcp-rampart'
If you have feedback or need assistance with the MCP directory API, please join our Discord server