mcplint
Static security analyzer for MCP (Model Context Protocol) configurations.
Finds exploitable security issues in MCP tool definitions, explains why they're dangerous, and fails CI builds with evidence. Think clang-tidy / semgrep for MCP.
Quickstart
# Install from source
# Scan your Claude Desktop config
Install
Quick install (Linux / macOS):
|
Set MCPLINT_VERSION=v0.1.0 to pin a version, or MCPLINT_INSTALL_DIR to change the install location (default: ~/.local/bin).
Homebrew (macOS / Linux):
npm (Node.js 16+):
# or install globally
Cargo (requires Rust 1.75+):
From source:
&&
Prebuilt binaries — download from GitHub Releases:
| Platform | Target |
|---|---|
| Linux x86_64 | x86_64-unknown-linux-gnu |
| Linux ARM64 | aarch64-unknown-linux-gnu |
| macOS x86_64 | x86_64-apple-darwin |
| macOS ARM64 | aarch64-apple-darwin |
| Windows x86_64 | x86_64-pc-windows-msvc |
💡 Windows is fully supported — prebuilt binaries, all rules, and all output formats work on Windows. Use
mcplint.exeafter extracting.
# Example: Linux x86_64
Scan a directory containing MCP configs (auto-detects Claude Desktop, Cursor, or generic MCP inputs):
Export to canonical format first (useful for CI or reproducibility), then scan:
export writes mcp.config.json and per-server *.tools.json files into the output directory.
Usage
# Scan any MCP config (auto-detects format)
# Output as JSON (for CI) or Markdown (for PRs)
# SARIF output (for GitHub Code Scanning)
# Fail CI if high or critical issues found
# Export any config to canonical mcplint format
# List all rules
# Explain a specific rule
# Scan from stdin (pipe or pre-commit)
|
# Scan multiple files at once
# Scan a live MCP server (stdio transport)
# Scan a live MCP server (HTTP transport)
# Scan a live server with JSON output
Pre-commit Hook
mcplint can run as a pre-commit hook:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/mcplint/mcplint
rev: v0.1.0
hooks:
- id: mcplint
MCP Server Mode
mcplint can run as an MCP server, allowing AI agents (Claude, Cursor, etc.) to invoke security scanning directly:
# Start the MCP server on stdio
Add to your MCP client configuration (e.g., Claude Desktop):
This exposes three tools to AI agents:
mcplint_scan— Scan an MCP config file or raw JSON for security issuesmcplint_list_rules— List all available security rules with CWE/OWASP mappingsmcplint_explain— Get detailed remediation guidance for a specific rule
Exit Codes
mcplint uses CI-standard exit codes for predictable automation:
| Code | Meaning | Example |
|---|---|---|
| 0 | Success — no findings above threshold | Clean scan, or findings below --fail-on level |
| 1 | Operational error — bad input or misconfiguration | File not found, invalid JSON, unknown rule |
| 2 | Policy violation — findings above threshold | Findings at/above --fail-on severity detected |
CI usage
status=
if [; then
elif [; then
elif [; then
fi
The same exit codes apply to mcplint diff (exit 2 on new findings above --fail-on-new threshold) and mcplint baseline diff --fail-on-drift (exit 2 on risky drift).
Incremental CI with diff
For teams adopting mcplint on existing projects, mcplint diff enables incremental rollout: baseline your current findings, then only fail CI when new issues appear.
Step 1: Create a baseline
Step 2: Use diff in CI
Exit code 0 = no new high/critical findings. Safe to merge.
Step 3: Update the baseline as you fix issues
Options
--fail-on-new critical— only fail on new critical findings--fail-on-new none— report-only mode, never fail (not yet supported, defaults tolow)--format json— machine-readable diff output--format markdown— for PR comments
GitHub Actions example
- name: mcplint diff
run: mcplint diff ./configs --baseline .mcplint-baseline.json --fail-on-new high
Note:
mcplint diffcompares security findings. The existingmcplint baselinecommand compares server/tool configurations for drift detection. Both are useful and complementary.
When to use diff vs baseline
| Feature | mcplint diff |
mcplint baseline diff |
|---|---|---|
| Compares | Security findings (rule violations) | Server/tool configurations (capabilities) |
| Use case | Incremental CI adoption — suppress existing issues, catch new ones | Rug-pull detection — catch tool additions, capability changes |
| Tracks | Finding fingerprints (rule ID + location) | Tool names, capabilities, transport types |
| CI pattern | --fail-on-new high |
--fail-on-drift |
Use both together for defense-in-depth: diff catches new code issues, baseline catches supply-chain drift.
Rules
| ID | Category | CWE | OWASP | OWASP MCP | Description |
|---|---|---|---|---|---|
| MG001 | Static | CWE-77, CWE-89, CWE-78 | A03:2021 | MCP05, MCP06 | Unbounded string to dangerous sink (exec, SQL, fs, HTTP) |
| MG002 | Semantic | CWE-285 | A01:2021 | MCP02 | Tool description understates actual capabilities |
| MG003 | Compositional | CWE-269, CWE-284 | A01:2021 | MCP02, MCP03 | Source → amplifier → sink escalation chains |
| MG004 | Static | CWE-22, CWE-73 | A01:2021 | MCP05, MCP10 | Filesystem access without path confinement |
| MG005 | Static | CWE-306, CWE-287 | A07:2021 | MCP01, MCP07 | Missing or weak authentication |
| MG006 | Static | CWE-200, CWE-538 | A01:2021 | MCP01, MCP10 | Internal metadata leaked in descriptions |
| MG007 | Static | CWE-20 | A03:2021 | MCP02, MCP05 | Overly broad tool scopes (unconstrained parameters) |
| MG008 | Static | CWE-319 | A02:2021 | MCP01, MCP07 | Insecure transport (HTTP/WS instead of HTTPS/WSS) |
| MG009 | Static | CWE-798, CWE-522 | A07:2021 | MCP01, MCP09 | Environment variable leakage (secrets in env) |
All rules map to CWE, OWASP Top 10 2021, and OWASP MCP Top 10 2025 threat IDs. Run mcplint explain <RULE_ID> for full details.
Auto-Fix
mcplint can automatically remediate certain findings with --fix:
# Preview what would change (no file modification)
# Apply fixes and re-scan
| Rule | Auto-Fix | What it does |
|---|---|---|
| MG001 | ✅ | Adds maxLength: 1000 to unbounded string parameters |
| MG002 | ❌ | Requires manual description update |
| MG003 | ❌ | Requires architectural changes |
| MG004 | ✅ | Adds allowedDirectories: ["."] to filesystem parameters |
| MG005 | ✅ | Adds auth: { type: "bearer", token: "REPLACE_ME" } placeholder |
| MG006 | ✅ | Replaces leaked metadata (IPs, paths, connection strings) with [REDACTED] |
| MG007 | ❌ | Requires manual schema constraints |
| MG008 | ❌ | Requires infrastructure changes (TLS) |
| MG009 | ❌ | Requires manual secret management |
⚠️ MG005 fix inserts a
REPLACE_MEplaceholder. Search your config forREPLACE_MEand substitute actual credentials.
💡 Recommendation: Always run
--fix-dry-runfirst to review changes before applying.
Notes:
--fixand--fix-dry-runare mutually exclusive.--fixonly works on single files, not directories.- After
--fix, mcplint re-scans and reports remaining (unfixable) findings.
Input Formats
Auto-detected — pass any of these to mcplint scan:
| Format | Detected by |
|---|---|
mcp.tools.json |
Filename contains "tools" |
mcp.config.json |
Native multi-server config |
claude_desktop_config.json |
Claude Desktop MCP config |
.cursor/mcp.json |
Cursor MCP config (file or parent directory) |
.vscode/mcp.json |
VS Code MCP config (project-level or settings.json with "mcp" wrapper) |
.cline/mcp_settings.json |
Cline MCP config (also .cline/mcp.json); skips disabled servers |
*windsurf*/mcp_config.json |
Windsurf/Codeium MCP config (also .windsurf/mcp.json) |
.continue/mcpServers/*.yaml|*.json |
Continue.dev MCP config (also .continue/config.yaml) |
*/zed/settings.json |
Zed editor MCP config (context_servers key; supports JSONC comments) |
*.json with mcpServers |
Generic heuristic |
See docs/export-format.md for the full schema reference, validation rules, and adapter examples.
Minimal example (mcp.tools.json):
Configuration
Create a .mcplint.toml in your project root (or any parent directory of
the scan target) to customize behavior without repeating CLI flags.
= "high"
= "sarif"
[]
= ["MG006"]
= [
{ = "MG001", = "run_sql", = "wrapped with allowlisted queries" },
{ = "MG004", = "filesystem", = "sandboxed container path only" },
]
[]
= "low"
Discovery: mcplint scan searches upward from the scan target for
.mcplint.toml. Use --config <path> to specify an explicit config or
--no-config to disable discovery entirely. CLI flags (--format, --fail-on)
always override config values.
Severity overrides can only downgrade findings (never escalate) to prevent accidental suppression of new critical issues.
GitHub Action
Quick start — 3 lines
- uses: actions/checkout@v4
- uses: mcplint/mcplint/.github/action@v1
with:
path: .
This scans all MCP configs, uploads SARIF to Code Scanning, and fails on high/critical findings.
Full scan with all options
jobs:
mcplint:
runs-on: ubuntu-latest
permissions:
security-events: write # for SARIF upload
contents: read
pull-requests: write # for PR comments
steps:
- uses: actions/checkout@v4
- uses: mcplint/mcplint/.github/action@v1
id: mcplint
with:
path: './configs'
format: sarif
fail-on: high
config: .mcplint.toml
upload-sarif: 'true'
comment-on-pr: 'true'
- run: echo "Found ${{ steps.mcplint.outputs.findings-count }} findings"
Incremental rollout with baseline diff
For existing projects, use diff mode to only fail on new findings:
jobs:
mcplint:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
- uses: mcplint/mcplint/.github/action@v1
with:
mode: diff
path: './configs'
baseline: .mcplint-baseline.json
fail-on-new: high
comment-on-pr: 'true'
upload-sarif: 'false'
Create the baseline and commit it:
&&
Conditional steps based on results
- uses: mcplint/mcplint/.github/action@v1
id: mcplint
with:
fail-on: high
continue-on-error: true
- if: steps.mcplint.outputs.exit-code == '2'
run: echo "Security findings detected — blocking merge"
- if: steps.mcplint.outputs.exit-code == '0'
run: echo "All clear"
Action outputs
| Output | Description |
|---|---|
findings-count |
Total findings |
critical-count |
Critical severity count |
high-count |
High severity count |
new-findings-count |
New findings (diff mode) |
resolved-findings-count |
Resolved findings (diff mode) |
exit-code |
0=clean, 1=error, 2=violations |
sarif-file |
Path to SARIF file |
baseline-file |
Path to saved baseline |
See .github/action/action.yml for the full
input/output reference.
Manual CI setup (without the Action)
If you prefer manual setup, mcplint produces SARIF output compatible with GitHub Code Scanning:
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- run: cargo install mcplint-cli
- run: mcplint scan . --format sarif > results.sarif
- uses: github/codeql-action/upload-sarif@v4
if: always()
with:
sarif_file: results.sarif
category: mcplint
- run: mcplint scan . --fail-on high
Baseline & Drift Detection
mcplint can create a deterministic fingerprint of your MCP configuration and detect capability drift ("rug-pull" detection) between runs.
Create a baseline:
Compare current config against a saved baseline:
Fail CI if risky drift is detected (new dangerous tools, capability expansion, transport changes from local to remote):
Output formats: --format text (default), --format json, --format markdown.
What counts as "risky drift"?
- A new server or tool with
exec,fs_write,net, ordbcapabilities - An existing tool gaining any of those capability flags
- Transport change from
stdio(local) tohttp/sse(remote)
Advanced Examples
Multi-config CI pipeline with SARIF
Scan all MCP configs across your project and upload results to GitHub Code Scanning:
# Scan all configs, output SARIF for GitHub
# In GitHub Actions, upload to Code Scanning:
# - uses: github/codeql-action/upload-sarif@v3
# with:
# sarif_file: mcplint.sarif
Custom policy with severity overrides
Create .mcplint.toml to tailor mcplint to your risk tolerance:
# Ignore MG005 (auth) for local-only stdio servers
[[]]
= "MG005"
= "local-dev-*"
# Downgrade MG007 (broad scopes) from high to medium in dev
[[]]
= "MG007"
= "medium"
Live MCP server scanning
Connect to a running MCP server and scan its live tool definitions:
# Scan a server via SSE
# Scan and output JSON
Pre-commit hook
Add mcplint to your Git pre-commit workflow:
# .pre-commit-config.yaml (using stdin for changed files)
Drift detection in CI
Detect tool capability changes between deployments:
# Save baseline after deploying
# In CI, detect drift
Migration from mcp-guard
This project was previously named mcp-guard and has been renamed to mcplint.
- Binary:
mcp-guard→mcplint - Config file:
.mcp-guard.toml→.mcplint.toml - Crates:
mcp_guard_*→mcplint_*
Backward compatibility: .mcp-guard.toml is still recognized during config
discovery with a deprecation warning. If both .mcplint.toml and .mcp-guard.toml
exist, .mcplint.toml takes precedence.
License
Apache-2.0