Zero-trust security gateway for MCP (Model Context Protocol) tool servers — static scanning, sandbox behavioural profiling, and runtime policy enforcement.
Project description
MCP Zero-Trust Gateway
A security gateway that sits between an LLM agent and the MCP (Model Context Protocol) tool servers it uses, on the principle that no tool server is trusted by default. Every tool is inspected before it is allowed in, profiled to see what it actually does, constrained by least-privilege policy, and monitored at runtime.
It runs entirely on your machine. The trust store is a local SQLite file and no telemetry is sent anywhere.
The problem
An LLM agent discovers tools by reading each MCP server's self-description
(tools/list). It then calls them (tools/call) with its own privileges. The
agent treats the server's description as truth. That assumption is the
vulnerability: a malicious server can hide instructions in its description
(tool poisoning) or perform actions its manifest never declared (e.g. read
~/.ssh/id_rsa while claiming to fetch weather). This gateway removes the
default trust.
What it does
- Intake scan — static inspection of the manifest at registration, including detection of poisoned descriptions.
- Behavioral profiling — runs the server in a hardened sandbox (
--network none,--cap-drop ALL, seccomp) understraceand records the syscalls it actually makes. - Declared-vs-observed verification — flags any capability the tool used but did not declare, and detects rug-pulls when a new version quietly gains one.
- Policy enforcement — constrains even approved tools to least privilege at runtime.
- Runtime proxy — every tool call passes through the gateway, is checked, logged, and its response filtered.
- Dashboard — makes verdicts, mismatches, and blocked actions visible.
Install
pip install mcp-ztgateway
Optional extras:
pip install "mcp-ztgateway[audit]" # adds pip-audit for supply-chain scanning
Docker is required for behavioural profiling (step 2). Everything else — static scanning, policy enforcement, the proxy and the dashboard — runs without it.
Quick start
# 1. Check the environment
mcp-ztgateway doctor
# 2. Statically scan a tool manifest (exits non-zero on findings, so it works in CI)
mcp-ztgateway scan manifest.json
# 3. Profile a tool's real behaviour in a sandbox (needs Docker)
mcp-ztgateway profile my-tool:latest --tool get_weather --args '{"city":"London"}'
# 4. Run the gateway
mcp-ztgateway serve
serve binds to 127.0.0.1:8000 by default, so it is not reachable from other
machines.
Where profiles live
A profile is the JSON record of what a tool did when sandboxed. Without one, a tool cannot be verified and is denied (default-deny). Profiles are looked up in this order:
./profiles— project-local, so a repo can pin its own trusted profiles$MCP_ZTGATEWAY_PROFILES— explicit override for CI or containers~/.mcp-ztgateway/profiles— the per-user default
mcp-ztgateway doctor prints which one is active.
Optional: require an API key
The gateway is local-first and needs no authentication when bound to localhost.
If you expose it beyond your machine, set a key and every request must then send
a matching X-API-Key header:
export GATEWAY_API_KEY=$(python -c "import secrets; print(secrets.token_urlsafe(32))")
mcp-ztgateway serve --host 0.0.0.0
/health and / stay open so load balancers can probe them.
Running with Docker
docker compose up --build
# gateway -> http://localhost:8000
# dashboard -> http://localhost:5173
Published images:
docker pull abhiii1005/mcp_zerotrust_security_gateway:1.0.0
docker pull abhiii1005/zerotrust_dashboard:1.0.0
The gateway image is runtime-only: it enforces policy using pre-committed profiles and does not run Docker inside itself, so no privileged socket mount is needed. Live profiling stays a host-side step.
Development
git clone https://github.com/nabrahma/MCP_Zero-Trust_Gateway_BTP
cd MCP_Zero-Trust_Gateway_BTP
pip install -e ".[dev,audit]"
pytest -q
Documentation
MD_files/ARCHITECTURE.md— architecture, requirements, components, data flowsMD_files/THREAT_MODEL.md— what is defended, what is out of scope, mapped to the OWASP MCP Top 10MD_files/CONTRACTS.md— the shared data shapes between components (read before writing code)sandbox/enforcement/— captured proof that the sandbox enforcement actually blocks the attacks it claims to
Status and honest limitations
Final-year B.Tech project: built and empirically evaluated, not a production system.
- Behavioural profiling is evadable. A tool that stays dormant during profiling, detects the sandbox, or only misbehaves on unseen input will not be caught. This is the inherent limit of dynamic analysis.
- seccomp is coarse. It filters on syscall numbers and scalar arguments, not
path strings, so it can deny "all network" but not "reads of
.envspecifically". Per-path decisions are made by the policy layer above it. - Capabilities are classes, not exact semantics. The gateway reports "this tool reads files and opens sockets", not "this tool exfiltrates SSH keys".
See MD_files/THREAT_MODEL.md for the full scope.
Tech stack
Python · FastAPI · Docker (seccomp/strace) · SQLite · React + Tailwind · pip-audit
Team & roles
- Static scanning & comparator (Layers 1, 3)
- Sandbox profiler & enforcement (Layer 2)
- Gateway: proxy, policy, dashboard (Layers 4–7)
License
MIT — see LICENSE.
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_ztgateway-0.1.0.tar.gz.
File metadata
- Download URL: mcp_ztgateway-0.1.0.tar.gz
- Upload date:
- Size: 47.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.30 {"installer":{"name":"uv","version":"0.11.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6e1a29885bbaf020dea37efdd42e336db1a1f952ea2b43667737c69b53f0018d
|
|
| MD5 |
8ebe05aadd7967ced9f521756e28f7b1
|
|
| BLAKE2b-256 |
22d653de912b415aeae9809e6c2a59ad66a480160f40648de71cb353b7ce1de2
|
File details
Details for the file mcp_ztgateway-0.1.0-py3-none-any.whl.
File metadata
- Download URL: mcp_ztgateway-0.1.0-py3-none-any.whl
- Upload date:
- Size: 41.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.30 {"installer":{"name":"uv","version":"0.11.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8ed0ea5e189eca7442e2173208b656b22b5c8c507d35211fba85228d0c2304b9
|
|
| MD5 |
1452648dbcefc65718d8aedef0002150
|
|
| BLAKE2b-256 |
aa31a9d1171271e2ed9fc7c8530186fa3fcffab4b092e2aea5b59f8769e61b8d
|