mcp-security-toolkit
README.md
# mcp-security-toolkit
> Project **#6** of the DevSecOps portfolio: a **local, free** [MCP](https://modelcontextprotocol.io) server that exposes the portfolio's security scanners (Trivy, Gitleaks, Checkov, Semgrep) as tools an AI agent can call — turning "run a scan" into something an LLM does for you, with **zero API cost**.
This is project **#6**. It makes the rest of the portfolio *agent-accessible*: instead of a human typing `trivy fs`, an MCP-aware agent calls the `trivy_fs_scan` tool and reasons over the JSON it gets back.
| # | Project | Role |
|---|---------|------|
| 1 | secure-k8s-lab | Reproducible cluster + GitOps + isolated vulnerable target |
| 2 | devsecops-pipeline | Scanning in CI (SAST/DAST/deps/IaC) |
| 3 | supply-chain-security | Image signing, SBOM, admission control |
| 4 | offensive-writeups | Documented attacks against the lab |
| 5 | runtime-security | Falco + Cilium detecting those attacks |
| **6** | **mcp-security-toolkit** *(this repo)* | **Security scanners exposed as MCP tools for AI agents** |
## The story this repo tells
> "My security tooling isn't just CLI I run by hand — it's an MCP server. Any agent (a local Ollama model, Cline, or Claude) can call `trivy_fs_scan`, `gitleaks_scan`, `checkov_scan` and `semgrep_scan` and reason over the findings. And it's all free and reproducible: a local Python server, open-source scanners, no paid API required."
## Architecture
```mermaid
flowchart LR
subgraph clients["MCP clients"]
I["MCP Inspector<br/>(no AI, free)"]
O["Ollama model<br/>via Cline / ollmcp"]
C["Claude<br/>(1 free connector)"]
end
subgraph server["mcp-security-toolkit (stdio)"]
T1[trivy_fs_scan]
T2[gitleaks_scan]
T3[checkov_scan]
T4[semgrep_scan]
end
subgraph scanners["open-source scanners"]
TR[(Trivy)]
GL[(Gitleaks)]
CK[(Checkov)]
SG[(Semgrep)]
end
I --> server
O --> server
C -->|"MCP / JSON-RPC over stdio"| server
T1 --> TR
T2 --> GL
T3 --> CK
T4 --> SG
TR -->|JSON report| server
GL -->|JSON report| server
CK -->|compact JSON| server
SG -->|compact JSON| server
```
## Tools
| Tool | Wraps | Returns |
|------|-------|---------|
| `trivy_fs_scan` | `trivy fs --format json` | Dependency/OS CVEs (+ secrets) in a local path |
| `gitleaks_scan` | `gitleaks dir --report-format json` | Hard-coded secrets / credentials in a local path |
| `checkov_scan` | `checkov -d --output json --compact` | IaC misconfigurations (Terraform / K8s / Dockerfile / Helm) |
| `semgrep_scan` | `semgrep scan --json` | SAST findings in source code |
All four wrap **open-source** scanners and return **structured JSON**, so the agent gets machine-readable findings instead of scraping CLI text. The server speaks MCP over **stdio**, so it runs anywhere a client can spawn a subprocess — no ports, no daemon, no cloud.
**Keeping the JSON small.** Checkov and Semgrep can emit *huge* reports. To stay
within an LLM's context window, `checkov_scan` and `semgrep_scan` return a
**compact, filtered summary** rather than raw output: only failures, trimmed to a
few fields, filtered by severity, and capped at `max_findings` (default 50). The
full counts are always reported, and a `truncated` flag tells you when findings
were omitted. `trivy_fs_scan` likewise defaults to `HIGH,CRITICAL` +
`--ignore-unfixed` to cut noise at the source.
> Semgrep's default `config="auto"` fetches rules from the registry on first use
> (needs network once); pass a local rules path or a pinned pack like
> `p/security-audit` for fully offline runs.
## Scanning a GitHub repo (clone first)
The tools take a **local filesystem path, not a GitHub URL**. To scan a remote
repo it must first be cloned to disk; you then hand the tool the local path:
```bash
git clone https://github.com/owner/repo.git
# then ask the agent: "scan ./repo with trivy and gitleaks"
```
**The server itself never clones.** Whether a clone happens automatically depends
entirely on the *client* you connect it to:
| Client | Can it clone for you? |
|--------|----------------------|
| Agent **with a shell/terminal tool** (e.g. Claude Code, Cline with command execution) | ✅ Yes — it runs `git clone` with its *own* tool, then calls `trivy_fs_scan` on the result. Two steps, two different tools (one the agent's, one ours). |
| Agent connected to **only this server** (e.g. the MCP Inspector, or a model wired to this server alone) | ❌ No — clone manually first, then pass the local path. |
| **This server's tools** | ❌ Never — there is no clone tool here; the path must already exist on disk (a missing path returns a clear error). |
> **History caveat:** `gitleaks_scan` uses `gitleaks dir`, which scans the
> **working tree as it is now** — it does *not* walk git history, so a secret that
> was committed and later deleted won't be caught (that would need `gitleaks git`).
## Prerequisites
- [Python](https://www.python.org/) ≥ 3.10
- [uv](https://docs.astral.sh/uv/) — `curl -LsSf https://astral.sh/uv/install.sh | sh`
- [Node.js](https://nodejs.org/) (only for `npx`, used by the MCP Inspector)
- [Trivy](https://aquasecurity.github.io/trivy/) — `brew install trivy`
- [Gitleaks](https://github.com/gitleaks/gitleaks) — `brew install gitleaks`
- [Checkov](https://www.checkov.io/) — `brew install checkov` (or `pip install checkov`)
- [Semgrep](https://semgrep.dev/) — `brew install semgrep` (or `pip install semgrep`)
The scanners are looked up on `PATH` at call time; a clear error is returned if one is missing.
## Quick start — no AI, free (MCP Inspector)
The fastest way to see the tools work, with **no model and no API key**: the
[MCP Inspector](https://github.com/modelcontextprotocol/inspector) is a browser
UI that connects to the server and lets you call tools by hand.
```bash
make up # create the venv + install the server (uv sync)
make inspect # launch the Inspector against the server -> http://localhost:6274
```
In the Inspector: open **Tools → List Tools**, pick `trivy_fs_scan`, set
`path` to `.`, and **Run** — you'll get the raw Trivy JSON back.
```bash
make test # run the smoke tests
make down # remove the venv + caches
```
## As an agent (free) — a local LLM with Ollama
Drive the tools with a **fully local, free** model via [Ollama](https://ollama.com/).
Use a model that supports tool calling:
```bash
ollama pull qwen2.5:7b # tool-calling capable, runs on a laptop
```
**Option A — [ollmcp](https://github.com/jonigl/mcp-client-for-ollama)** (a terminal MCP client for Ollama):
```bash
pipx install ollmcp
ollmcp --model qwen2.5:7b --mcp-server "uv run mcp-security-toolkit"
```
**Option B — [Cline](https://github.com/cline/cline)** (VS Code extension): set the
API provider to **Ollama**, then add this server to `cline_mcp_settings.json`:
```json
{
"mcpServers": {
"security-toolkit": {
"command": "uv",
"args": ["run", "mcp-security-toolkit"],
"cwd": "/absolute/path/to/mcp-security-toolkit"
}
}
}
```
Then just ask: *"Scan `./` with trivy and summarise the critical findings."*
## With Claude (free tier = 1 connector)
Claude's free tier allows a **single custom connector**, which is plenty for this
local (stdio) server.
**Claude Code:**
```bash
claude mcp add security-toolkit -- uv run mcp-security-toolkit
```
**Claude Desktop** — add to `claude_desktop_config.json`:
```json
{
"mcpServers": {
"security-toolkit": {
"command": "uv",
"args": ["run", "mcp-security-toolkit"],
"cwd": "/absolute/path/to/mcp-security-toolkit"
}
}
}
```
Then ask: *"Use `trivy_fs_scan` on this repo and tell me what to fix first."*
## Repository layout
```
mcp-security-toolkit/
├── pyproject.toml # uv project: deps (mcp[cli]) + console script
├── .python-version # pinned interpreter for uv
├── src/
│ └── mcp_security_toolkit/
│ ├── __init__.py
│ └── server.py # FastMCP server: trivy / gitleaks / checkov / semgrep
├── tests/
│ └── test_server.py # smoke tests (no scanners required)
├── Makefile # up / inspect / test / down / help
├── .pre-commit-config.yaml # local gates (ruff, gitleaks, hygiene)
├── .markdownlint.yaml
├── .vscode/ # recommended extensions + format-on-save
├── .github/
│ └── workflows/
│ └── mirror-to-gitlab.yml # GitHub -> GitLab mirror (+ workflow_dispatch)
└── docs/
└── architecture.md # why MCP, server design, the three clients
```
## ⚠️ Note
The tools run real scanners against **whatever path you give them** and shell out
to local binaries. Only point them at code/paths **you own or are authorised to
scan**, and only connect the server to clients you trust — an agent that can call
these tools can read any file under the paths it scans.
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues