mcp-sanity-check

mcp-sanity-check

Scans repositories for owner identifiers and secrets, blocking pushes or CI merges if any are found.

Category
访问服务器

README

mcp-sanity-check

A dependency-light CLI that scans a repository's tracked files for owner identifiers and secrets, then exits non-zero if it finds any. Drop it into CI or a pre-push hook and private data cannot ship into a public repo.

What problem it solves

When you maintain a fleet of MCP servers (or any set of personal automation repos) that you plan to publish publicly, a single slip can embed your home IP, email, device hostname, or an API key in the Git history forever. mcp-sanity-check is the last gate before a push or a CI merge — it scans every tracked file and blocks the operation if anything personal is found.

The tool ships with no owner identifiers baked in, so the scanner itself can live in a public repo without leaking anyone's data. Your specific strings (emails, account IDs, home-LAN IPs, device names) stay in ~/.config/mcp-sanity/identifiers.json on your machine and are never committed anywhere.

Install

One-liner via npx (no install needed):

npx -y github:nidamen/mcp-sanity-check-mcp --path /path/to/repo

Or install globally:

npm install -g mcp-sanity-check
mcp-sanity-check --path /path/to/repo

Or run from a local checkout:

node bin/mcp-sanity-check.mjs --path /path/to/repo

Requires Node >= 18. Zero runtime dependencies.

MCP client configuration

This tool runs as a stdio MCP server. Add it to your MCP client config:

{
  "mcpServers": {
    "mcp-sanity-check": {
      "command": "npx",
      "args": ["-y", "github:nidamen/mcp-sanity-check-mcp"],
      "env": {}
    }
  }
}

To use your private identifier list, set the MCP_SANITY_IDENTIFIERS environment variable to the path of your identifiers.json:

{
  "mcpServers": {
    "mcp-sanity-check": {
      "command": "npx",
      "args": ["-y", "github:nidamen/mcp-sanity-check-mcp"],
      "env": {
        "MCP_SANITY_IDENTIFIERS": "/Users/you/.config/mcp-sanity/identifiers.json"
      }
    }
  }
}

CLI usage

mcp-sanity-check [--path <dir>] [--staged] [--range <a..b>] [--json] [--quiet] [--no-color]
Flag Description
--path <dir> Directory to scan. Default: current working directory.
--staged Scan only staged (index) added lines. For use in a pre-commit hook.
--range <a..b> Scan only lines added in the given git commit range. Used by pre-push.
--json Emit a machine-readable JSON report. Values are still masked.
--quiet Suppress per-hit lines; print only the summary.
--no-color Disable ANSI color. Also honored via the NO_COLOR environment variable.

Exit codes: 0 = clean, 1 = one or more hits found, 2 = usage error (bad path, etc.).

Complete tool reference

This is a CLI tool, not an MCP tool-calling server. The scanner exposes one capability: scan a directory and report leaks.

mcp-sanity-check (CLI / binary)

Purpose: Scan a repository for owner identifiers and secrets and exit non-zero if any are found.

Modes:

Mode Trigger flag What is scanned
Full scan (no flag, default) All git-tracked files, or full directory walk if not a git repo
Staged scan --staged Only added lines in the git index (git diff --cached)
Range scan --range <sha1>..<sha2> Only added lines in the given commit range

Input parameters:

Parameter Type Required Default Description
--path string No process.cwd() Absolute or relative path to the repo root
--staged boolean No false Enable staged-lines-only mode
--range string No null Git commit range string (a..b)
--json boolean No false Emit JSON instead of colored text
--quiet boolean No false Suppress per-hit lines
--no-color boolean No false Disable ANSI color codes

Returns (human mode):

✓ mcp-sanity-check: clean (42 files scanned)

or on a hit:

✗ mcp-sanity-check: 2 potential leak(s) found
  SECRET    config.env:3  github-personal-access-token (ghp_)  -> ghp_****...ab
  IDENTIFIER src/client.js:7  owner-identifier:you@example.com  -> you@****
BLOCKED: 2 hit(s) across 42 files. Remove the values above, ...

Returns (JSON mode, --json):

{
  "ok": false,
  "filesScanned": 42,
  "hitCount": 2,
  "mode": "full",
  "hits": [
    {
      "file": "config.env",
      "line": 3,
      "class": "secret",
      "pattern": "github-personal-access-token (ghp_)",
      "masked": "ghp_****...ab"
    }
  ]
}

Fields in each hit object:

Field Type Description
file string Relative path of the file containing the hit
line number 1-indexed line number
class string "identifier", "pii", or "secret"
pattern string Human-readable name of the rule that matched
masked string First 4 + last 2 chars of the value; middle replaced with *

What gets flagged

Owner identifiers

Loaded at runtime from (in priority order):

  1. Path in $MCP_SANITY_IDENTIFIERS environment variable (points to a JSON file).
  2. ~/.config/mcp-sanity/identifiers.json (default private config location).
  3. identifiers array in the scanned repo's .sanity-patterns.json.

The JSON file must be an object with an identifiers array of strings:

{ "identifiers": ["your@email.com", "192.168.1.50", "myhostname", "acct-id-xyz"] }

This file is never committed anywhere. It lives only on your machine.

Generic PII (public CI backstop)

Even without a private identifier list, the scanner catches:

Pattern name What it matches
email-address Any user@domain.tld email
private-ipv4 (RFC1918) 10.x.x.x, 192.168.x.x, 172.16-31.x.x addresses
personal-home-path /Users/<name> or /home/<name> path segments
mac-address Six colon-separated hex octets

Obvious documentation placeholders (you@example.com, 192.168.1.1, /home/user, aa:bb:cc:dd:ee:ff, etc.) are excluded so docs and examples do not trip the backstop.

Secret patterns

Pattern name Shape matched
github-personal-access-token (ghp_) ghp_ + 20+ alphanumeric chars
github-fine-grained-pat github_pat_ + 20+ chars
openai-api-key (sk-) sk- + 20+ alphanumeric/dash/underscore chars
slack-token (xox*) xoxb-, xoxa-, xoxp-, xoxr-, xoxs- + 10+ chars
aws-access-key-id (AKIA) AKIA + 16 uppercase alphanumeric chars
google-api-key (AIza) AIza + 30+ alphanumeric chars
private-key-block -----BEGIN ... PRIVATE KEY-----
high-entropy-assignment *key/secret/token/password* = "40+ high-entropy chars"

The high-entropy rule fires only when the assigned value is 40+ characters, base64-ish, and clears a Shannon-entropy threshold (H >= 3.5 bits/char, 12+ distinct characters). This keeps false positives low on long-but-repetitive strings.

All matched values are masked in output: the first 4 and last 2 characters are shown; everything in between is replaced with *.

Private config: ~/.config/mcp-sanity/

The directory ~/.config/mcp-sanity/ is the one place the owner's specific identifiers live. It is:

  • Never committed (it sits outside any repo).
  • Never referenced by path in any tracked file.
  • Loaded at runtime by the scanner binary on the machine where the private list is needed.

Structure:

~/.config/mcp-sanity/
  identifiers.json      <- {"identifiers": ["your@email.com", "192.168.1.50", ...]}

How a repo opts in

Option 1: CI workflow

Copy .github/workflows/sanity-check.yml from this repo into the target repo. It runs on every push and PR using ubuntu-latest + Node 20, fetches the full history, and fails the build on any hit.

It can also be called as a reusable workflow:

jobs:
  sanity:
    uses: nidamen/mcp-sanity-check/.github/workflows/sanity-check.yml@main

Option 2: Pre-push git hook

Install hooks/pre-push so leaks are blocked before they ever reach the remote. The hook scans only the outgoing commit range, so it is fast.

# Per-repo:
cp /path/to/mcp-sanity-check/hooks/pre-push /path/to/your-repo/.git/hooks/pre-push
chmod +x /path/to/your-repo/.git/hooks/pre-push

# Shared across all repos (global hooks dir):
mkdir -p ~/.git-hooks
cp /path/to/mcp-sanity-check/hooks/pre-push ~/.git-hooks/pre-push
chmod +x ~/.git-hooks/pre-push
git config --global core.hooksPath ~/.git-hooks

The hook resolves the scanner via (in order): $MCP_SANITY_CHECK env var (full path to the .mjs), mcp-sanity-check on PATH, or npx mcp-sanity-check.

To bypass intentionally (not recommended): git push --no-verify.

Per-repo tuning: .sanity-patterns.json

Place a .sanity-patterns.json file at the scanned repo's root to extend or relax the defaults:

{
  "identifiers": ["ACME_INTERNAL_CODENAME", "another-owner-string"],
  "allow":       ["EXAMPLE_PLACEHOLDER"],
  "allowFiles":  ["docs/sample-output.txt", "test/fixtures/"]
}
Key Type Effect
identifiers string array Added to the runtime identifier list. Case-insensitive substring match.
allow string array If a flagged line contains any allow-string, the hit is dropped. For known false positives and sample data.
allowFiles string array File-path substrings: any file whose relative path contains one of these is skipped entirely. Use sparingly, only for files that legitimately define or document the patterns.

Quick usage examples

Check a repo before publishing:

mcp-sanity-check --path ~/code/my-mcp-server

Run in CI (no color, machine output):

mcp-sanity-check --path . --no-color --json | tee scan-report.json

Check only what you are about to commit:

mcp-sanity-check --staged

Tests

npm test
# or
node test/run.mjs

The suite creates dirty fixtures in a temp directory (planted identifiers and secrets never live in tracked source), confirms the scanner catches them, confirms the values are masked in output, confirms the allow-list suppresses false positives, and confirms a clean directory exits zero.

Limitations

  • Scans text files only. Files larger than 5 MB and files with a NUL byte in the first 4 KB are skipped.
  • Binary file types (images, archives, compiled objects, fonts, audio, video, SQLite, lock files) are skipped by extension.
  • The high-entropy rule can still produce false positives on long deterministic strings (base64-encoded config blobs, encoded protobuf payloads). Use allow in .sanity-patterns.json to suppress these.
  • Generic PII patterns (email, RFC1918 IP, home path, MAC) are designed to catch leaks in public CI where the private identifier list is unavailable; they may fire on legitimate example values that are not in the placeholder list. Add them to allow as needed.
  • --staged and --range modes scan only added lines in the diff, not the full file state. A pre-existing leak in unchanged lines is not caught until a full --path scan is run.
  • Entropy check thresholds (H >= 3.5, distinct >= 12) were tuned empirically; an unusually low-entropy real secret may not be caught by the high-entropy rule (but would still be caught if it matches a named pattern).

License

MIT

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选