Skip to main content

Security scanner for MCP servers — Python + TypeScript/JavaScript, zero dependencies, 57+ rules, plugin system, live scanner, fleet scanning, policy engine, OWASP Agentic Top 10

Project description

mcpaudit

Static security scanner for MCP servers -- zero dependencies, AST-based, 20 rules, <200ms.

python 3.11+ | zero dependencies | MIT license


Quick Start

# Install
pip install -e .

# Scan a file
mcpaudit /path/to/server.py

# Scan a directory
mcpaudit /path/to/mcp-servers/

# JSON output for CI/CD
mcpaudit /path/to/server.py --format json

# HTML report
mcpaudit /path/to/server.py --format html --output report.html

# SARIF output (GitHub Code Scanning, VS Code SARIF Viewer)
mcpaudit /path/to/server.py --format sarif -o results.sarif

# Generate default config file
mcpaudit --init

Why mcpaudit?

AI-Infra-Guard (Tencent) mcpaudit
Requirements Docker + 4GB RAM + LLM API key Python 3.11+ (stdlib only)
Speed Minutes (API calls) <200ms (static analysis)
Method ReAct agent with LLM AST + regex pattern matching
Cost LLM API calls $0 (everything local)
Dependencies Docker, LLM SDK None (stdlib only)
CI/CD Manual Exit codes + JSON + HTML + SARIF

Security Rules (20)

Every finding includes a CWE reference for standards traceability and a confidence level (HIGH, MEDIUM, or LOW) indicating detection accuracy.

Rule ID Severity What it Detects CWE
CMD-001 CRITICAL Command injection -- subprocess with shell=True CWE-78
CMD-002 HIGH Command injection -- subprocess with f-strings or string concatenation CWE-78
SQL-001 CRITICAL SQL injection -- queries with string interpolation CWE-89
SEC-001 CRITICAL Hardcoded secrets -- API keys, tokens, passwords in source code CWE-798
DESER-001 CRITICAL Unsafe deserialization -- yaml.load(), arbitrary code execution CWE-502
PATH-001 HIGH Path traversal -- file operations on user input without resolve()/is_relative_to() CWE-22
PATH-002 MEDIUM Hardcoded absolute paths -- /Users/, /home/, C:\Users\ --
PERM-001 HIGH Excessive permissions (chmod 777) CWE-250
AUTH-001 MEDIUM Missing authentication in server code CWE-306
CORS-001 MEDIUM CORS wildcard (Access-Control-Allow-Origin: *) CWE-942
VAL-001 MEDIUM Missing input validation in MCP handler functions --
REDOS-001 MEDIUM ReDoS -- regex with nested quantifiers --
RATE-001 LOW Missing rate limiting in server code CWE-770
TEMP-001 LOW Insecure temporary file creation CWE-377
SSRF-001 HIGH Server-Side Request Forgery -- HTTP requests with dynamic URLs CWE-918
FILE-001 HIGH Unsafe file write -- open() with dynamic path in write mode CWE-73
ERR-001 MEDIUM Missing error handling in MCP tool handler functions CWE-755
LOG-001 MEDIUM Sensitive data in logs -- logging secrets, tokens, passwords CWE-532
RES-001 MEDIUM Resource exhaustion -- unbounded reads, missing timeouts CWE-400
INFO-001 LOW Information disclosure -- detailed exceptions returned to users --

Configuration File

mcpaudit supports a .mcpaudit.yml configuration file for persistent project-level settings.

Generate default config

mcpaudit --init

This creates a .mcpaudit.yml in the current directory with all options commented out.

Use a custom config

mcpaudit /path/to/code --config .mcpaudit.yml

If no --config flag is passed, mcpaudit automatically loads .mcpaudit.yml from the current working directory when present.

Configuration options

# .mcpaudit.yml

# Disable specific rules by ID
exclude_rules:
  - AUTH-001
  - RATE-001

# Skip files/directories matching these glob patterns
exclude_paths:
  - "tests/*"
  - "vendor/*"

# Only show findings at or above this severity level
# Values: critical, high, medium, low, info
severity_threshold: medium

# Default output format: text, json, html, sarif
output_format: text

CLI flags (--format, --severity) override config file values when both are specified.

Output Formats

Terminal (default)

============================================================
  MCP Security Audit -- Resultados
============================================================
  Archivos escaneados: 1
  Lineas escaneadas: 150
  Hallazgos totales: 3
============================================================

  [FILE] server.py
     Grade: C | 3 hallazgos | 12.3ms

     [!!] [CMD-001] Command Injection (shell=True)
       Linea 42: subprocess.run() con shell=True.
       Codigo: subprocess.run(cmd, shell=True)
       Fix: Usar lista de argumentos sin shell=True.

     [!] [PATH-001] Posible Path Traversal
       Linea 18: Funcion open() sin validacion de path.
       Fix: Usar path.resolve() y path.is_relative_to(base_dir).

     [-] [AUTH-001] Sin autenticacion detectada
       Linea 1: El servidor MCP no implementa autenticacion.
============================================================

JSON (for CI/CD)

{
  "summary": {
    "files_scanned": 1,
    "total_findings": 3,
    "overall_grade": "C",
    "severity_counts": {
      "CRITICAL": 1,
      "HIGH": 1,
      "MEDIUM": 1,
      "LOW": 0,
      "INFO": 0
    },
    "exit_code": 2
  },
  "results": [...]
}

Each finding in results includes cwe (e.g., "CWE-78") and confidence (e.g., "HIGH") fields.

HTML Report

Self-contained dark-themed HTML with dashboard, severity breakdown, and detailed findings. Generate with:

mcpaudit /path/to/code --format html --output report.html

SARIF (Static Analysis Results Interchange Format)

SARIF 2.1.0 output for integration with industry-standard tooling:

  • GitHub Code Scanning -- upload via github/codeql-action/upload-sarif
  • VS Code SARIF Viewer -- view findings inline in your editor
  • Azure DevOps -- native SARIF support in pipelines
  • Any SARIF-compatible viewer -- standard OASIS format
mcpaudit /path/to/code --format sarif -o results.sarif

Each SARIF result includes security-severity scores (0--10 scale), CWE tags, confidence-based precision levels, and inline fix suggestions.

Upload to GitHub Code Scanning

# In your GitHub Actions workflow
- run: mcpaudit . --format sarif -o results.sarif
- uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: results.sarif

Grading System

Grade Weighted Score Meaning
A+ 0 No findings
A 1-2 Minor issues only
B 3-5 Some medium issues
C 6-10 High severity findings
D 11-20 Multiple high severity
F 21+ Critical issues present

Exit Codes

Code Meaning
0 No HIGH or CRITICAL findings
1 HIGH findings present
2 CRITICAL findings present

CI/CD Integration

GitHub Actions

# .github/workflows/security.yml
name: Security Scan
on: [push, pull_request]

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      - run: pip install -e path/to/mcpaudit
      - run: mcpaudit . --format json --output results.json
      - run: mcpaudit . --format html --output report.html
      - run: mcpaudit . --format sarif --output results.sarif
      - uses: actions/upload-artifact@v4
        with:
          name: security-report
          path: |
            report.html
            results.json
      - uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: results.sarif

A reusable workflow is included at .github/workflows/security-scan.yml.

Pre-commit Hook

cp hooks/pre-commit .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit

Blocks commits with HIGH or CRITICAL findings.

Baseline (Suppress Known Findings)

Accept existing findings to only fail on new security issues:

# Step 1: Create baseline from current state
mcpaudit . --create-baseline .mcpaudit-baseline.json

# Step 2: In CI/CD, scan with baseline — only NEW findings trigger failure
mcpaudit . --baseline .mcpaudit-baseline.json

Fingerprints are stable across line number changes — a finding is only un-suppressed if the code itself changes.

Architecture

mcpaudit/
|
|-- __init__.py          # Package exports (MCPSecurityScanner, models)
|-- __main__.py          # CLI entry point (mcpaudit command)
|-- scanner.py           # Core scanning engine
|-- models.py            # Data classes (Finding, ScanResult, Severity, etc.)
|-- formatters.py        # Text and JSON output formatters
|-- config.py            # Configuration file loader (.mcpaudit.yml)
|
|-- rules/               # Modular security rules (20 rules)
|   |-- __init__.py      # Rule base class + get_all_rules()
|   |-- path_traversal.py
|   |-- command_injection.py
|   |-- hardcoded_secrets.py
|   |-- absolute_paths.py
|   |-- input_validation.py
|   |-- sql_injection.py
|   |-- unsafe_deser.py
|   |-- info_disclosure.py
|   |-- missing_auth.py
|   |-- cors_misconfig.py
|   |-- unsafe_temp.py
|   |-- excessive_perms.py
|   |-- redos.py
|   |-- rate_limiting.py
|   |-- ssrf.py           # SSRF detection
|   |-- unsafe_file_write.py # Dynamic path write detection
|   |-- error_handling.py  # Missing try/except in tool handlers
|   |-- sensitive_logging.py # Secrets in log statements
|   |-- resource_exhaustion.py # Unbounded reads, missing timeouts
|
|-- reporters/           # Report generators
|   |-- html_reporter.py # Self-contained HTML report (dark theme)
|   |-- sarif_reporter.py # SARIF 2.1.0 output (GitHub, VS Code, etc.)
|
|
|-- examples/           # Demo files
|   |-- vulnerable_server.py  # Intentionally vulnerable MCP server (26 findings)
|
tests/
|   |-- test_scanner.py    # Core scanner tests
|   |-- test_sarif.py      # SARIF output validation
|   |-- test_config.py     # Config file tests
|   |-- test_new_rules.py  # Tests for SSRF, FILE, ERR, LOG, RES rules
|
hooks/
|   |-- pre-commit       # Git pre-commit hook
|
.github/workflows/
    |-- security-scan.yml  # Reusable GitHub Actions workflow

CWE Reference Table

All rule CWE mappings at a glance:

Rule ID CWE ID CWE Name
CMD-001, CMD-002 CWE-78 OS Command Injection
SQL-001 CWE-89 SQL Injection
AUTH-001 CWE-306 Missing Authentication for Critical Function
PATH-001 CWE-22 Path Traversal
DESER-001 CWE-502 Deserialization of Untrusted Data
CORS-001 CWE-942 Overly Permissive Cross-domain Whitelist
RATE-001 CWE-770 Allocation of Resources Without Limits
PERM-001 CWE-250 Execution with Unnecessary Privileges
TEMP-001 CWE-377 Insecure Temporary File
SEC-001 CWE-798 Use of Hard-coded Credentials
SSRF-001 CWE-918 Server-Side Request Forgery
FILE-001 CWE-73 External Control of File Name or Path
ERR-001 CWE-755 Improper Handling of Exceptional Conditions
LOG-001 CWE-532 Insertion of Sensitive Information into Log File
RES-001 CWE-400 Uncontrolled Resource Consumption

Adding Custom Rules

from mcpaudit.rules import Rule
from mcpaudit.models import Finding, Severity

class MyCustomRule(Rule):
    @property
    def rule_id(self) -> str:
        return "CUSTOM-001"

    @property
    def name(self) -> str:
        return "My Custom Check"

    @property
    def severity(self) -> Severity:
        return Severity.HIGH

    @property
    def description(self) -> str:
        return "Detects my custom pattern."

    def check(self, tree, source) -> list[Finding]:
        findings = []
        # Your detection logic here
        return findings

# Use it
from mcpaudit.scanner import MCPSecurityScanner
scanner = MCPSecurityScanner(rules=[MyCustomRule()])

License

MIT License. Created by Carlos Miret.

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

mcpaudit-1.0.0.tar.gz (183.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mcpaudit-1.0.0-py3-none-any.whl (157.7 kB view details)

Uploaded Python 3

File details

Details for the file mcpaudit-1.0.0.tar.gz.

File metadata

  • Download URL: mcpaudit-1.0.0.tar.gz
  • Upload date:
  • Size: 183.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.6

File hashes

Hashes for mcpaudit-1.0.0.tar.gz
Algorithm Hash digest
SHA256 444c5b5d09006507e69d7279e38ca1e9ab4e609a95c600e37f0d4fcb1b37c90d
MD5 4b2a47a3823755a2ab8bd957e0d086d0
BLAKE2b-256 d2c982febf8ec89b595650b5945b70a8716ee1a71dab510e1a8ae4def6c8ee54

See more details on using hashes here.

File details

Details for the file mcpaudit-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: mcpaudit-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 157.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.6

File hashes

Hashes for mcpaudit-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f2e269a98d31c444af9f6faf1d3c34089d582913272f7262d0b9c604270089f0
MD5 39ddc0664a3575e7fdb737240fe461cf
BLAKE2b-256 e37fe9d930f6aa035bf33d1a04870e9d4784fa543aa9c190fc5753a5b4a2867c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page