Skip to main content
Glama

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

  • v0.1 β€” FastAPI introspection, MCP Streamable HTTP transport, examples

  • v0.2 β€” bridge.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)

  • 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.


A
license - permissive license
-
quality - not tested
C
maintenance

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/mcpsentry'

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