Sift MCP (Docker edition)
by Sidera-Labs
README.md
# Sift MCP ā Docker edition š³
An [MCP](https://modelcontextprotocol.io) server that exposes the **SANS SIFT**
digital-forensics toolkit as tools an LLM can call. Drive it from **Claude
Desktop**, **Ollama Desktop**, or any MCP client.
This edition runs the whole toolchain **as a self-contained Docker container** ā
no SIFT VM required, works anywhere Docker runs. If you'd rather run on an
existing SANS SIFT install, see the VM edition (separate repo): **sift-mcp-vm**.
It wraps standard DFIR command-line programs (The Sleuth Kit, Volatility 3,
Plaso, exiftool, YARA, etc.) behind a safe, allowlisted interface. This is a
defensive / investigative tool ā it does not generate exploits or malware.
## Contents
```
sift-mcp-docker/
āāā server.py # the MCP server
āāā requirements.txt # Python dependencies
āāā Dockerfile # Ubuntu 24.04 + forensic toolchain + server
āāā docker-compose.yml # service, mounts, ports, healthcheck
āāā healthcheck.py # container liveness probe
āāā .env.example # host bind address, port, timeouts
āāā .dockerignore
āāā clients/ # example client configs (Claude Desktop, Ollama)
āāā README.md
```
The image is Ubuntu 24.04 with The Sleuth Kit, foremost, exiftool, binwalk, yara,
and Plaso (from the GIFT PPA), plus Volatility 3 and python-evtx (via pip). It
runs as a non-root user and serves MCP over HTTP on port 8000.
## Quick start
```bash
git clone <your-repo-url> sift-mcp-docker
cd sift-mcp-docker
cp .env.example .env # optional: tweak ports/limits
mkdir -p cases/output # evidence goes in ./cases
docker compose up -d --build # build + start
docker compose logs -f # watch startup
```
The endpoint is now `http://localhost:8000/mcp`. Put evidence in `./cases`
(e.g. `./cases/case01/disk.E01`); recovered/carved files and timelines appear in
`./cases/output`.
## How the mounts work
- `./cases` ā mounted **read-only** at `/cases`; the container can never alter
your original evidence.
- `./cases/output` ā mounted writable at `/cases/output` for results.
If the container can't write to `cases/output` (a bind-mount permission
mismatch), either `chmod 777 cases/output` on the host, or add
`user: "${UID}:${GID}"` to the service in `docker-compose.yml` and run
`UID=$(id -u) GID=$(id -g) docker compose up -d`.
## Without compose
```bash
docker build -t sift-mcp:latest .
docker run -d --name sift-mcp -p 127.0.0.1:8000:8000 \
-v "$PWD/cases:/cases:ro" -v "$PWD/cases/output:/cases/output" \
sift-mcp:latest
```
## Common commands
```bash
docker compose ps # status + health
docker compose logs -f # logs
docker compose restart # restart after editing .env
docker compose down # stop and remove
docker compose up -d --build # rebuild after changing server.py
```
## The tools
**Disk / file analysis** ā `sift_disk_partitions` (mmls), `sift_image_info`
(img_stat), `sift_filesystem_info` (fsstat), `sift_list_files` (fls),
`sift_extract_file` (icat, returns SHA-256), `sift_carve_files` (foremost),
`sift_file_type` (file), `sift_hash_file` (md5/sha1/sha256).
**Memory forensics** ā `sift_volatility` (any Volatility 3 plugin).
**Timeline & artifacts** ā `sift_create_timeline` (log2timeline),
`sift_export_timeline` (psort), `sift_parse_evtx`.
**Metadata & strings** ā `sift_exiftool`, `sift_strings`, `sift_binwalk`,
`sift_hexdump`, `sift_yara_scan`.
**Housekeeping** ā `sift_list_evidence`, `sift_server_info` (shows which
binaries are installed). Call `sift_server_info` after startup to confirm the
toolchain inside the container.
## Connecting clients
Both configs are in `clients/`. Use `http://localhost:8000/mcp` as the URL.
### Claude Desktop
Claude Desktop speaks MCP over stdio, so bridge to the HTTP endpoint with
`mcp-remote` (needs Node.js on the host). Edit
`%APPDATA%\Claude\claude_desktop_config.json` (Windows) or
`~/Library/Application Support/Claude/claude_desktop_config.json` (macOS):
```json
{
"mcpServers": {
"sift": {
"command": "npx",
"args": ["-y", "mcp-remote", "http://localhost:8000/mcp", "--transport", "http-only"]
}
}
}
```
### Ollama Desktop
Use [`mcphost`](https://github.com/mark3labs/mcphost) to bridge an Ollama model
to MCP:
```bash
go install github.com/mark3labs/mcphost@latest
mcphost -m ollama:qwen2.5 --config clients/ollama_mcphost_config.example.json
```
Use a tool-calling model (e.g. `qwen2.5`, `llama3.1`).
### Quick check
```bash
curl -i http://localhost:8000/mcp
```
A `406 Not Acceptable` is expected and good ā it means the server is up (it only
accepts proper MCP POSTs, not bare GETs).
## Configuration (environment variables)
Set host-side values in `.env`; container-internal paths are fixed by compose.
| Variable | Default | Purpose |
|---|---|---|
| `HOST_BIND` | `127.0.0.1` | Host address to publish on (`0.0.0.0` for LAN access) |
| `HOST_PORT` | `8000` | Host port mapped to the container |
| `SIFT_TIMEOUT` | `600` | Default per-command timeout (s) |
| `SIFT_MAX_OUTPUT_CHARS` | `60000` | Output truncation limit |
## Security model
- Each tool runs one fixed, allowlisted binary via `exec` ā never a shell.
- File paths are resolved (symlinks included) and confined to `/cases` (read)
and `/cases/output` (write); anything outside is rejected.
- Plugin names, carve types, inode addresses, and parser names are
shape-validated. Every command runs under a timeout with truncated output.
- The server has **no authentication** ā by default it publishes only on
`127.0.0.1`. If you set `HOST_BIND=0.0.0.0`, keep it on a trusted/private
network, never the public internet.
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues