Skip to content

Latest commit

 

History

History
421 lines (294 loc) · 15 KB

File metadata and controls

421 lines (294 loc) · 15 KB

Getting Started

DocumentationGet Started

This guide walks you through installing MCTS, running your first scan, and understanding the results. No prior MCP security experience required.

Time needed: ~15 minutes.

Where to go next Link
Pick a scan mode (live, remote, snapshot…) Which scan mode should I use?
Set up CI CI integration
Every flag and command CLI reference
Full doc index Documentation map

Unfamiliar with a term? See the Glossary.


What you'll do

By the end of this guide you will:

  1. Install MCTS on your machine
  2. Scan the included vulnerable example server
  3. Read the terminal security report
  4. Export JSON and generate an HTML dashboard
  5. Know where to go next for CI, live scanning, and advanced features

What is MCTS?

MCTS (Model Context Threat Scanner) analyzes MCP servers for security issues. An MCP server is a program that exposes tools — callable actions an AI assistant can use (read files, query databases, send messages, etc.).

MCTS reads your server code (or connects to a running server), runs automated security checks, and produces:

  • A list of findings ranked by severity (Critical → Low)
  • Two scores by default — legacy score.overall (0–100, higher = better) and v2 score_v2.absolute_risk (integer, higher = worse)
  • Exportable reports in JSON, SARIF, and HTML formats

Scores confusing? Read the Scoring developer guide (5 min) before diving into formulas.

For the full pipeline design, see Architecture.


Prerequisites

Requirement Version Notes
Python 3.11+ Required
uv Latest recommended Fast dependency manager used by this repo
Git Any recent To clone from MCP-Audit/MCTS

Optional extras

Install these only when you need the corresponding feature:

Feature Install command What it enables
Live probing + fuzzing uv sync --extra mcp Connect to running MCP servers
REST API uv sync --extra api mcts serve (FastAPI)
YARA rules uv sync --extra yara --yara metadata pattern matching
LLM-as-judge / triage uv sync --extra llm --llm-judge, --llm-triage (opt-in semantic review)
Semgrep SAST uv sync --extra semgrep --semgrep (also requires semgrep CLI on PATH)
Dependency CVE scan uv sync --extra supplychain --pip-audit
Deep TypeScript SAST uv sync --extra sast Tree-sitter taint analysis
MCP server mode uv sync --extra mcp mcts-mcp for IDE agent integration

For your first scan, the base install is enough.

If mcts doctor . reports Extra [mcp] as missing, install that optional extra before using mcts-mcp, mcts scan --live, or mcts fuzz.


Install

Recommended (isolated)

PyPI distribution: mcp-mcts (import package and CLI: mcts). The shorter name mcts is already used by another project on PyPI.

# Scan without installing
uvx mcp-mcts scan examples/vulnerable-mcp-server/server.py

# One-off live scan with MCP extra (no global install)
uvx --from 'mcp-mcts[mcp]' mcts scan ./server.py --live --i-understand-live-risk

# Or install in an isolated tool environment
pipx install 'mcp-mcts[mcp]'
uv tool install mcp-mcts
mcts --version
Install Use case
uvx mcp-mcts One-off static scan
pipx install mcp-mcts Global isolated CLI
pip install mcp-mcts[mcp] Live probing in a dedicated venv
pip install mcp-mcts[all] All extras except LLM (no litellm)
pip install 'mcp-mcts[all,llm]' Full analyzer set including --llm-judge

From PyPI (dedicated environment)

Use a separate virtualenv — not your application's dev .venv:

pip install mcp-mcts
mcts scan --help

Add extras when you need them (avoid [all] in app venvs):

pip install "mcp-mcts[mcp]"          # live probing + fuzzing
pip install "mcp-mcts[api]"          # REST API (`mcts serve`)
pip install "mcp-mcts[supplychain]"  # `--pip-audit` / `--npm-audit`
pip install "mcp-mcts[llm]"          # `--llm-judge` / `--llm-triage`
pip install "mcp-mcts[semgrep]"      # `--semgrep` SAST adapter
pip install "mcp-mcts[mcp]"          # live probing + fuzzing + `mcts-mcp`

From source (contributors)

git clone https://github.com/MCP-Audit/MCTS.git
cd MCTS
uv sync --all-extras

Verify the CLI works:

uv run mcts --version
uv run mcts scan --help

Minimal install (static scan only)

If you only want to scan source code without live probing:

# PyPI
pip install mcp-mcts

# Source
uv sync
uv run mcts scan examples/vulnerable-mcp-server/server.py

Example servers

The repo includes demo servers you can scan immediately:

Path What it demonstrates Expected score
examples/vulnerable-mcp-server/server.py Destructive tools, injection, attack chains Legacy ~1/100; v2 absolute risk ~2260
examples/baseline-mcp-server/server.py Minimal, safe tool surface ~100/100
examples/medium-risk-mcp-server/server.py Moderate findings ~67/100
examples/live-mcp-server/server.py Live probe + fuzz tests Varies
examples/prompt-only-server/ Prompt-surface scanning Multi-surface demo

Start with the vulnerable server to see a full report with real findings.


Scan your first server

Run this command:

uv run mcts scan examples/vulnerable-mcp-server/server.py

What happens under the hood

  1. Discovery — MCTS parses the Python file and finds all @tool handlers, their descriptions, input schemas, and handler source code
  2. Analysis — 25+ security analyzers check for permissions, injection, secrets, command execution, attack chains, and more
  3. Scoring — Two engines run by default: legacy score.overall + v2 score_v2 (guide)
  4. Report — Results appear in your terminal

Reading the output

==================== MCTS Security Report ====================
Overall Score:   1/100 (CRITICAL)
Risk Index:      100/100
Scoring basis:   5 Critical, 11 High, 1 Medium, 0 Low (17 scorable findings)
Absolute Risk:   2260 (critical)
Security Score:  9/100

● Critical    5
● High       11
● Medium      1
Field Meaning
Overall Score Legacy 0–100 (higher = better). Existing CI --min-score uses this.
Absolute Risk v2 integer (higher = worse). Primary posture metric for new policies.
Security Score v2 benchmark vs corpus (higher = better). Not the same as Overall Score.
Severity counts Findings by level (compliance rows appear in reports but are excluded from score math)

Two scores? That is expected — legacy 1/100 and v2 2260 measure different things. See the Scoring developer guide for which metric to use in CI.

Scan a whole repository

uv run mcts scan examples/bench/multi-file-server/

Directory scans walk the tree, discover Python and TypeScript MCP servers, merge tools by name, and skip test directories and dependencies automatically.

Scan prompts and instructions in a repo

Agent projects often store prompts in markdown (system_prompt.md, skills/*/SKILL.md) rather than MCP prompts/list. MCTS discovers these files by default on static scans:

# Prompt/instruction surfaces only (skips supply-chain noise on pyproject.toml)
uv run mcts scan . --surfaces prompt,instruction

# Skills tree only
uv run mcts scan ./skills --surfaces prompt,instruction

# Explicit files or globs
uv run mcts scan . --instruction-file src/agent/system_prompt.md
uv run mcts inventory --skills --skills-dir ./skills

Disable repo markdown discovery with --no-discover-instructions when you only want MCP tool metadata from source code. See Security checks — metadata poisoning.

Terminal themes

uv run mcts scan examples/vulnerable-mcp-server/server.py --theme cyber    # default
uv run mcts scan examples/vulnerable-mcp-server/server.py --theme minimal
uv run mcts scan examples/vulnerable-mcp-server/server.py --no-progress    # CI-friendly

Save JSON and SARIF

By default, every scan writes artifacts to mcts_analysis/ in your project folder:

File Purpose
scan-report.json Full machine-readable report
scan-report.html Executive HTML dashboard (open directly)
scan-report.sarif GitHub Code Scanning upload
history.json Score trend across runs (scoring_version, absolute_risk when v2)

Relative -o paths use the basename only under mcts_analysis/ — e.g. -o report.jsonmcts_analysis/report.json, not ./report.json.

JSON (full report)

uv run mcts scan examples/vulnerable-mcp-server/server.py -o report.json
# → writes mcts_analysis/report.json (+ HTML + SARIF)

The JSON contains everything: server metadata, all findings, score breakdown, and attack chain graph. Use this for CI automation or mcts report (paths auto-resolve under mcts_analysis/).

SARIF (GitHub Code Scanning)

uv run mcts scan examples/vulnerable-mcp-server/server.py \
  -o report.sarif --format sarif
# → writes mcts_analysis/report.sarif

Upload to GitHub with github/codeql-action/upload-sarif. See CI Integration.


HTML security dashboard

Every scan already writes mcts_analysis/scan-report.html. Open it directly after scanning — no extra step required.

To regenerate HTML from an existing JSON file:

uv run mcts scan examples/vulnerable-mcp-server/server.py -o report.json
open mcts_analysis/scan-report.html   # macOS — written automatically on scan
# optional:
uv run mcts report report.json        # resolves to mcts_analysis/report.json

The dashboard is a single self-contained HTML file with:

  • Score gauge, letter grade, and partitioned area scores
  • Severity breakdown and category radar chart
  • Searchable findings table (location, CWE, technique links, expandable evidence)
  • Full MCTS-T technique grid (79 techniques) with Detected / Clear filters
  • Tool capability matrix and attack chain visualization
  • OWASP LLM + MCP Top 10 mapping with coverage gap cards
  • Scan history trend chart
  • In-browser export (JSON, HTML, PDF)

Full layout reference: HTML Security Dashboard.


Optional: live probing

By default, MCTS reads source code only. Live mode starts your server as a subprocess and asks it what tools it actually exposes at runtime.

uv sync --extra mcp

uv run mcts scan examples/live-mcp-server/server.py \
  --live --i-understand-live-risk

Live mode requires explicit consent because it starts a real server process. Add --i-understand-live-risk or set MCTS_LIVE_OK=1 in CI.

Deep dive: Live Scanning.


Optional: remote HTTP scanning

Scan a hosted MCP server without local source code:

uv run mcts scan . \
  --url https://mcp.example.com/mcp \
  --bearer-token "$TOKEN" \
  --i-understand-live-risk

See Remote Scanning.


Other scan modes

Most users start with a static scan (mcts scan ./server.py). When you need something else:

If you… Read
Have source code on disk (default) You're in the right place — keep reading below
Need to probe a running server Live scanning
Have a hosted URL, no source Remote scanning
Have exported JSON, no network Static snapshot
Aren't sure which applies Which scan mode should I use?

Also useful: mcts inventory --scan (audit local configs) · mcts scan --machine-wide (all configs) · mcts doctor . (preflight) · full task list


CI gate

Fail your build when security thresholds aren't met.

Existing pipelines (legacy — no change required):

uv run mcts scan ./server.py \
  --fail-on-critical \
  --min-score 70 \
  -o report.json

New policies (v2 gates — scoring is both by default):

uv run mcts scan ./server.py \
  --fail-on-critical \
  --max-absolute-risk 500 \
  --max-risk-level high \
  -o report.json

Gate cheat sheet: Scoring developer guide · GitHub Action: CI Integration · action/README.md


Optional: one-command auto scan

When you are unsure which entrypoint or MCP config to use:

mcts scan . --auto
mcts scan . --auto --auto-server my-server -o report.json --html report.html

--auto picks a single entrypoint, a lone config server, or falls back to repo scan. It never enables live probing.


Troubleshooting

Symptom Likely cause Fix
externally-managed-environment / PEP 668 pip install into system Python Use uvx mcp-mcts, pipx install mcp-mcts, or a dedicated venv
mcts: command not found Tool not on PATH pipx ensurepath, uv tool update-shell, or use uvx mcp-mcts
Dependency conflicts after install MCTS installed in app .venv Use isolated install; avoid pip install mcp-mcts[all] in app venv
Exit code 2, "Live probing requires consent" Missing consent flag Add --i-understand-live-risk or MCTS_LIVE_OK=1
Exit code 2, "Unknown format" Invalid --format Use json or sarif
No tools discovered Wrong target or empty repo Point at server entrypoint; check --languages
Score seems wrong / two different numbers Dual engines on default scans Expected — see Scoring guide; check score.basis and score_v2.basis
mcp import error Missing extra uv sync --extra mcp or uvx --from 'mcp-mcts[mcp]' mcts …
Remote scan fails Missing consent or auth --i-understand-live-risk + --bearer-token
TS tools missing Language filter Use --languages typescript

Next steps

I want to… Guide
Understand scores & CI gates Scoring developer guide
Pick live vs remote vs snapshot Which scan mode?
See every CLI flag CLI reference
Understand a finding Security checks
Set up CI/CD CI integration
Full doc map Documentation index