Zsnoop
Un servidor MCP para exploración de solo lectura de instantáneas ZFS en hosts remotos.
Documentación
zsnoop-mcp
Pregúntale a tu asistente de IA cosas como:
- ⏪ "Recupera mi
.zshrcde antes de que hiciera el commit de la reescritura hace tres semanas." - 🧹 "¿Qué instantáneas de más de 6 meses están desperdiciando más espacio?"
- 🔎 "¿Cuándo apareció por primera vez el directorio
/srv/backupsen este host?" - ⌛ "Encuentra todo lo eliminado bajo
/home/youruseren la última semana, y muéstrame cuándo estuvo presente cada cosa por última vez." - 🏥 "¿Alguno de mis pools está dando errores de disco? ¿Cuándo fue el último scrub?"
Un servidor MCP para exploración y recuperación de instantáneas ZFS en hosts remotos —
solo lectura por defecto, con herramientas restore_* opt-in (v0.4.0+) habilitadas por host.
Explora, compara, busca y lee archivos de cualquier instantánea en cualquiera de tus hosts
ZFS a través de tu asistente de IA, mediante una única conexión SSH persistente por
host. Solo lectura por defecto; las herramientas de escritura restore_file / restore_dir
(v0.4.0+) son opt-in por host y están limitadas por una lista de permitidos de rutas
definida por el operador — con la configuración estándar, nada en el remoto puede
escribirse.
Inicio rápido
# 1. Install
uv tool 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.
El agente se transmite por SSH en la primera conexión — no es necesario instalar
nada en el host remoto más allá de python3 (3.11+) y la CLI de zfs.
Solo lectura por defecto, aplicado mediante una lista de permitidos explícita en el lado
del agente. Las herramientas de escritura restore_file / restore_dir (v0.4.0+) son
opt-in por host y están limitadas por una lista de permitidos de rutas definida
por el operador; con la configuración predeterminada se niegan antes de hacer nada.
Acerca de este código
Este proyecto se desarrolló en colaboración con Claude
Code (Anthropic). El autor humano (Mark
Hellewell) definió la arquitectura, el modelo de seguridad y los criterios
de aceptación, y revisó cada cambio antes de que se integrara; Claude se encargó de
la mayor parte del borrador, el andamiaje de pruebas, las refactorizaciones y la documentación.
El modo solo-lectura por defecto fue un requisito estricto desde el primer día, aplicado mediante una
lista de permitidos de métodos explícita y la suite de pruebas. Las herramientas restore_* opt-in
añadidas en v0.4.0 son los únicos métodos de escritura y están controladas en el lado del servidor
mediante configuración por host (desactivadas por defecto; requieren una lista de permitidos de rutas
no vacía cuando se activan) — ver
SECURITY.md. Si estás revisando o auditando el
código, trátalo como contexto, no como una razón para saltarte el escrutinio habitual.
Cómo funciona
┌─────────────────┐ 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
El agente remoto es un script de Python de un solo archivo, solo con la biblioteca estándar. Puede
estar preinstalado en ~/bin/zfs-snoop-agent en cada host, o transmitirse por SSH
stdin en cada conexión — no se requiere instalación permanente.
Herramientas expuestas al LLM
Diseñado en torno a cuatro flujos de trabajo dominantes: recuperación de archivos ("dame /etc/foo tal como estaba ayer" — en tu estación de trabajo, o restaurado en su lugar en el servidor), auditoría de deriva de configuración ("¿cuándo cambió X?"), forensia ("¿qué había en la máquina cuando Y se rompió?"), y mantenimiento de almacenamiento ("¿qué instantáneas son las más grandes / más antiguas?"). Las herramientas se agrupan a continuación por su caso de uso dominante; muchas se combinan entre flujos de trabajo.
Descubrimiento e introspección
| Herramienta | Qué hace |
|---|---|
list_hosts | Hosts configurados |
agent_info | Versión del agente, métodos, límites |
list_pools | Pools ZFS visibles para el agente (descubrimiento en vivo) |
pool_status | zpool status analizado: árbol vdev, scrub, errores |
list_datasets | Sistemas de archivos y volúmenes |
dataset_properties | zfs get (todos o filtrados) con valores y fuentes |
Inventario de instantáneas y mantenimiento
| Herramienta | Qué hace |
|---|---|
list_snapshots | Instantáneas (filtros opcionales de dataset/tiempo/capacidad) |
snapshot_cadence | Resumen: recuentos por clase, brecha (por dataset), extensión |
stale_snapshots | Instantáneas más antiguas que una frase de tiempo, ordenadas por unicidad |
size_delta | Bytes escritos entre dos instantáneas de un dataset |
Exploración y dimensionamiento dentro de una instantánea
| Herramienta | Qué hace |
|---|---|
list_dir | Listado de directorio acotado dentro de una instantánea |
size_breakdown | Bytes recursivos para un directorio de instantánea + tamaños por hijo |
top_consumers | Top-N archivos/directorios más grandes bajo un subárbol de instantánea |
Lectura de contenido
| Herramienta | Qué hace |
|---|---|
read_file | Lectura acotada; UTF-8 o base64 para binarios |
find_files | Búsqueda de nombres fnmatch dentro de una instantánea |
content_grep | Búsqueda de contenido con regex dentro de una instantánea |
checksum_file | SHA-256 de archivo completo (límite de 256 MiB) para comprobaciones de integridad |
Comparación de instantáneas y seguimiento de cambios
| Herramienta | Qué hace |
|---|---|
diff_snapshots | Diff a nivel de ruta entre dos instantáneas |
file_diff | Diff unificado de un archivo entre dos instantáneas |
file_history | La versión de cada instantánea de un archivo dado en un dataset |
versions_of | file_history deduplicado por hash (solo versiones distintas) |
snapshots_containing | Instantáneas en las que una ruta existe actualmente (con rango de tiempo) |
first_appearance | Instantánea más temprana que contiene una ruta |
last_appearance | Instantánea más reciente que contiene una ruta; revela cuándo se eliminó |
find_deleted | Rutas eliminadas entre dos instantáneas en una ventana de tiempo |
bisect_change | Búsqueda binaria de la instantánea donde un predicado cambia |
Recuperación — copiar a tu estación de trabajo
| Herramienta | Qué hace |
|---|---|
fetch_file | Copiar un archivo de instantánea a una ruta local vía SFTP |
fetch_dir | Copiar un árbol de directorios de instantánea a una ruta local vía SFTP |
Recuperación — restaurar en el servidor (opt-in, v0.4.0+)
Estas son las únicas herramientas de escritura. Desactivadas por host por defecto;
requieren allow_restore = true y una lista de permitidos restore_paths no vacía
en hosts.toml. Ver SECURITY.md para el modelo de amenazas.
| Herramienta | Qué hace |
|---|---|
restore_file | Restaurar un archivo de instantánea a una ruta del servidor (opt-in) |
restore_dir | Restaurar un árbol de directorios de instantánea a una ruta del servidor |
Los parámetros de rango de tiempo aceptan ISO 8601 o frases en lenguaje natural — yesterday,
last week, 3 days ago, 2 hours ago, etc. El análisis se realiza localmente; el
agente solo ve marcas de tiempo ISO 8601 absolutas.
Instalación
Desde PyPI (recomendado)
uv tool install zsnoop-mcp
Ejecútalo con zsnoop-mcp.
Desde un clon (para modificar el código)
git clone https://github.com/hamsolodev/zsnoop-mcp.git
cd zsnoop-mcp
uv sync
Ejecútalo con uv run zsnoop-mcp desde el checkout.
Ver docs/PUBLISHING.md para el flujo por versión (bump de versión → tag → CI publica vía OIDC).
Configuración
Crea ~/.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"
Configuración por host en el remoto (una sola vez):
# user mode: grant diff for each pool you want to compare snapshots in
sudo zfs allow -u $USER diff rpool
Ver docs/INSTALL.md para la configuración completa, incluido el modo sudo para leer archivos de instantánea propiedad de root.
Conectar con Claude Code
Después de uv tool install zsnoop-mcp:
claude mcp add zsnoop --scope user -- zsnoop-mcp
Eso escribe la entrada directamente en tu configuración de Claude Code; no se necesita
edición de JSON. Reinicia tu sesión de Claude Code; las herramientas aparecen
bajo el espacio de nombres zsnoop.
Si estás ejecutando desde un worktree en lugar de un binario instalado, apunta
el comando a uv run --directory <path> en su lugar:
claude mcp add zsnoop --scope user -- \
uv run --directory ~/path/to/zsnoop-mcp zsnoop-mcp
O, si prefieres editar ~/.claude/settings.json a mano:
{
"mcpServers": {
"zsnoop": { "command": "zsnoop-mcp" }
}
}
Uso
Ver docs/USAGE.md para ejemplos de prompts que ejercitan los flujos de trabajo de recuperación de archivos, auditoría de deriva y forensia.
Documentación
- ¿Nuevo aquí? Comienza con el tutorial de incorporación —
un recorrido de 10 capítulos sobre qué/por qué/cómo a través del código, que termina con un
ejemplo práctico de cómo añadir una nueva herramienta de principio a fin. Se renderiza bien como HTML
vía
uv run mkdocs serve(ver--group docs). - Instalación — configuración local, delegación ZFS, modo sudo
- Ejemplos de uso — prompts concretos que las herramientas manejan
- Modelo de seguridad — modelo de amenazas, garantías, compensación de sudo
- Publicación — publicación en PyPI
Desarrollo
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 ejecuta pip-audit automáticamente cada vez que pyproject.toml o
uv.lock cambian.
Licencia
MIT — ver LICENSE.