Security scanner and runtime firewall for AI agents and MCP servers
Project description
AgentShield
Security scanner and runtime firewall for AI agents and MCP servers.
AgentShield protects your AI coding tools (Claude Code, Cursor, Windsurf, VS Code, Cline, Continue) from malicious MCP servers, tool poisoning, supply chain attacks, and configuration vulnerabilities.
The Problem
MCP servers are the plugins of AI coding tools. Developers install them from npm, give them access to their codebase, API keys, and databases — and nobody checks if they're safe.
- A plugin's tool description can contain hidden instructions that trick the AI into exfiltrating your data
- A typosquatted package like
mcp-sevrer-semgrepsilently installs malware - Hardcoded API keys in config files get committed to git
- A trusted plugin gets silently updated with a malicious payload
AgentShield catches all of this.
Quick Start
pip install agentshield
Scan your MCP config:
# Auto-detect and scan .mcp.json in current directory
agentshield scan
# Scan a specific config file
agentshield scan mcp-config -f .mcp.json
# Scan all AI tool configs in a project
agentshield scan project --dir .
Output:
+-------------------------------- AgentShield --------------------------------+
| Scan Results |
| Target: .mcp.json |
| Servers: 4 scanned |
| Findings: 3 high, 1 medium |
+-----------------------------------------------------------------------------+
! CFG-NPX-server Unverified npx install: server
Uses 'npx -y' which auto-installs packages without verification.
Fix: Pin the package version explicitly.
! CFG-SECRET-api-KEY Hardcoded secret in config: API_KEY
Has env var 'API_KEY' with a hardcoded value.
Fix: Use environment variable references (${VAR}).
Features
Scanner (14 Security Checks)
| Check | What it Detects | OWASP Ref |
|---|---|---|
| Tool Poisoning | Hidden instructions, invisible unicode, exfiltration URLs, prompt injection | ASI04 |
| Config Audit | npx -y, hardcoded secrets, missing binaries, no version pinning |
ASI04 |
| Auth Gaps | Destructive tools without auth, unauthenticated HTTP endpoints | ASI03 |
| Transport | Plaintext HTTP, secrets in CLI args | — |
| Tool Exposure | Admin/debug tools, overly broad permissions (shell, file access) | ASI07 |
| Rug Pull | Silent tool definition changes (baseline tracking) | ASI04 |
| Code Execution | Tools enabling arbitrary code execution | ASI05 |
| Data Leakage | PII fields in schemas, bulk data exposure | ASI08 |
| Permission Scope | Dangerous tool combinations (read_file + exec = RCE) | ASI03+07 |
| Cross-Origin | Cross-server escalation, external service interaction | ASI01+09 |
| Schema Validation | Missing schemas, injection-prone fields, unbounded strings | ASI04 |
| Resource Exposure | Sensitive URIs (database://, file://), internal paths | ASI08 |
| Tool Shadowing | Name impersonation via Levenshtein distance, leet-speak | ASI04 |
| npm Verify | Typosquat detection, npm 404 check, deprecated packages | ASI04 |
Runtime Proxy (Firewall for AI Tool Calls)
AgentShield can sit between your AI client and MCP servers, intercepting every tool call:
# Generate a protected config
agentshield shield --config .mcp.json
# Wraps every server with the proxy:
# "command": "agentshield"
# "args": ["proxy", "--server", "name", "--config", ".mcp.json"]
Define guardrails in .agentshield.yml:
guardrails:
default_action: allow
rules:
- name: block-destructive
action: deny
tools: ["delete_*", "rm_*", "drop_*"]
message: "Destructive operations blocked"
- name: audit-file-writes
action: audit
tools: ["write_*", "create_*", "edit_*"]
- name: block-ssrf
action: deny
args_pattern: "169\\.254\\.169\\.254"
message: "SSRF attempt blocked"
- name: rate-limit
action: rate_limit
tools: ["*"]
rate: "100/minute"
View the audit log:
agentshield audit
Policy Engine
# .agentshield.yml
version: 1
profile: standard # strict | standard | minimal
checks:
disabled:
- transport-security
severity_overrides:
"CFG-BINARY-*": low
ignore:
- check_id: config-audit
server: local-dev-server
custom_rules:
- name: no-localhost
pattern: "localhost"
target: args
severity: high
message: "No localhost in production configs"
fail_on: medium
More Commands
# Auto-fix security issues
agentshield fix -f .mcp.json
agentshield fix -f .mcp.json --no-dry-run # Apply fixes
# Compare scan results over time
agentshield scan mcp-config -f .mcp.json --format json -o baseline.json
# ... make changes ...
agentshield scan mcp-config -f .mcp.json --format json -o current.json
agentshield diff baseline.json current.json
# Watch for config changes in real-time
agentshield watch -f .mcp.json
# Machine-wide inventory of all MCP servers
agentshield inventory
# Convert configs between AI tools
agentshield convert -f .mcp.json --from claude --to cursor
# List compliance profiles
agentshield profiles
# Generate a secure config template
agentshield init --format claude
Output Formats
| Format | Flag | Use Case |
|---|---|---|
| Text | --format text |
Terminal (default) |
| JSON | --format json |
Programmatic consumption |
| SARIF | --format sarif |
GitHub Security tab |
| HTML | --format html |
Shareable reports |
| Markdown | --format markdown |
PR comments, docs |
CI/CD Integration
GitHub Action
- uses: ewibrahim/agentshield@v1
with:
file: .mcp.json
fail-on: high
sarif-output: agentshield.sarif
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: agentshield.sarif
Pre-commit Hook
# .pre-commit-config.yaml
repos:
- repo: https://github.com/ewibrahim/agentshield
rev: v1.0.0
hooks:
- id: agentshield
CI Pipeline
pip install agentshield
agentshield scan mcp-config -f .mcp.json --ci --fail-on high
Supported AI Tools
| Tool | Config Path | Auto-detected |
|---|---|---|
| Claude Code | .mcp.json |
Yes |
| Cursor | .cursor/mcp.json |
Yes |
| Windsurf | .windsurf/mcp.json |
Yes |
| VS Code | .vscode/mcp.json |
Yes |
| Cline | .cline/mcp_settings.json |
Yes |
| Continue | .continue/config.json |
Yes |
Plugin System
Create custom checks and distribute them as pip packages:
# my_plugin/checks.py
from agentshield.checks.base import BaseCheck, CheckContext
from agentshield.core.models import Finding
class MyCustomCheck(BaseCheck):
id = "my-custom-check"
name = "My Custom Check"
requires_connection = True
async def run(self, context: CheckContext) -> list[Finding]:
# Your check logic here
return []
# pyproject.toml
[project.entry-points."agentshield.checks"]
my_check = "my_plugin.checks:MyCustomCheck"
Testing
pip install -e ".[dev]"
pytest tests/ -v
Full test suite covering all 14 security checks, policy engine, guardrails, proxy, converter, and diff engine.
Architecture
agentshield/
cli.py # Typer CLI (13 commands)
core/
scanner.py # Orchestrator
models.py # Pydantic data models
mcp_client.py # MCP connection (read-only, never calls tools)
guardrails.py # Runtime rule engine
proxy.py # MCP stdio proxy
policy.py # .agentshield.yml loading
scoring.py # Risk scoring (0-100)
report.py # Text/JSON/SARIF formatters
...
checks/
base.py # BaseCheck ABC
mcp/ # 14 security checks
db/
known_tools.json # Known MCP tool definitions
known_mcp_packages.json # Known npm packages
Safety constraint: AgentShield never calls call_tool() on MCP servers. It only reads metadata via list_tools(), list_resources(), and list_prompts().
Contributing
Contributions welcome! Please open an issue first to discuss what you'd like to change.
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 agentic_shield-1.0.0b1.tar.gz.
File metadata
- Download URL: agentic_shield-1.0.0b1.tar.gz
- Upload date:
- Size: 108.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ecd1250a24fbf4dc567320e3f6d0a855e199877c6208fc1595967999a3749d18
|
|
| MD5 |
a480dab0dafc3488f96e68fd0b7e1e31
|
|
| BLAKE2b-256 |
7e295355ab87ac6f54c12801e26bb39718f8661ed4dc2dc8e84389eab307285d
|
Provenance
The following attestation bundles were made for agentic_shield-1.0.0b1.tar.gz:
Publisher:
publish.yml on ewibrahim/agentshield
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agentic_shield-1.0.0b1.tar.gz -
Subject digest:
ecd1250a24fbf4dc567320e3f6d0a855e199877c6208fc1595967999a3749d18 - Sigstore transparency entry: 1091827201
- Sigstore integration time:
-
Permalink:
ewibrahim/agentshield@777e26cf4957ba6bd94cd17f6a6e8fe98906fbb3 -
Branch / Tag:
refs/tags/v1.0.0b1 - Owner: https://github.com/ewibrahim
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@777e26cf4957ba6bd94cd17f6a6e8fe98906fbb3 -
Trigger Event:
release
-
Statement type:
File details
Details for the file agentic_shield-1.0.0b1-py3-none-any.whl.
File metadata
- Download URL: agentic_shield-1.0.0b1-py3-none-any.whl
- Upload date:
- Size: 87.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
900b929db2e14dc18cdb1da316e0fd766865f5c5aa58b1bd4b84039998ce9132
|
|
| MD5 |
0185ffdf700038b540e3a5c737b744f0
|
|
| BLAKE2b-256 |
29a40bb5d2e226731e6d1801c1d7a1cc3b9e805c896ae138d00fb59f34e865d0
|
Provenance
The following attestation bundles were made for agentic_shield-1.0.0b1-py3-none-any.whl:
Publisher:
publish.yml on ewibrahim/agentshield
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agentic_shield-1.0.0b1-py3-none-any.whl -
Subject digest:
900b929db2e14dc18cdb1da316e0fd766865f5c5aa58b1bd4b84039998ce9132 - Sigstore transparency entry: 1091827252
- Sigstore integration time:
-
Permalink:
ewibrahim/agentshield@777e26cf4957ba6bd94cd17f6a6e8fe98906fbb3 -
Branch / Tag:
refs/tags/v1.0.0b1 - Owner: https://github.com/ewibrahim
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@777e26cf4957ba6bd94cd17f6a6e8fe98906fbb3 -
Trigger Event:
release
-
Statement type: