canopii
v0.2.0
Published
MCP server security scanner — the open-source engine behind the Canopii Trust Index
Maintainers
Readme
MCP server security scanner — the open-source engine behind the Canopii Trust Index.
Scan any Model Context Protocol server — a GitHub repo, an npm/PyPI package, or your local checkout — and get a deterministic, evidence-based security score with concrete fixes.
npx canopii scan --github https://github.com/modelcontextprotocol/serverscanopii scan --local .
canopii scan --npm @modelcontextprotocol/server-filesystem
canopii scan --pypi mcp-server-fetchWhy?
Most scanners hand you a list of findings. canopii computes the Canopii Risk Score — the same scoring engine that powers the Canopii Trust Index, where thousands of public MCP servers are continuously scored. That means:
- Deterministic — same input, same score. No LLM in the scoring loop (AI review exists, but it's opt-in and advisory-only — it never changes the score).
- Evidence-earned — a high score certifies verified good practices, not the absence of findings. What we couldn't check lowers confidence, and confidence caps the score: absence of evidence is not evidence of safety.
- Guarded — the worst confirmed issue dominates. A committed secret or a command-injection sink caps the score no matter how clean everything else is; good practices can't buy it back.
- Comparable — your score means the same thing as every score on the Trust Index.
What it checks
~29 controls across 6 domains (full rubric in docs/scoring.md):
| Domain | Examples |
|---|---|
| Code safety | command injection, eval, path traversal, SSRF, unsafe deserialization (semgrep, offline ruleset) |
| Secrets | committed credentials (gitleaks), env-based credential hygiene |
| Supply chain | known CVEs (OSV.dev), lockfile pinning, install scripts, typosquatting, provenance |
| Tool integrity | prompt-injection markers in tool descriptions, strict schemas, destructive tool scope, rug-pull drift |
| Auth & transport | TLS on remotes, declared auth, sandboxing, bind-all exposure |
| Maintenance | activity, archival, license, security policy, signed releases |
The score: earned points over evaluated controls, hard-capped by the worst failed guard (critical → 20, high → 49, medium → 74, low → 89) and by verification coverage (<40% coverage → max 40). Grades: A ≥ 90 · B ≥ 75 · C ≥ 60 · D ≥ 40 · F.
Install
Recommended — installs the CLI plus the scanners that give you full coverage:
curl -fsSL https://raw.githubusercontent.com/canopii-dev/canopii-cli/main/install.sh | bashThe script is short and auditable: it installs canopii from npm, puts a checksum-verified gitleaks binary in ~/.canopii/bin (no sudo, no PATH edits — the CLI looks there itself), installs semgrep via brew/uv/pipx if you have one, and finishes with canopii doctor so you see exactly what your scans will cover. Requires Node.js ≥ 22. Uninstall: npm rm -g canopii && rm -rf ~/.canopii.
npm-only also works — scans then run with reduced coverage (code-safety and secret controls report not_checked, which lowers confidence and caps the score):
npm install -g canopii # or one-off: npx canopii scan ...On Windows: npm install -g canopii plus winget install semgrep gitleaks. Check any setup with:
canopii doctorUsage
canopii scan --github <url> # GitHub repository (public)
canopii scan --local <path> # local directory (also: canopii scan <path>)
canopii scan --npm <pkg[@version]> # npm package
canopii scan --pypi <pkg[@version]> # PyPI package
canopii scan --remote <url> # live MCP endpoint — alone, or combined with any of the above
--api-key <key> bearer token for --remote (default: $CANOPII_REMOTE_API_KEY)
--header <n:v> extra header for --remote (repeatable)
--transport <type> remote transport: streamable-http (default) | sse
--dynamic also live-probe remotes declared by the scanned package/repo
--token <gh-token> GitHub token (default: $GITHUB_TOKEN) — raises rate limits
--judge AI advisory review of tool descriptions ($ANTHROPIC_API_KEY);
advisory-only, never affects the score
--json full machine-readable result
--min-score <n> exit 1 below this score (CI gate)
--min-grade <A-F> exit 1 below this grade (CI gate)Fullest coverage = static + live in one scan:
canopii scan --github https://github.com/you/your-mcp --remote https://api.you.com/mcp --api-key $KEYLive probes are read-only — initialize plus tools/resources/prompts enumeration; no tool is ever invoked, and the requests carry identifying Canopii-Scanner headers so operators can recognize (or block) them. When you pass credentials, the scanner also re-probes anonymously to verify your auth is actually enforced — if the anonymous probe can enumerate your tools, the report says so.
Exit codes: 0 ok · 1 below threshold · 2 scan error / target unverifiable.
CI example
- run: npx canopii scan --local . --min-grade BSARIF output, a GitHub Action, and rug-pull baselines for your release pipeline are on the roadmap.
What it does not do
- Execute the scanned code. Sources are fetched as tarballs / read from disk; static analysis only.
- Phone home. No telemetry, no accounts.
- Score with an LLM.
--judgeemits human-review advisories only.
Library use
The engine is importable:
import { runScan, scoreControls, CONTROL_CATALOG } from "canopii";License
Apache-2.0. Built by Canopii — if you want continuous scoring, version history, and policy enforcement for the MCP servers your org uses, that's the platform.
