Scan projects for AI and MCP-related secrets before they leak.
Project description
mcp-guard
mcp-guard is a Python CLI for finding leaked secrets in MCP and AI-agent project files before they reach GitHub.
It recursively scans a file or directory, pays special attention to MCP config files, masks every detected value, assigns severity levels, and exits non-zero when findings meet your configured threshold.
What Is mcp-guard?
AI agents and MCP servers often need API keys in files such as .cursor/mcp.json, .vscode/mcp.json, claude_desktop_config.json, .env, and local config files. Those files are easy to commit by mistake.
mcp-guard gives you a lightweight pre-push or CI check for these leaks. It is designed for developer workflows, open-source projects, and portfolio repos where you want a readable terminal report plus machine-readable JSON for automation.
Install
Install from PyPI with pipx:
pipx install mcp-secrets-guard
Or install the latest version from GitHub:
pipx install git+https://github.com/chiragborse1/mcp-guard.git
From a local checkout:
python -m pip install .
For local development:
python -m pip install -e ".[dev]"
Usage
mcp-guard <path>
Examples:
mcp-guard --version
mcp-guard .
mcp-guard ./mcp.json
mcp-guard . --fail-on high
mcp-guard --json .
mcp-guard . --sarif mcp-guard.sarif
mcp-guard . --staged
Exit codes:
0: no findings at or above the configured failure severity1: findings exist at or above the configured failure severity2: scan could not run, such as a missing path
Severity
Each finding has a severity:
high: known credentials such as OpenAI, Anthropic, GitHub tokens, Postgres URLs, Supabase keys, and most provider API keysmedium: generic secret assignments and lower-confidence sensitive valueslow: reserved for future lower-risk checks
By default, mcp-guard behaves as --fail-on low, so any finding exits 1.
Use --fail-on to control CI strictness:
mcp-guard . --fail-on high
mcp-guard . --fail-on medium
mcp-guard . --fail-on low
For example, --fail-on high still prints medium findings, but exits 0 unless a high-severity finding exists.
Staged Files
Use --staged to scan only files currently staged in Git:
mcp-guard . --staged
This is useful in pre-commit hooks because local untracked files and unstaged work are ignored.
Example pre-commit configuration:
repos:
- repo: local
hooks:
- id: mcp-guard
name: mcp-guard
entry: mcp-guard . --staged --fail-on high
language: system
pass_filenames: false
The same example is available at examples/pre-commit/.pre-commit-config.yaml.
JSON Output
mcp-guard --json .
Example:
{
"root": "/path/to/project",
"files_scanned": 3,
"files_skipped": 0,
"findings": [
{
"path": ".env",
"line": 1,
"column": 16,
"kind": "OpenAI API key",
"severity": "high",
"masked_secret": "sk-p...7890",
"context": "OPENAI_API_KEY=sk-p...7890",
"is_mcp_config": false
}
]
}
Secrets are masked in both text and JSON output.
SARIF Output
Use SARIF when you want to upload findings to GitHub code scanning:
mcp-guard . --sarif mcp-guard.sarif
SARIF output includes rule metadata, severity-mapped levels, file locations, and masked values only. The command still prints normal terminal output and uses the same --fail-on exit-code behavior.
For a permissive code-scanning upload that records medium findings but only fails on high severity:
mcp-guard . --fail-on high --sarif mcp-guard.sarif
Ignoring Files
Create a .mcpguardignore file in the scanned project root to ignore known-safe paths, such as test fixtures or intentionally unsafe examples.
Example:
# Test fixtures intentionally use fake secrets.
tests/
examples/unsafe-mcp-config/
*.snapshot
When you scan a directory directly, mcp-guard reads that directory's own .mcpguardignore. This repo ignores examples/unsafe-mcp-config/ during root scans, but you can still scan that folder directly.
For a single known-safe fake value, add an inline allow comment on the same line or the line immediately before it:
# mcp-guard: allow - fake local fixture
OPENAI_API_KEY=sk-p...7890
ANTHROPIC_API_KEY=sk-a...7890 # mcp-guard: ignore
Use allow comments sparingly. Prefer .mcpguardignore for whole fixture directories.
Example Scan
This repo includes fake unsafe files for testing:
mcp-guard examples/unsafe-mcp-config
Expected output includes masked fake findings:
mcp-guard scanned 3 file(s) under /path/to/mcp-guard/examples/unsafe-mcp-config
Found 6 possible secret(s):
HIGH .cursor/mcp.json:7:31 Firecrawl API key [MCP config] -> fc_f...7890
JSON:
mcp-guard --json examples/unsafe-mcp-config
What It Detects
mcp-guard looks for:
- OpenAI and Anthropic API keys
- GitHub tokens
- Postgres connection URLs
- Supabase URLs and JWT-style keys
- Pinecone, Qdrant, Firecrawl, Brave Search, and Perplexity keys
- Generic
api_key,password,secret, andtokenassignments
It gives special attention to MCP configuration files, including:
mcp.jsonclaude_desktop_config.json.cursor/mcp.json.vscode/mcp.json
The scanner skips .git, node_modules, dist, build, .next, venv, .venv, and __pycache__.
GitHub Actions
Add this workflow to .github/workflows/mcp-guard.yml:
name: mcp-guard
on:
pull_request:
push:
branches: [main]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install pipx
run: python -m pip install --user pipx
- name: Install mcp-guard
run: pipx install mcp-secrets-guard
- name: Scan repository
run: mcp-guard . --fail-on high
GitHub code scanning with SARIF upload:
name: mcp-guard-sarif
on:
pull_request:
push:
branches: [main]
permissions:
security-events: write
contents: read
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install pipx
run: python -m pip install --user pipx
- name: Install mcp-guard
run: pipx install mcp-secrets-guard
- name: Scan repository
run: mcp-guard . --fail-on high --sarif mcp-guard.sarif
- name: Upload SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: mcp-guard.sarif
You can also use the bundled composite action:
name: mcp-guard-action
on:
pull_request:
permissions:
security-events: write
contents: read
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: chiragborse1/mcp-guard/.github/actions/mcp-guard@v1.0.1
with:
path: "."
fail-on: high
sarif: mcp-guard.sarif
- name: Upload SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: mcp-guard.sarif
For PR-only terminal scanning without SARIF:
name: mcp-guard-pr
on:
pull_request:
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: chiragborse1/mcp-guard/.github/actions/mcp-guard@v1.0.1
with:
path: "."
fail-on: high
Development
Run tests:
uv run --extra dev pytest -q
Run the local CLI:
uv run --extra dev mcp-guard .
See CONTRIBUTING.md for contribution guidelines and docs/RELEASE_CHECKLIST.md for release steps.
Release history is tracked in CHANGELOG.md.
The current roadmap and future ideas are tracked in docs/ROADMAP.md.
License
MIT
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 mcp_secrets_guard-1.0.1.tar.gz.
File metadata
- Download URL: mcp_secrets_guard-1.0.1.tar.gz
- Upload date:
- Size: 16.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9585344a1e0ecd60127af92d6a1430c2b74e7ea9ebbf07b3da0b7550159ae399
|
|
| MD5 |
14f9c5696e4de46ae1be90a793197ef0
|
|
| BLAKE2b-256 |
e74379499c2d30f1c7863dadb491e569db1efaa15b7a1188f195f7399395440c
|
Provenance
The following attestation bundles were made for mcp_secrets_guard-1.0.1.tar.gz:
Publisher:
publish.yml on chiragborse1/mcp-guard
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_secrets_guard-1.0.1.tar.gz -
Subject digest:
9585344a1e0ecd60127af92d6a1430c2b74e7ea9ebbf07b3da0b7550159ae399 - Sigstore transparency entry: 1520685511
- Sigstore integration time:
-
Permalink:
chiragborse1/mcp-guard@820d8db34ebe0bc5dedaf9b98e11ce6a497fc523 -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/chiragborse1
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@820d8db34ebe0bc5dedaf9b98e11ce6a497fc523 -
Trigger Event:
release
-
Statement type:
File details
Details for the file mcp_secrets_guard-1.0.1-py3-none-any.whl.
File metadata
- Download URL: mcp_secrets_guard-1.0.1-py3-none-any.whl
- Upload date:
- Size: 12.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
45f7c38be5afc95d6652d44dbdf01cc34fa3130792292abdf2d5551cfedc5f9d
|
|
| MD5 |
88590b3121c842ad3e3a065808af9e5f
|
|
| BLAKE2b-256 |
d5b0d1c4d582381083cf4dba9a145cb261c0cdc7ea2101109b672a48c5d77a1e
|
Provenance
The following attestation bundles were made for mcp_secrets_guard-1.0.1-py3-none-any.whl:
Publisher:
publish.yml on chiragborse1/mcp-guard
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_secrets_guard-1.0.1-py3-none-any.whl -
Subject digest:
45f7c38be5afc95d6652d44dbdf01cc34fa3130792292abdf2d5551cfedc5f9d - Sigstore transparency entry: 1520685574
- Sigstore integration time:
-
Permalink:
chiragborse1/mcp-guard@820d8db34ebe0bc5dedaf9b98e11ce6a497fc523 -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/chiragborse1
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@820d8db34ebe0bc5dedaf9b98e11ce6a497fc523 -
Trigger Event:
release
-
Statement type: