Install
$ agentstack add mcp-cisco-ai-defense-mcp-scanner ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ● Filesystem access Used
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
MCP Scanner
[](https://opensource.org/licenses/Apache-2.0) [](https://www.python.org/downloads/) [](https://pypi.org/project/cisco-ai-mcp-scanner/) [](https://discord.com/invite/nKWtDcXxtx) [](https://www.cisco.com/site/us/en/products/security/ai-defense/index.html) [](https://learn-cloudsecurity.cisco.com/ai-security-framework)
A Python tool for scanning MCP (Model Context Protocol) servers and tools for potential security findings. The MCP Scanner combines Cisco AI Defense inspect API, YARA rules and LLM-as-a-judge to detect malicious MCP tools.
Overview
The MCP Scanner provides a comprehensive solution for scanning MCP servers and tools for security findings. It leverages three powerful scanning engines (Yara, LLM-as-judge, Cisco AI Defense) that can be used together or independently.
The SDK is designed to be easy to use while providing powerful scanning capabilities, flexible authentication options, and customization.
Features
- Multiple Modes: Run scanner as a stand-alone CLI tool or REST API server
- Multi-Engine Security Analysis: Use all three scanning engines together or independently based on your needs.
- Vulnerable Packages Scanning: Scan Python dependencies for known vulnerabilities (CVE/PYSEC/GHSA) using pip-audit integration.
- Readiness Scanning: Zero-dependency static analysis for production readiness issues (timeouts, retries, error handling).
- Comprehensive Scanning: Scan MCP tools, prompts, resources, and server instructions for security findings
- Behavioural Code Scanning: Scan Source code of MCP servers for finding threats.
- VirusTotal Binary Scanning: Automatically detect malware in binary files (images, PDFs, executables, archives) bundled with MCP servers using VirusTotal hash lookups.
- Behavioural Code Scanning: Scan Source code of MCP servers for detecting threats.
- Static/Offline Scanning: Scan pre-generated JSON files without live server connections - perfect for CI/CD pipelines and air-gapped environments
- Explicit Authentication Control: Fine-grained control over authentication with explicit Auth parameters.
- OAuth Support: Full OAuth authentication support for both SSE and streamable HTTP connections.
- Custom Endpoints: Configure the API endpoint to support any Cisco AI Defense environments.
- MCP Server Integration: Connect directly to MCP servers to scan tools, prompts, and resources with flexible authentication.
- Customizable YARA Rules: Add your own YARA rules to detect specific patterns.
- Comprehensive Reporting: Detailed reports on detected security findings.
Installation
Prerequisites
- Python 3.11+
- uv (Python package manager)
- A valid Cisco AI Defense API Key (optional)
- LLM Provider API Key (optional)
- VirusTotal API Key (optional, for binary file malware scanning)
Installing as a CLI tool
uv tool install --python 3.13 cisco-ai-mcp-scanner
Alternatively, you can install from source:
uv tool install --python 3.13 --from git+https://github.com/cisco-ai-defense/mcp-scanner cisco-ai-mcp-scanner
Installing for local development
git clone https://github.com/cisco-ai-defense/mcp-scanner
cd mcp-scanner
uv sync --python 3.13
Install as a dependency in other projects
Add MCP Scanner as a dependency using uv. From your project root (initialize with uv if needed):
uv init --python 3.13 #if not already done
uv add cisco-ai-mcp-scanner
# then activate the virtual environment:
## macOS and Linux: source .venv/bin/activate
## Windows CMD: .venv\Scripts\activate
## Windows PWSH: .venv\Scripts\Activate.ps1
uv sync
The module name is mcpscanner. Import this module with:
# import everything (not recommended)
import mcpscanner
# selective imports (recommended). For example:
from mcpscanner import Config, Scanner
from mcpscanner.core.models import AnalyzerEnum
Quick Start
Environment Setup
Core API Configuration
Cisco AI Defense API (only required for API analyzer)
export MCP_SCANNER_API_KEY="your_cisco_api_key"
export MCP_SCANNER_ENDPOINT="https://us.api.inspect.aidefense.security.cisco.com/api/v1"
# For other endpoints please visit https://developer.cisco.com/docs/ai-defense/getting-started/#base-url
LLM Configuration (for LLM analyzer and Code Behavioral Analyzer)
Tested LLMs: OpenAI GPT-4o and GPT-4.1 | AWS Bedrock Claude 4.5 Sonnet
# AWS Bedrock Claude with AWS credentials (profile)
export AWS_PROFILE="your-profile"
export AWS_REGION="us-east-1"
export MCP_SCANNER_LLM_MODEL="bedrock/anthropic.claude-sonnet-4-5-20250929-v2:0" # Any AWS Bedrock supported model
# AWS Bedrock Claude with API key (Bearer token)
export MCP_SCANNER_LLM_API_KEY="bedrock-api-key-..." # Generated via Amazon Bedrock -> API Keys
export AWS_REGION="us-east-1"
export MCP_SCANNER_LLM_MODEL="bedrock/us.anthropic.claude-sonnet-4-5-20250929-v2:0" # Any AWS Bedrock supported model
# LLM Provider API Key (required for LLM analyzer)
export MCP_SCANNER_LLM_API_KEY="your_llm_api_key" # OpenAI
# LLM Model Configuration (optional - defaults provided)
export MCP_SCANNER_LLM_MODEL="gpt-5.2" # Any LiteLLM-supported model
export MCP_SCANNER_LLM_BASE_URL="https://api.openai.com/v1" # Custom LLM endpoint
export MCP_SCANNER_LLM_API_VERSION="2025-04-01-preview" # API version (if required)
# For Azure OpenAI (example)
export MCP_SCANNER_LLM_BASE_URL="https://your-resource.openai.azure.com/"
export MCP_SCANNER_LLM_API_VERSION="2025-04-01-preview"
export MCP_SCANNER_LLM_MODEL="azure/gpt-5.2"
# For Extended Thinking Models (longer timeout)
export MCP_SCANNER_LLM_TIMEOUT=300
Note: If you are using models from Azure Foundry, set the MCPSCANNERLLMBASEURL and MCPSCANNERLLMMODEL environment variables, as Microsoft has deprecated the need for MCPSCANNERLLMAPI_VERSION.
VirusTotal Configuration (for file/directory malware scanning)
The VirusTotal analyzer scans files and directories against VirusTotal's malware database using SHA256 hash lookups. It runs as a standalone analyzer via the virustotal subcommand or as part of --analyzers virustotal.
# VirusTotal API key (get one free at https://www.virustotal.com/)
export VIRUSTOTAL_API_KEY="your_virustotal_api_key"
# Optional: explicitly disable VirusTotal scanning even when API key is present.
# When not set, scanning is auto-enabled if VIRUSTOTAL_API_KEY is configured.
# Set to "false" to skip VT scanning without removing the API key (e.g. in CI).
export MCP_SCANNER_VIRUSTOTAL_ENABLED=false
# Optional: Upload unknown files to VirusTotal for scanning (default: false, privacy-friendly)
export MCP_SCANNER_VIRUSTOTAL_UPLOAD_FILES=false
# Optional: Max files to scan per directory (default: 10, set to 0 for unlimited)
export MCP_SCANNER_VT_MAX_FILES=10
> Note: Without VIRUSTOTAL_API_KEY, files will not be scanned for malware. When enabled, the analyzer uses configurable inclusion/exclusion extension lists to determine which files to scan, skipping __pycache__ and hidden directories.
Stdio Connection Timeout
When scanning stdio MCP servers, the scanner waits for the server process to start and respond. The default timeout is 60 seconds, which may be insufficient for servers that download large dependencies on first run. This setting only affects the stdio server connection; LLM/API call timeouts are controlled separately via MCP_SCANNER_LLM_TIMEOUT.
# Increase stdio server startup timeout (default: 60 seconds)
export MCP_SCANNER_STDIO_TIMEOUT=180 # 3 minutes — useful for servers with heavy deps
# Or use the CLI flag (overrides the environment variable)
mcp-scanner --stdio-timeout 180 stdio --stdio-command uvx --stdio-arg mcp-clickhouse
Using a Local LLM (No API Key Required)
If you are using a local LLM endpoint such as Ollama, vLLM, or LocalAI, the MCP_SCANNER_LLM_API_KEY variable is still required but can be set to any value.
Example:
export MCP_SCANNER_LLM_API_KEY=test
export MCP_SCANNER_LLM_ENDPOINT=http://localhost:11434
Quick Start Examples
The fastest way to get started is using the mcp-scanner CLI command. Global flags (like --analyzers, --format, etc.) must be placed before a subcommand.
CLI Usage
# Scan well-known client configs on this machine
mcp-scanner --scan-known-configs --analyzers yara --format summary
# Stdio server (example using uvx mcp-server-fetch)
mcp-scanner --stdio-command uvx --stdio-arg=--from --stdio-arg=mcp-server-fetch --stdio-arg=mcp-server-fetch --analyzers yara --format summary
# Remote server (deepwiki example)
mcp-scanner --server-url https://mcp.deepwiki.com/mcp --analyzers yara --format summary
# Suppress all output below ERROR (useful in CI/CD)
mcp-scanner --log-level error --analyzers yara --format raw --server-url https://mcp.deepwiki.com/mcp
# MCP Scanner as REST API
mcp-scanner-api --host 0.0.0.0 --port 8080
SDK Usage
import asyncio
import os
from mcpscanner import Config, Scanner, set_log_level
from mcpscanner.core.models import AnalyzerEnum
import logging
async def main():
# Suppress all mcpscanner logs below ERROR
set_log_level(logging.ERROR)
# Create configuration with your API keys
config = Config(
api_key="your_cisco_api_key",
llm_provider_api_key="your_llm_api_key"
)
# Create scanner
scanner = Scanner(config)
# Scan all tools on a remote server
tool_results = await scanner.scan_remote_server_tools(
"https://mcp.deepwiki.com/mcp",
analyzers=[AnalyzerEnum.API, AnalyzerEnum.YARA, AnalyzerEnum.LLM]
)
# Print tool results
for result in tool_results:
print(f"Tool: {result.tool_name}, Safe: {result.is_safe}")
# Scan all prompts on a server
prompt_results = await scanner.scan_remote_server_prompts(
"http://127.0.0.1:8000/mcp",
analyzers=[AnalyzerEnum.LLM]
)
# Print prompt results
for result in prompt_results:
print(f"Prompt: {result.prompt_name}, Safe: {result.is_safe}")
# Scan all resources on a server
resource_results = await scanner.scan_remote_server_resources(
"http://127.0.0.1:8000/mcp",
analyzers=[AnalyzerEnum.LLM],
allowed_mime_types=["text/plain", "text/html"]
)
# Print resource results
for result in resource_results:
print(f"Resource: {result.resource_name}, Safe: {result.is_safe}, Status: {result.status}")
# Scan a stdio server while suppressing its stderr output
from mcpscanner.core.mcp_models import StdioServer
server = StdioServer(command="uvx", args=["mcp-server-fetch"])
with open(os.devnull, "w") as devnull:
stdio_results = await scanner.scan_stdio_server_tools(
server,
analyzers=[AnalyzerEnum.YARA],
errlog=devnull
)
# Run the scanner
asyncio.run(main())
Subcommands Overview
- remote: scan a remote MCP server (SSE or streamable HTTP). Supports
--server-url, optional--bearer-token,--header. - stdio: launch and scan a stdio MCP server. Requires
--stdio-command; accepts--stdio-args,--stdio-env, optional--stdio-tool,--stdio-timeout. - config: scan servers from a specific MCP config file. Requires
--config-path; optional--bearer-token. - known-configs: scan servers from well-known client config locations on this machine; optional
--bearer-token. - prompts: scan prompts on an MCP server. Requires
--server-url; optional--prompt-name,--bearer-token,--header. - resources: scan resources on an MCP server. Requires
--server-url; optional--resource-uri,--mime-types,--bearer-token,--header. - instructions: scan server instructions from InitializeResult. Requires
--server-url; optional--bearer-token. - virustotal: scan files or directories for malware using VirusTotal hash lookups. Requires a
scan_pathargument (file or directory). - supplychain: scan source code of an MCP server for Behavioural analysis. requires 'path of MCP Server source code or MCP Server source file'
- vulnerable-package: scan Python dependencies for known vulnerabilities using pip-audit. Requires a path to a requirements file or project directory.
- static: scan pre-generated MCP JSON files offline (CI/CD mode). Supports
--tools,--prompts,--resources, optional--mime-types.
Note: Top-level flags (e.g., --server-url, --stdio-*, --config-path, --scan-known-configs) remain supported when no subcommand is used, but subcommands are recommended.
Additional Examples
Scan well-known MCP config paths (Windsurf, Cursor, Claude, VS Code)
# YARA-only scan of all servers defined in well-known config locations
mcp-scanner --scan-known-configs --analyzers yara --format summary
# Detailed output
mcp-scanner --scan-known-configs --analyzers yara --detailed
Scan a specific MCP config file
# Expand ~ yourself if needed by your shell
mcp-scanner --config-path "$HOME/.codeium/windsurf/mcp_config.json" \
--analyzers yara --format by_tool
Scan a stdio MCP server
# Use repeated --stdio-arg for reliable argument passing
mcp-scanner --analyzers yara --format summary \
stdio --stdio-command uvx \
--stdio-arg=--from --stdio-arg=mcp-server-fetch --stdio-arg=mcp-server-fetch
# Or list-form (ensure it doesn't conflict with later flags)
mcp-scanner --analyzers yara --detailed \
stdio --stdio-command uvx \
--stdio-args --from mcp-server-fetch mcp-server-fetch
# Scan only a specific tool on the stdio server
mcp-scanner --analyzers yara --format summary \
stdio --stdio-command uvx \
--stdio-arg=--from --stdio-arg=mcp-server-fetch --stdio-arg=mcp-server-fetch \
--stdio-tool fetch
# Increase startup timeout for servers with heavy dependencies (default: 60s)
mcp-scanner --stdio-timeout 180 --analyzers yara --format summary \
stdio --stdio-command uvx --stdio-arg mcp-clickhouse@0.1.13
Use a Bearer token with remote servers (non-OAuth)
# Direct remote server with Bearer token
mcp-scanner --analyzers yara --format summary \
remote --server-url https://your-mcp-server/sse --bearer-token "$TOKEN"
# Apply Bearer token to all remote servers discovered from configs
mcp-scanner --analyzers yara --detailed known-configs --bearer-token "$TOKEN"
mcp-scanner --analyzers yara --format by_tool \
config --config-path "$HOME/.codeium/windsurf/mcp_config.json" --bearer-token "$TOKEN"
Use custom HTTP headers (e.g., MCP Gateway dual-token auth)
# Single custom header
mcp-scanner --analyzers yara remote --server-url https://your-mcp-server/mcp \
--header "X-API-Key: your-api-key"
# Multiple custom headers (MCP Gateway dual-token authentication)
mcp-scanner --analyzers yara remote --server-url https://gateway.example.com/mcp \
--header "Authorization: Bearer ingress-token" \
--header "X-Egress-Auth: Bearer egress-token"
> Note: Avoid specifying the same header via both --bearer-token and --header. If you use both --bearer-token and --header "Authorization: Bearer ", the custom header value will be used (custom headers are applied last and override any duplicates).
Scan Prompts
# Scan all prompts on an MCP server
mcp-scanner --analyzers llm prompts --server-url http://127.0.0.1:8000/mcp
# Scan all prompts with detailed output
mcp-scanner --analyzers llm --detailed prompts --server-url http://127.0.0.1:8000/mcp
# Scan all prompts with table format
mcp-scanner --analyzers llm --format table prompts --server-url http://127.0.0.1:8000/mcp
# Scan a specific prompt by name
mcp-scanner --analyzers llm prompts --server-url http://127.0.0.1:8000/mcp --prompt-name "greet_user"
# Get raw JSON output
mcp-scanner --analyzers llm --raw prompts --server-url http://127.0.0.1:8000/mcp
Scan Resour
…
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: cisco-ai-defense
- Source: cisco-ai-defense/mcp-scanner
- License: Apache-2.0
- Homepage: https://blogs.cisco.com/ai/securing-the-ai-agent-supply-chain-with-ciscos-open-source-mcp-scanner
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.