Security toolkit for FastAPI-based MCP servers โ pre-flight audit + runtime prompt-injection guardrail.
Project description
๐ก๏ธ MCPRampart
Security for the FastAPI apps you expose to LLMs via MCP.
Pre-flight audit. Runtime prompt-injection guardrail. One package.
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.
Why this exists
MCP has gone from "interesting experiment" to 97M+ installs per month in 2026. Anthropic, OpenAI, Google, Cursor, Codex, Microsoft โ every major agent ships MCP support, and the Linux Foundation now stewards the protocol. The dev tooling around it has scaled fast.
The security tooling around it has not.
Every FastAPI app shipped as an MCP server is one careless include_paths=["/*"] away from handing a language model:
- its admin endpoints,
- its auth/OAuth flows,
- the columns of its user table,
- the verbs that mutate data.
And once it's live, every single tools/call request is untrusted input โ written by a model that may have been told to "ignore previous instructions" two turns ago.
MCPRampart is two things in one package, designed to make those two failure modes hard to ignore:
- A pre-flight
audit()that walks every route you'd expose and refuses to start the server when something looks dangerous. - A runtime
Guardrailthat scans the arguments of everytools/callagainst a curated prompt-injection pattern catalogue and blocks the call before your handler runs.
You don't have to integrate three libraries, write your own regex layer, or stand up a separate proxy. It's pip install mcp-rampart and three lines of code.
Quick start
pip install mcp-rampart
from 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 7 checks. Each finding gets a severity tag, a suggestion, and a category code you can match in CI.
| Severity | Check | Triggers whenโฆ |
|---|---|---|
| ๐ด CRITICAL | EXPOSED_AUTH |
route path matches /auth/, /login, /token, /oauth, โฆ |
| ๐ด CRITICAL | EXPOSED_ADMIN |
route path matches /admin/, /internal/, /debug/, โฆ |
| ๐ HIGH | MISSING_DOCSTRING |
no description โ LLM will guess and call the wrong tool |
| ๐ HIGH | SENSITIVE_PARAM_NAME |
parameter name contains password, token, api_key, โฆ |
| ๐ HIGH | PII_IN_RESPONSE |
response schema declares fields like email, phone, ssn, โฆ |
| ๐ก MEDIUM | DESTRUCTIVE_METHOD |
DELETE / PUT / PATCH exposed without explicit consent flow |
| ๐ต LOW | UNTYPED_PARAMETER |
3+ parameters falling back to str โ LLMs may send malformed inputs |
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 | ignore previous instructions, you are now โฆ, developer/admin/jailbreak mode, chat-template control tokens (<|im_start|>), [[system]] markers, SYSTEM: do โฆ |
| ๐ MEDIUM | system prompt, act as โฆ, pretend to be โฆ, "reveal your instructions", "repeat everything above", "begin new session as" |
| ๐ต 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 (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 mode
Plug your alerting in
def to_security_team(decision):
slack.post(f"โ ๏ธ MCPRampart 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 |
|---|---|---|---|---|---|
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. MCPRampart catches all three and refuses to start the server. Full breakdown in case-studies/01-fastapi-mcp-examples.md.
Where MCPRampart sits in the MCP-security landscape
MCP security tools have started shipping. Here's an honest map:
| Project | โญ | Shape | What it does |
|---|---|---|---|
mcp_rampart (this) |
new | Embedded library (pip install into your FastAPI app) |
Pre-flight audit of your own routes + runtime injection guardrail on every tools/call |
luckyPipewrench/pipelock |
583 | Client-side firewall | Agent egress control, DLP, sits between agent and MCP server |
apache/casbin-gateway |
559 | HTTP gateway | Casbin policy enforcement in front of MCP traffic |
apisec-inc/mcp-audit |
149 | Config scanner | Scans mcp.json for exposed secrets / unsafe servers installed on your machine |
hyprmcp/mcp-gateway |
92 | OAuth proxy | DCR + analytics in front of MCP servers |
ModelContextProtocol-Security/mcpserver-audit |
16 | CLI | Audit MCP servers before you install them |
Where MCPRampart is the only one โ
| mcp_rampart | pipelock | casbin-gateway | 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 tools/call |
โ | partial | โ | โ | โ |
Pluggable on_block / on_alert callbacks |
โ | โ | โ | โ | โ |
Three-policy model (block / alert / log) |
โ | โ | โ | โ | โ |
The gateway / firewall / config-scanner projects each solve a real problem for the agent operator or the MCP user. MCPRampart solves the dual problem for the MCP server author: did you accidentally expose something dangerous, and if so, are you willing to ship anyway?
If you're building an MCP server (not consuming someone else's), this is the layer you don't currently have.
How it works
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Your FastAPI app โ
โ โ
โ @app.get("/api/recipes") โ Existing routes โ
โ @app.post("/api/recipes") โ
โ @app.delete("/api/admin/...") โ BAD โ
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ MCPRampart (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 output - 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) + tunable confidence thresholds
- v0.6 โ 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
Contributing
git clone https://github.com/miloudbelarebia/mcp-rampart
cd mcp-rampart
pip install -e ".[dev]"
pytest
See CONTRIBUTING.md for guidelines.
License
MIT โ see LICENSE.
Built with โค๏ธ by Miloud Belarebia
97M MCP installs per month. Someone has to audit what they expose.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mcp_rampart-0.3.3.tar.gz.
File metadata
- Download URL: mcp_rampart-0.3.3.tar.gz
- Upload date:
- Size: 27.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4c0d2980454025c936d4563bebfeddb2e55680c7150d71b4cfc9e89af0088438
|
|
| MD5 |
5ee4056fe3fa8ee98f7b9d3d941c9b8f
|
|
| BLAKE2b-256 |
7ef4afd3dd574b09947469bcbe508100594c21ab75862d215d8a7d48ac37e6b1
|
File details
Details for the file mcp_rampart-0.3.3-py3-none-any.whl.
File metadata
- Download URL: mcp_rampart-0.3.3-py3-none-any.whl
- Upload date:
- Size: 24.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5a1ed3b9c51e9e8f6ab0d27e809eb589105fb01eecdf0e9a158f46f307ea410c
|
|
| MD5 |
5746bb3cf6e1ee84bef7a6391921909f
|
|
| BLAKE2b-256 |
e2d1ed947d55dbef0b7aae3d2540da1ac781f24c933aadae5378d3a42a2b4863
|