Skip to main content

MCP server for read-only exploration of ZFS snapshots on remote hosts over SSH (AI-assisted)

Project description

zsnoop-mcp

PyPI Python License: MIT CI

Ask your AI assistant things like:

  • โช "Recover my .zshrc from before I committed the rewrite three weeks ago."
  • ๐Ÿงน "Which snapshots older than 6 months are wasting the most space?"
  • ๐Ÿ”Ž "When did the directory /srv/backups first appear on this host?"
  • โŒ› "Find everything deleted under /home/youruser in the last week, and show me when each thing was last present."
  • ๐Ÿฅ "Are any of my pools throwing disk errors? When was the last scrub?"

An MCP server for read-only exploration of ZFS snapshots on remote hosts.

Browse, diff, search, and read files from any snapshot on any of your ZFS hosts through your AI assistant, over a single persistent SSH connection per host. No mutation operations are ever exposed.

Quickstart

# 1. Install
uv tool install zsnoop-mcp        # or: pipx install zsnoop-mcp

# 2. Configure one host (more in docs/INSTALL.md)
mkdir -p ~/.config/zsnoop-mcp
cat > ~/.config/zsnoop-mcp/hosts.toml <<'EOF'
[hosts.myhost]
ssh_target = "myhost.example.com"
agent_mode = "bootstrap"
sudo       = false
EOF

# 3. Register the MCP server with Claude Code
claude mcp add zsnoop --scope user -- zsnoop-mcp

# 4. Restart Claude Code, then ask your assistant any of the prompts above.

The agent is streamed over SSH on first connect โ€” nothing needs to be installed on the remote host beyond python3 (3.11+) and the zfs CLI. Read-only is enforced by an explicit allowlist on the agent side; the LLM can't bypass it.

About this codebase

This project was developed collaboratively with Claude Code (Anthropic). The human author (Mark Hellewell) defined the architecture, security model, and acceptance criteria, and reviewed every change before it landed; Claude handled the bulk of the drafting, test scaffolding, refactors, and documentation. Read-only-by-construction was a hard requirement from day one, enforced by an explicit method allowlist and the test suite โ€” see SECURITY.md. If you're reviewing or auditing the code, treat that as context, not as a reason to skip the usual scrutiny.

How it works

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   MCP (stdio)    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   MCP client    โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ โ”‚  zsnoop-mcp server โ”‚
โ”‚ (Claude Code,โ€ฆ) โ”‚ โ—„โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”‚     (local)        โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                                โ”‚
                       JSON-RPC over SSH stdio  โ”‚  one persistent
                       (one channel per host)   โ”‚  subprocess
                                                โ–ผ
                                      โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                                      โ”‚  zfs-snoop-agent    โ”‚
                                      โ”‚  (remote, Python)   โ”‚
                                      โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                                โ”‚
                                       zfs list / zfs diff,
                                       walk .zfs/snapshot/โ€ฆ
                                                โ–ผ
                                            ZFS pool

The remote agent is a single-file, stdlib-only Python script. It can be pre-installed at ~/bin/zfs-snoop-agent on each host, or streamed over SSH stdin on each connection โ€” no permanent install required.

Tools exposed to the LLM

Designed around three dominant workflows: file recovery ("get me /etc/foo as it was yesterday"), config drift audit ("when did X change?"), and forensics ("what was on the box when Y broke?").

Tool What it does
list_hosts Configured hosts
agent_info Agent version, methods, limits
list_pools ZFS pools visible to the agent (live discovery)
pool_status Parsed zpool status: vdev tree, scrub, errors
list_datasets Filesystems and volumes
dataset_properties zfs get (all or filtered) with values + sources
list_snapshots Snapshots (optionally scoped to a dataset, recursive)
snapshot_cadence Snapshot inventory summary: counts by class, biggest gap
diff_snapshots Path-level diff between two snapshots
list_dir Bounded directory listing within a snapshot
size_breakdown Recursive bytes for a snapshot dir + per-child sizes
top_consumers Top-N largest files/dirs under a snapshot subtree
read_file Bounded read; UTF-8 or base64 for binary
find_files fnmatch name search inside a snapshot
content_grep Regex content search inside a snapshot
file_history Every snapshot's version of a given file in a dataset
versions_of file_history deduped by content hash (distinct versions only)
file_diff Unified diff of one file across two snapshots
snapshots_containing Snapshots in which a path currently exists (time-ranged)
first_appearance Earliest snapshot containing a path
last_appearance Latest snapshot containing a path (answers "when did X disappear?")
find_deleted Paths deleted between two snapshots in a time window
bisect_change Binary-search snapshots for the one where a predicate flips
stale_snapshots Snapshots older than a time phrase, sorted by unique bytes
size_delta Bytes written between two snapshots of one dataset

