MCP Shield 🛡️
A local policy-enforcement runtime for MCP tool calls.
MCP Shield evaluates tool names and arguments against configurable security policies. It returns an ALLOW or BLOCK decision and records the result in an audit log.
[!IMPORTANT] MCP Shield is an early-stage project. The current release does not automatically discover MCP servers or transparently intercept tool calls from Codex, Claude Code, Cursor, Proxyman, or other MCP clients and servers.
TL;DR
MCP Shield provides a command-line interface and local REST API for evaluating MCP tool calls against YAML security policies.
It can:
- Allow or block tools using configurable allowlists
- Recursively inspect tool arguments for dangerous patterns
- Detect common SSRF targets, sensitive paths, and unsafe URL schemes
- Record allowed and blocked decisions in an audit log
- Display audit statistics
- Calculate basic risk scores from tool capabilities
Tool calls must currently be submitted through the mcpshield CLI or the /inspect API. The application making the actual MCP call is responsible for enforcing the returned decision.
Why MCP Tool Calls Need Security Controls
The Model Context Protocol (MCP) allows AI applications to connect to external tools and data sources through MCP servers.
Depending on the server, those tools may be able to:
- Read or write files
- Call internal or external APIs
- Query databases
- Access environment variables
- Control browsers
- Execute commands
These capabilities are useful, but a malicious, compromised, or overly permissive server can expose credentials, sensitive files, internal services, or the host system.
MCP Shield provides a policy-decision layer that callers can use before allowing a tool call to continue.
How It Works
- A caller submits the server name, policy, tool name, and arguments.
- MCP Shield checks whether the tool is permitted by the selected policy.
- It recursively scans the arguments for blocked hosts, paths, schemes, and patterns.
- It returns an
ALLOWorBLOCKdecision with a reason. - It records the decision in the audit log.
Tool call
│
▼
MCP Shield policy evaluation
│
├── BLOCK → record decision and reject the call
│
└── ALLOW → record decision and permit the caller to continue
MCP Shield currently evaluates requests; it is not yet a transparent MCP proxy.
Features
- YAML-based policies
- Per-policy tool allowlists
- Recursive argument inspection
- SSRF and sensitive-path pattern detection
- CLI inspection commands
- REST API
- SQLite audit logging
- Audit statistics
- Basic server risk scoring
- Docker sandbox management endpoints
- Experimental Firecracker backend for Linux/KVM environments
Requirements
- Python 3.12 or newer
- macOS, Linux, or Windows for the core API and CLI
- Docker only when using the Docker sandbox backend
- Linux with KVM only when using the experimental Firecracker backend
Installation
Standard installation
Create and activate a virtual environment:
python3.12 -m venv ~/mcpshield-env
source ~/mcpshield-env/bin/activate
Install MCP Shield:
python -m pip install --upgrade pip
python -m pip install mcpshield-runtime
Verify the installation:
python --version
mcpshield --help
macOS installation
Some macOS installations still provide Python 3.9 through Xcode. Check your version:
python3 --version
If it is older than Python 3.12, install Python 3.12 with Homebrew:
brew install python@3.12
Create the environment using Homebrew’s interpreter:
$(brew --prefix python@3.12)/bin/python3.12 -m venv ~/mcpshield-env
source ~/mcpshield-env/bin/activate
python -m pip install --upgrade pip
python -m pip install mcpshield-runtime
To reactivate the environment later:
source ~/mcpshield-env/bin/activate
To leave it:
deactivate
Quick Start
MCP Shield currently uses two terminal windows:
- Terminal 1 runs the local API.
- Terminal 2 runs the CLI commands.
1. Get the policies
Release 0.1.2 must be started from the cloned repository so the runtime can locate the policies/ directory:
cd ~
git clone https://github.com/srisowmya2000/mcp-shield.git
cd ~/mcp-shield
If the repository already exists:
cd ~/mcp-shield
git pull origin main
2. Terminal 1: Start the API
cd ~/mcp-shield
source ~/mcpshield-env/bin/activate
export NO_PROXY=localhost,127.0.0.1
export no_proxy=localhost,127.0.0.1
uvicorn runtime.api.main:app \
--host 127.0.0.1 \
--port 8000
Keep this terminal open. The API will be available at:
http://127.0.0.1:8000
Useful pages:
- Health:
http://127.0.0.1:8000/health - API documentation:
http://127.0.0.1:8000/docs - Dashboard:
http://127.0.0.1:8000/dashboard
3. Terminal 2: Run CLI commands
source ~/mcpshield-env/bin/activate
export NO_PROXY=localhost,127.0.0.1
export no_proxy=localhost,127.0.0.1
Check API health:
curl --noproxy "*" http://127.0.0.1:8000/health
Expected response:
{"status":"ok","service":"mcp-shield","version":"0.1.0"}
Inspect a tool that should be blocked:
mcpshield inspect read_secrets
Inspect an allowed tool:
mcpshield inspect safe_tool
View audit statistics and recent decisions:
mcpshield stats
mcpshield audit
Expected results:
read_secrets → BLOCKED
safe_tool → ALLOWED
CLI Usage
Inspect a tool call
mcpshield inspect TOOL_NAME
Example:
mcpshield inspect read_secrets
Provide tool arguments as JSON:
mcpshield inspect ssrf_fetch \
--args '{"url":"http://169.254.169.254/latest/meta-data/"}'
Select a policy and server label:
mcpshield inspect safe_tool \
--policy default \
--server demo-server \
--args '{"name":"Sri"}'
Score tool risk
mcpshield risk "read_secrets,ssrf_fetch,safe_tool"
View audit records
mcpshield audit
View audit statistics
mcpshield stats
REST API
Health check
curl --noproxy "*" http://127.0.0.1:8000/health
Inspect a tool call
curl --noproxy "*" \
-X POST http://127.0.0.1:8000/inspect \
-H "Content-Type: application/json" \
-d '{
"server_name": "demo",
"policy": "default",
"tool_call": {
"tool_name": "read_secrets",
"arguments": {}
}
}'
Example blocked response:
{
"server": "demo",
"tool": "read_secrets",
"policy": "default",
"decision": "BLOCK",
"reason": "Tool 'read_secrets' is not in the allowed_tools list",
"blocked": true
}
Audit endpoints
curl --noproxy "*" http://127.0.0.1:8000/audit
curl --noproxy "*" http://127.0.0.1:8000/audit/stats
Risk scoring
curl --noproxy "*" \
-X POST http://127.0.0.1:8000/risk/score \
-H "Content-Type: application/json" \
-d '{"tool_names":["read_secrets","ssrf_fetch","safe_tool"]}'
Policies
Policies are stored as YAML files inside policies/.
Example:
allowed_tools:
- safe_tool
- list_files
- get_time
block_network: true
block_env_access: true
blocked_arg_patterns:
- "169.254.169.254"
- "169.254.170.2"
- "localhost"
- "127.0.0.1"
- "/etc/passwd"
- "/etc/shadow"
- "file://"
- "gopher://"
max_memory_mb: 256
execution_timeout_seconds: 30
The repository includes:
default.yaml— general allowlist and argument checksstrict.yaml— more restrictive policy
Select a policy with:
mcpshield inspect safe_tool --policy strict
Policy matching is a security control, not a complete guarantee of safety. Use operating-system isolation, least privilege, network restrictions, and careful review of MCP servers.
Troubleshooting
No matching distribution found
Example:
ERROR: Could not find a version that satisfies the requirement mcpshield-runtime
ERROR: No matching distribution found for mcpshield-runtime
Check your Python version:
python3 --version
MCP Shield requires Python 3.12 or newer.
On macOS:
brew install python@3.12
$(brew --prefix python@3.12)/bin/python3.12 \
-m venv ~/mcpshield-env
source ~/mcpshield-env/bin/activate
python -m pip install mcpshield-runtime
pip: command not found
Use pip through the active Python interpreter:
python -m pip install mcpshield-runtime
Do not run:
pip3 install --upgrade pip3
The package is named pip, not pip3. The correct command is:
python -m pip install --upgrade pip
Cannot connect to mcp-shield API
The CLI requires the local API server.
Start it in another terminal:
cd ~/mcp-shield
source ~/mcpshield-env/bin/activate
uvicorn runtime.api.main:app \
--host 127.0.0.1 \
--port 8000
Then verify:
curl --noproxy "*" http://127.0.0.1:8000/health
RemoteProtocolError: Server disconnected without sending a response
A system proxy or an application such as Proxyman may be intercepting localhost traffic.
Set localhost bypass variables in both terminals:
export NO_PROXY=localhost,127.0.0.1
export no_proxy=localhost,127.0.0.1
Also add localhost and 127.0.0.1 to the proxy application’s bypass or ignore list.
/inspect returns 404 Not Found
In release 0.1.2, policies are resolved relative to the current working directory.
Start Uvicorn from the cloned repository:
cd ~/mcp-shield
uvicorn runtime.api.main:app \
--host 127.0.0.1 \
--port 8000
Confirm that the policy files exist:
ls -la ~/mcp-shield/policies
This packaging limitation is expected to be corrected in a later release.
KeyError: 'blocked'
This usually means the /inspect endpoint returned an error response instead of a policy decision.
Check the API terminal for a 404 or 500 response.
Confirm that:
- The API is running
- Uvicorn was started from
~/mcp-shield policies/default.yamlexists- Port
8000is available - Localhost proxy bypass variables are configured
Missing argument 'tool'
This command is incomplete:
mcpshield inspect
Provide a tool name:
mcpshield inspect read_secrets
Repository already exists
If cloning returns:
fatal: destination path 'mcp-shield' already exists and is not an empty directory
Use the existing repository:
cd ~/mcp-shield
git pull origin main
Current Limitations
The current release does not:
- Automatically discover MCP client configurations
- Automatically discover or scan configured MCP servers
- Transparently intercept MCP protocol traffic
- Automatically integrate with Codex, Claude Code, Cursor, or Proxyman MCP
- Automatically enforce decisions for an external MCP client
- Replace operating-system sandboxing or least-privilege controls
An external caller or future proxy integration must submit the tool call to MCP Shield and honor the returned decision.
Security Model
MCP Shield is intended as a defense-in-depth policy layer. It should not be treated as a complete sandbox or a replacement for:
- Reviewing third-party MCP server code
- Restricting filesystem permissions
- Limiting environment variables and secrets
- Applying outbound network controls
- Running untrusted code in isolated environments
- Monitoring the host and MCP server processes
See docs/threat-model.md for additional details.
Development
Clone the repository and install it in editable mode:
git clone https://github.com/srisowmya2000/mcp-shield.git
cd mcp-shield
python3.12 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e .
Run the tests:
python -m pip install pytest
pytest tests/ -v
Start the development API:
uvicorn runtime.api.main:app --reload
Roadmap
- Package built-in policies correctly for installation from any directory
- Add clearer CLI handling for API error responses
- Add
mcpshield serveandmcpshield doctorcommands - Add structured policy validation
- Add per-tool argument-schema validation
- Add prompt-injection detection
- Add webhook alerts for blocked calls
- Explore an optional MCP proxy and enforcement integration
Automatic MCP client/server discovery belongs to a separate scanner project and is not part of the current MCP Shield runtime.
Responsible Use
Use MCP Shield only with systems, MCP servers, accounts, and environments you own or are authorized to test.
Review policy decisions and server behavior before relying on the project in a sensitive environment.
License
MCP Shield is released under the MIT License.
Author
Sri Sowmya Nemani — security researcher and engineer working in MCP security, application security, detection engineering, and responsible vulnerability disclosure.
Contributions, bug reports, and documentation improvements are welcome.
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 mcpshield_runtime-0.1.3.tar.gz.
File metadata
- Download URL: mcpshield_runtime-0.1.3.tar.gz
- Upload date:
- Size: 15.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
891bfaf9b21a9d50d14a67b70b68afc7d6a425ad8739a93fcda2517960530308
|
|
| MD5 |
ec014fd5bb517d6a46740f7f39d6ad91
|
|
| BLAKE2b-256 |
b89684546100dde3a3b1df87a95f65943a7bd8fc689703a959dd0bf1bc55b044
|
File details
Details for the file mcpshield_runtime-0.1.3-py3-none-any.whl.
File metadata
- Download URL: mcpshield_runtime-0.1.3-py3-none-any.whl
- Upload date:
- Size: 17.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
195949e01e84f3b7bcaf48d798845169ca876b73fefe78d4049eefa3059a33ed
|
|
| MD5 |
75052cd0193d2d0be17c4a439d9ad65d
|
|
| BLAKE2b-256 |
f8ebeee6f466f456e4f5e91f5930c75cbfff8ef98939c1b864d924f01a4f53ef
|