Zsnoop
Um servidor MCP para exploração somente leitura de snapshots ZFS em hosts remotos.
Documentação
zsnoop-mcp
Pergunte ao seu assistente de IA coisas como:
- ⏪ "Recupere meu
.zshrcde antes de eu ter feito o commit da reescrita há três semanas." - 🧹 "Quais snapshots com mais de 6 meses estão desperdiçando mais espaço?"
- 🔎 "Quando o diretório
/srv/backupsapareceu pela primeira vez neste host?" - ⌛ "Encontre tudo que foi excluído sob
/home/youruserna última semana e mostre quando cada coisa esteve presente pela última vez." - 🏥 "Algum dos meus pools está apresentando erros de disco? Quando foi o último scrub?"
Um servidor MCP para exploração e recuperação de snapshots ZFS em hosts remotos —
somente leitura por padrão, com ferramentas restore_* opcionais (v0.4.0+) controladas por host.
Navegue, compare, pesquise e leia arquivos de qualquer snapshot em qualquer um dos seus
hosts ZFS através do seu assistente de IA, por uma única conexão SSH persistente por
host. Somente leitura por padrão; as ferramentas graváveis restore_file / restore_dir
(v0.4.0+) são opcionais por host e limitadas por uma lista de permissões de caminho
definida pelo operador — com a configuração padrão, nada no remoto pode ser gravado.
Início 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.
O agente é transmitido via SSH na primeira conexão — nada precisa ser instalado no
host remoto além de python3 (3.11+) e do CLI zfs.
Somente leitura por padrão, imposto por uma lista de permissões explícita no lado
do agente. As ferramentas graváveis restore_file / restore_dir (v0.4.0+) são
opcionais por host e limitadas por uma lista de permissões de caminho definida pelo
operador; com a configuração padrão, elas recusam antes de fazer qualquer coisa.
Sobre este código
Este projeto foi desenvolvido em colaboração com Claude
Code (Anthropic). O autor humano (Mark
Hellewell) definiu a arquitetura, o modelo de segurança e os critérios de aceitação,
e revisou cada mudança antes de ela ser incorporada; Claude cuidou da maior parte da
redação, da estrutura de testes, das refatorações e da documentação.
Somente leitura por padrão foi um requisito rígido desde o primeiro dia, imposto por uma
lista de permissões de métodos explícita e pela suíte de testes. As ferramentas restore_* opcionais
adicionadas na v0.4.0 são os únicos métodos graváveis e são controladas no lado do servidor
por configuração por host (desativadas por padrão; exigem uma lista de permissões de caminho
não vazia quando ativadas) — veja
SECURITY.md. Se você está revisando ou auditando o
código, trate isso como contexto, não como motivo para pular o escrutínio usual.
Como 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
O agente remoto é um script Python de arquivo único, apenas com a biblioteca padrão. Ele pode ser
pré-instalado em ~/bin/zfs-snoop-agent em cada host, ou transmitido via stdin SSH em cada
conexão — sem necessidade de instalação permanente.
Ferramentas expostas ao LLM
Projetado em torno de quatro fluxos de trabalho dominantes: recuperação de arquivos ("me traga /etc/foo como estava ontem" — para sua estação de trabalho, ou restaurado no servidor), auditoria de desvio de configuração ("quando X mudou?"), forense ("o que havia na máquina quando Y quebrou?"), e manutenção de armazenamento ("quais snapshots são maiores / mais antigos?"). As ferramentas estão agrupadas abaixo pelo caso de uso dominante; muitas se combinam entre fluxos de trabalho.
Descoberta e introspecção
| Ferramenta | O que faz |
|---|---|
list_hosts | Hosts configurados |
agent_info | Versão do agente, métodos, limites |
list_pools | Pools ZFS visíveis ao agente (descoberta ao vivo) |
pool_status | zpool status analisado: árvore vdev, scrub, erros |
list_datasets | Sistemas de arquivos e volumes |
dataset_properties | zfs get (todos ou filtrados) com valores + fontes |
Inventário de snapshots e manutenção
| Ferramenta | O que faz |
|---|---|
list_snapshots | Snapshots (filtros opcionais de dataset/tempo/capacidade) |
snapshot_cadence | Resumo: contagens por classe, lacuna (por dataset), intervalo |
stale_snapshots | Snapshots mais antigos que uma frase de tempo, ordenados por exclusividade |
size_delta | Bytes gravados entre dois snapshots de um dataset |
Navegação e dimensionamento dentro de um snapshot
| Ferramenta | O que faz |
|---|---|
list_dir | Listagem de diretório limitada dentro de um snapshot |
size_breakdown | Bytes recursivos para um diretório de snapshot + tamanhos por filho |
top_consumers | Top-N maiores arquivos/diretórios sob uma subárvore de snapshot |
Leitura de conteúdo
| Ferramenta | O que faz |
|---|---|
read_file | Leitura limitada; UTF-8 ou base64 para binário |
find_files | Pesquisa de nome fnmatch dentro de um snapshot |
content_grep | Pesquisa de conteúdo com regex dentro de um snapshot |
checksum_file | SHA-256 do arquivo completo (limite de 256 MiB) para verificações de integridade |
Comparando snapshots e rastreando mudanças
| Ferramenta | O que faz |
|---|---|
diff_snapshots | Diff em nível de caminho entre dois snapshots |
file_diff | Diff unificado de um arquivo entre dois snapshots |
file_history | Versão de cada snapshot de um determinado arquivo em um dataset |
versions_of | file_history deduplicado por hash (apenas versões distintas) |
snapshots_containing | Snapshots em que um caminho existe atualmente (com intervalo de tempo) |
first_appearance | Snapshot mais antigo contendo um caminho |
last_appearance | Snapshot mais recente contendo um caminho; revela quando foi excluído |
find_deleted | Caminhos excluídos entre dois snapshots em uma janela de tempo |
bisect_change | Busca binária pelo snapshot onde um predicado muda |
Recuperação — copiar para sua estação de trabalho
| Ferramenta | O que faz |
|---|---|
fetch_file | Copiar um arquivo de snapshot para um caminho local via SFTP |
fetch_dir | Copiar uma árvore de diretórios de snapshot para um caminho local via SFTP |
Recuperação — restaurar no servidor (opcional, v0.4.0+)
Estas são as únicas ferramentas graváveis. Desativadas por host por padrão;
exigem allow_restore = true e uma lista de permissões restore_paths não vazia
em hosts.toml. Veja SECURITY.md para o modelo de ameaças.
| Ferramenta | O que faz |
|---|---|
restore_file | Restaurar um arquivo de snapshot para um caminho do servidor (opcional) |
restore_dir | Restaurar uma árvore de diretórios de snapshot para um caminho do servidor |
Os parâmetros de intervalo de tempo aceitam ISO 8601 ou frases humanas — yesterday,
last week, 3 days ago, 2 hours ago, etc. A análise ocorre localmente; o
agente só vê timestamps absolutos ISO 8601.
Instalação
Via PyPI (recomendado)
uv tool install zsnoop-mcp
Execute com zsnoop-mcp.
A partir de um clone (para mexer no código)
git clone https://github.com/hamsolodev/zsnoop-mcp.git
cd zsnoop-mcp
uv sync
Execute com uv run zsnoop-mcp a partir do checkout.
Veja docs/PUBLISHING.md para o fluxo por versão (incremento de versão → tag → CI publica via OIDC).
Configuração
Crie ~/.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"
Configuração por host no remoto (uma vez):
# user mode: grant diff for each pool you want to compare snapshots in
sudo zfs allow -u $USER diff rpool
Veja docs/INSTALL.md para a configuração completa, incluindo o modo sudo para ler arquivos de snapshot de propriedade do root.
Integrar ao Claude Code
Após uv tool install zsnoop-mcp:
claude mcp add zsnoop --scope user -- zsnoop-mcp
Isso grava a entrada diretamente na sua configuração do Claude Code; não é necessário
editar JSON. Reinicie sua sessão do Claude Code; as ferramentas aparecem
sob o namespace zsnoop.
Se você estiver executando a partir de um worktree em vez de um binário instalado, aponte
o comando para uv run --directory <path> em vez disso:
claude mcp add zsnoop --scope user -- \
uv run --directory ~/path/to/zsnoop-mcp zsnoop-mcp
Ou, se preferir editar ~/.claude/settings.json manualmente:
{
"mcpServers": {
"zsnoop": { "command": "zsnoop-mcp" }
}
}
Uso
Veja docs/USAGE.md para exemplos de prompts que exercitam os fluxos de recuperação de arquivos, auditoria de desvio e forense.
Documentação
- Novo aqui? Comece com o tutorial de integração —
um passeio de 10 capítulos, o que/porquê/como pelo código, terminando com um
exemplo prático de adição de uma nova ferramenta de ponta a ponta. Renderiza bem como HTML
via
uv run mkdocs serve(veja--group docs). - Instalação — configuração local, delegação ZFS, modo sudo
- Exemplos de uso — prompts concretos que as ferramentas lidam
- Modelo de segurança — modelo de ameaças, garantias, trade-off do sudo
- Publicação — lançamento no PyPI
Desenvolvimento
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
O pre-commit executa pip-audit automaticamente sempre que pyproject.toml ou
uv.lock mudam.
Licença
MIT — veja LICENSE.