Time-range parameters accept ISO 8601 or human phrases โ€” yesterday, last week, 3 days ago, 2 hours ago, etc. Parsing happens locally; the agent only sees absolute ISO 8601 timestamps.

Install

From a clone (dev / current path)

git clone https://github.com/hamsolodev/zsnoop-mcp.git
cd zsnoop-mcp
uv sync

From PyPI

uv tool install zsnoop-mcp    # or: pip install zsnoop-mcp

See docs/PUBLISHING.md for the per-release flow (version bump โ†’ tag โ†’ CI publishes via OIDC).

Configure

Create ~/.config/zsnoop-mcp/hosts.toml:

[hosts.r2d2]
ssh_target = "r2d2.example.com"
agent_mode = "bootstrap"          # or "preinstalled"
sudo       = false                # set true to read root-owned snapshot files
pools      = ["rpool", "bpool"]   # used by the LLM for scoping hints

[hosts.c3po]
ssh_target = "c3po.example.com"
agent_mode = "bootstrap"
sudo       = false
pools      = ["rpool"]

[hosts.this-box]
transport  = "local"              # run the agent on this machine, no SSH
agent_mode = "bootstrap"

Per-host setup on the remote (one-time):

# user mode: grant diff for each pool you want to compare snapshots in
sudo zfs allow -u $USER diff rpool

See docs/INSTALL.md for the full setup, including sudo mode for reading root-owned snapshot files.

Wire into Claude Code

Add to ~/.claude/settings.json:

{
  "mcpServers": {
    "zsnoop": {
      "command": "uv",
      "args": ["run", "--directory", "/home/youruser/Documents/worktrees/zsnoop-mcp", "zsnoop-mcp"]
    }
  }
}

Or, after PyPI install with uv tool install zsnoop-mcp:

{
  "mcpServers": {
    "zsnoop": {
      "command": "zsnoop-mcp"
    }
  }
}

Restart your Claude Code session; the tools appear under the zsnoop namespace.

Use

See docs/USAGE.md for example prompts that exercise the file-recovery, drift-audit, and forensics workflows.

Documentation

  • New here? Start with the onboarding tutorial โ€” a 10-chapter, what/why/how walk through the codebase, ending with a worked example of adding a new tool end-to-end. Renders nicely as HTML via uv run mkdocs serve (see --group docs).
  • Installation โ€” local setup, ZFS delegation, sudo mode
  • Usage examples โ€” concrete prompts the tools handle
  • Security model โ€” threat model, guarantees, sudo tradeoff
  • Publishing โ€” releasing to PyPI

Development

uv sync                            # install runtime + dev deps into .venv
uv run pytest                      # tests
uv run ruff check                  # lint
uv run ruff format                 # format
uv run mypy                        # type-check
uv run pip-audit --skip-editable   # CVE scan of locked deps
uv run pre-commit install          # set up hooks

Pre-commit runs pip-audit automatically whenever pyproject.toml or uv.lock change.

License

MIT โ€” see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

zsnoop_mcp-0.1.1.tar.gz (213.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

zsnoop_mcp-0.1.1-py3-none-any.whl (41.4 kB view details)

Uploaded Python 3

File details

Details for the file zsnoop_mcp-0.1.1.tar.gz.

File metadata

  • Download URL: zsnoop_mcp-0.1.1.tar.gz
  • Upload date:
  • Size: 213.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for zsnoop_mcp-0.1.1.tar.gz
Algorithm Hash digest
SHA256 cbfe4772b7a02bc6634af51c69e996715e748bcdb5b364a7f88e9028ce82f3d7
MD5 fb4a80ba644482f4351b273587010c60
BLAKE2b-256 540ed4b964e86eb88fd78ba32285ff8c92cbc57f89905628d7f220db3a382fde

See more details on using hashes here.

Provenance

The following attestation bundles were made for zsnoop_mcp-0.1.1.tar.gz:

Publisher: release.yml on hamsolodev/zsnoop-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file zsnoop_mcp-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: zsnoop_mcp-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 41.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for zsnoop_mcp-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 c94b6132843899516f06710e86b5843a5362af1df2225903cd3e9d5d2b990e87
MD5 0e78bbf1add6c0528a5689784841c067
BLAKE2b-256 cd3d8a0d09b54891a542829ba6bd9fc54965bdce53c0f5b7738b437f1bdb6833

See more details on using hashes here.

Provenance

The following attestation bundles were made for zsnoop_mcp-0.1.1-py3-none-any.whl:

Publisher: release.yml on hamsolodev/zsnoop-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page