Zero-Trust Security Layer for AI Agentic Workflows via the Model Context Protocol
Project description
MCP-Aegis
The Zero-Trust Security Layer for AI Agentic Workflows.
MCP-Aegis is an open-source, high-performance security middleware library that acts as a firewall for AI agents. AI assistants like Claude and Cursor are no longer just answering questions. They now directly control your computer — reading files, running commands, querying databases — through something called MCP (Model Context Protocol).
THE PROBLEM
That remote control has no lock on it.
Right now, if you give an AI agent access to your database, it gets FULL access. It can read your data, delete your data, or drop entire tables. There is no way to say "you can read, but you cannot delete."
Worse, a bad actor can trick the AI (called prompt injection) into running dangerous commands like deleting files or sending your passwords to an external server. The AI doesn't know it's being tricked.
And nobody is keeping a record of what the AI did, when, or why.
THE SOLUTION
MCP-Aegis is a security guard that sits between the AI and your tools.
AI Agent → Guardian (checks everything) → Your Tools
Before any action reaches your tools, Guardian asks four questions:
- Who is asking? (identity check)
- Are they allowed? (permission check)
- Is the request safe? (scans for dangerous commands)
- Are they asking too much? (rate limiting)
If any answer is "no," the request is blocked. It never reaches your tools.
Features
- OAuth 2.1 / JWT Authentication — RS256 validation with scope-based access control and RFC 8707 Resource Indicators.
- RBAC Policy Engine — YAML-driven policies with wildcard permissions and principal-to-tool mapping.
- Argument Sanitization — Blocks shell injection, path traversal, and other malicious patterns before they reach tool servers.
- Stateful Rate Limiting — Token Bucket algorithm with pluggable backends (in-memory, Redis).
- Transport Agnostic — Supports both SSE and Stdio transports via a clean abstraction.
- CLI Security Shim — Drop-in
mcp-aegiscommand wraps any MCP server with zero code changes. - Structured Logging — Full traceability with JSON-RPC request ID correlation.
- Dependency Injection — Swap auth providers, policy engines, and rate limiters without touching proxy code.
- Production Hardened — Payload size limits, concurrency caps, nesting depth guards, bounded buffers, and Redis failure resilience prevent crashes under any load.
Installation
pip install mcp-aegis
# With Redis support for distributed rate limiting
pip install mcp-aegis[redis]
From source
git clone https://github.com/kalyanganala28/MCP-guardian.git
cd MCP-guardian
pip install -e ".[dev]"
Quick Start
Option 1: CLI (Stdio Shim) — Recommended
Wrap any MCP server with Guardian in one command. No code changes needed:
mcp-aegis \
--target "npx @modelcontextprotocol/server-filesystem /tmp" \
--policy policies.yaml \
--principal developer \
--roles dev \
--log-level INFO
Use it in your Claude Desktop / Cursor MCP config:
{
"mcpServers": {
"guarded-filesystem": {
"command": "mcp-aegis",
"args": [
"--target", "npx @modelcontextprotocol/server-filesystem /tmp",
"--policy", "/path/to/policies.yaml",
"--principal", "developer",
"--roles", "dev"
]
}
}
}
Option 2: Python Library (HTTP Proxy)
from mcp_guardian import GuardianProxy, JWTAuthenticator, YAMLPolicyEngine
authenticator = JWTAuthenticator(jwks_uri="https://auth.example.com/.well-known/jwks.json")
policy_engine = YAMLPolicyEngine.from_file("policies.yaml")
proxy = GuardianProxy(authenticator=authenticator, policy_engine=policy_engine)
proxy.serve(host="0.0.0.0", port=8443)
Option 3: Programmatic Stdio Bridge
import asyncio
from mcp_guardian import StdioBridge, YAMLPolicyEngine, LocalAuthenticator
from mcp_guardian.sanitizer import Sanitizer
auth = LocalAuthenticator(principal="my-agent", roles=frozenset({"dev"}))
policy = YAMLPolicyEngine.from_file("policies.yaml")
bridge = StdioBridge(
["npx", "@modelcontextprotocol/server-filesystem", "/tmp"],
claims=auth._claims,
policy_engine=policy,
sanitizer=Sanitizer(),
)
asyncio.run(bridge.run())
CLI Reference
usage: mcp-aegis [-h] --target TARGET --policy POLICY [--mode {stdio}]
[--log-level {DEBUG,INFO,WARNING,ERROR}]
[--principal PRINCIPAL] [--roles ROLES]
[--rate-limit N] [--max-line-size BYTES]
[--max-arg-size BYTES] [--max-depth N] [--version]
Required:
--target TARGET Command to launch the downstream MCP server
--policy POLICY Path to the YAML policy file
Optional:
--principal PRINCIPAL Local identity for policy evaluation (default: local-user)
--roles ROLES Comma-separated roles (e.g. 'admin,dev')
--rate-limit N Max tool calls per minute
--log-level LEVEL DEBUG, INFO, WARNING, ERROR (default: INFO)
--mode {stdio} Transport mode (default: stdio)
--max-line-size BYTES Max bytes per stdio JSON-RPC line (default: 10 MB)
--max-arg-size BYTES Max bytes per individual argument value (default: 1 MB)
--max-depth N Max nesting depth for argument structures (default: 32)
Policy Configuration
Define access control in policies.yaml:
version: "1"
defaults:
effect: deny # deny-by-default (zero trust)
principals:
admin:
roles: [admin]
tools:
- pattern: "*" # wildcard: access to everything
actions: [read, execute]
developer:
roles: [dev]
tools:
- pattern: "db:read" # exact match
actions: [execute]
- pattern: "fs:*" # namespace wildcard
actions: [read]
- pattern: "git:*"
actions: [read, execute]
readonly:
roles: [observer]
tools:
- pattern: "*"
actions: [read] # can read anything, execute nothing
Verification
Run the built-in verification script to confirm everything works:
python verify.py
Expected output:
1. Import Check
PASS All modules import successfully
2. Policy Engine
PASS Load policies.yaml
PASS Admin wildcard access allowed
PASS Junior denied db:write
3. Argument Sanitizer
PASS Clean SQL passes
PASS Shell injection blocked
PASS Path traversal blocked
PASS Command substitution blocked
...
============================================================
ALL 30 CHECKS PASSED
MCP-Aegis v0.1.1 is fully operational.
============================================================
Run the test suite:
pytest # quick run
pytest --cov=mcp_guardian --cov-branch # with coverage
pytest --cov=mcp_guardian --cov-report=html # HTML report
Production Hardening
MCP-Aegis is designed to never crash, regardless of input size or load. Every data path is bounded:
| Protection | Default | Industry Reference | Configurable via |
|---|---|---|---|
| HTTP body size | 100 MB | gRPC 4 MB, Django 2.5 MB | max_http_body_bytes / GUARDIAN_MAX_HTTP_BODY_BYTES |
| Stdio line size | 100 MB | asyncio 64 KB | max_stdio_line_bytes / GUARDIAN_MAX_STDIO_LINE_BYTES |
| Individual argument | 50 MB | — | max_argument_bytes / GUARDIAN_MAX_ARGUMENT_BYTES |
| Total arguments | 100 MB | — | max_arguments_total_bytes / GUARDIAN_MAX_ARGUMENTS_TOTAL_BYTES |
| Nesting depth | 128 levels | JSON parsers ~100 | max_nesting_depth / GUARDIAN_MAX_NESTING_DEPTH |
| Regex scan cap | 1 MB | — | sanitizer_max_scan_bytes / GUARDIAN_SANITIZER_MAX_SCAN_BYTES |
| SSE stream buffer | 100 MB | — | max_sse_buffer_bytes / GUARDIAN_MAX_SSE_BUFFER_BYTES |
| Policy file | 10 MB | — | max_policy_file_bytes / GUARDIAN_MAX_POLICY_FILE_BYTES |
| Concurrent requests | 10,000 | Uvicorn backlog 2048 | max_concurrent_requests / GUARDIAN_MAX_CONCURRENT_REQUESTS |
| Transport timeout | 30s | httpx 5s, K8s probe 30s | transport_timeout / GUARDIAN_TRANSPORT_TIMEOUT |
| Redis op timeout | 5s | redis-py None (unsafe) | redis_operation_timeout / GUARDIAN_REDIS_OPERATION_TIMEOUT |
| Redis failure mode | fail-closed | — | redis_fail_open / GUARDIAN_REDIS_FAIL_OPEN |
| Shutdown grace | 30s | K8s SIGTERM grace 30s | target_shutdown_timeout / GUARDIAN_TARGET_SHUTDOWN_TIMEOUT |
Programmatic configuration
from mcp_guardian import configure_limits
configure_limits(
max_http_body_bytes=50 * 1024 * 1024, # 50 MB
max_concurrent_requests=5000,
redis_fail_open=True,
)
Environment variable configuration
export GUARDIAN_MAX_HTTP_BODY_BYTES=52428800
export GUARDIAN_MAX_CONCURRENT_REQUESTS=5000
export GUARDIAN_REDIS_FAIL_OPEN=true
Project Structure
src/mcp_guardian/
├── __init__.py # Public API
├── __main__.py # python -m mcp_guardian
├── cli.py # argparse CLI entry point
├── bridge.py # Stdio message pump (security shim)
├── errors.py # MCPGuardianError hierarchy
├── limits.py # GuardianLimits (production safety thresholds)
├── sanitizer.py # Argument sanitization
├── logging.py # Structured logging setup
├── core/
│ ├── proxy.py # GuardianProxy (HTTP mode) + middleware
│ └── transport.py # Transport ABC + SSE/Stdio
├── auth/
│ ├── jwt.py # JWTAuthenticator (OAuth 2.1)
│ └── local.py # LocalAuthenticator (stdio mode)
├── policy/
│ └── engine.py # YAMLPolicyEngine (RBAC)
└── rate_limit/
├── limiter.py # Token Bucket rate limiter
└── backends.py # InMemory + Redis backends
Development
git clone https://github.com/kalyanganala28/MCP-guardian.git
cd MCP-guardian
pdm install -G dev # or: pip install -e ".[dev]"
pdm run pytest # tests
pdm run mypy src/ # type checking
pdm run ruff check src/ # linting
Contributing
See CONTRIBUTING.md for development setup, coding standards, and PR process.
License
Project details
Release history Release notifications | RSS feed
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_aegis-0.2.0.tar.gz.
File metadata
- Download URL: mcp_aegis-0.2.0.tar.gz
- Upload date:
- Size: 42.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c4a26b152dd51544f4385cec82f63771de0eb0a5f338ad7d1a1a4a53dbc99d27
|
|
| MD5 |
45567e5ef626245983991ad9ab29e607
|
|
| BLAKE2b-256 |
8a54a9d3b8e8c12c76c94f74dca67c9ae58d2abbe49b9672acab566a83d2aa71
|
Provenance
The following attestation bundles were made for mcp_aegis-0.2.0.tar.gz:
Publisher:
publish.yml on kalyanganala28/MCP-guardian
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_aegis-0.2.0.tar.gz -
Subject digest:
c4a26b152dd51544f4385cec82f63771de0eb0a5f338ad7d1a1a4a53dbc99d27 - Sigstore transparency entry: 1280536909
- Sigstore integration time:
-
Permalink:
kalyanganala28/MCP-guardian@1c2ac0574a05b42aa4de99dee85d25522455e9d3 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/kalyanganala28
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1c2ac0574a05b42aa4de99dee85d25522455e9d3 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file mcp_aegis-0.2.0-py3-none-any.whl.
File metadata
- Download URL: mcp_aegis-0.2.0-py3-none-any.whl
- Upload date:
- Size: 32.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
158e37727622e09b89d14bf3e44707cd63d7f43bb1c8752a5e189ae0948e18c3
|
|
| MD5 |
ce3a14615ded3d6fbeb306cc116a67b5
|
|
| BLAKE2b-256 |
de50fd5c495cb0a17cb3d1f4ef0112bdc91440e47ea865dcbf5210a7835a629d
|
Provenance
The following attestation bundles were made for mcp_aegis-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on kalyanganala28/MCP-guardian
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_aegis-0.2.0-py3-none-any.whl -
Subject digest:
158e37727622e09b89d14bf3e44707cd63d7f43bb1c8752a5e189ae0948e18c3 - Sigstore transparency entry: 1280536912
- Sigstore integration time:
-
Permalink:
kalyanganala28/MCP-guardian@1c2ac0574a05b42aa4de99dee85d25522455e9d3 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/kalyanganala28
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1c2ac0574a05b42aa4de99dee85d25522455e9d3 -
Trigger Event:
workflow_dispatch
-
Statement type: