restic-defensive-mcp
Servidor MCP stdio estruturalmente somente leitura para inspecionar repositórios restic. Repositórios e credenciais são selados na inicialização; apenas um subconjunto fixo de subcomandos restic pode ser executado (snapshots/ls/find/stats). Sem shell, sem backup/restore/forget/prune.
Documentação
restic-defensive-mcp
Servidor MCP (stdio) estruturalmente somente leitura para inspecionar repositórios restic por meio de um cliente MCP não confiável sem expor um shell, CLI de formato livre ou caminho de mutação.
Meus backups estão presentes e recentes, seus metadados são legíveis e um snapshot contém os arquivos que espero?
Por que não expor restic diretamente?
Restic é uma ferramenta de backup poderosa. Um chamador sem restrições pode:
- excluir histórico de retenção (
forget/prune) - sobrescrever ou extrair dados (
backup/restore/dump) - desbloquear ou reescrever o estado do repositório
- aceitar URLs de repositório arbitrárias e comandos de senha
Wrappers finos que expõem "execute restic com esses argumentos" ou substituições de repositório por chamada recriam esse raio de impacto dentro do MCP.
Este projeto é diferente por construção:
- Repositórios são declarados e selados no início do processo
- A superfície MCP é exclusivamente somente leitura (sem flag de recurso para gravações)
- Apenas um subconjunto compilado de subcomandos do restic pode ser construído
- Sem shell:
exec.CommandContextapenas com argv fixo - Hosts, tags, caminhos e tamanhos de resultados são limitados
- Segredos vêm de arquivos com permissão verificada, nunca de
RESTIC_PASSWORD_COMMAND - Erros são estruturados e redigidos
- Cada ferramenta informa uma classe de custo explícita (
light/moderate/expensive)
Requisitos
- Go 1.25+ (compilação)
- restic 0.17.1+ em
PATH(ourestic_binaryna configuração); testado com 0.19.x - Um cliente MCP que suporte servidores stdio locais
Instalação (a partir do código-fonte)
git clone https://github.com/ThomasCrouzet/restic-defensive-mcp.git
cd restic-defensive-mcp
make build
./bin/restic-defensive-mcp --version
Início rápido
- Crie arquivos de senha e de localização do repositório (arquivos regulares, sem symlinks). Evite colocar a senha no histórico do shell:
secret_dir="${XDG_CONFIG_HOME:-$HOME/.config}/restic-defensive-mcp"
install -d -m 700 "$secret_dir"
install -m 600 /dev/null "$secret_dir/repository"
printf '%s\n' '/path/to/your/repo' > "$secret_dir/repository"
install -m 600 /dev/null "$secret_dir/password"
"${EDITOR:-vi}" "$secret_dir/password"
-
Copie e edite
config.example.yaml, incluindo os dois caminhos de arquivo acima. -
Execute o binário recém-compilado:
./bin/restic-defensive-mcp --config /path/to/config.yaml
- Aponte seu host MCP para o binário com
--config(somente transporte stdio).
Exemplo de trecho de host MCP (ilustrativo):
{
"mcpServers": {
"restic-defensive": {
"command": "/absolute/path/to/restic-defensive-mcp",
"args": ["--config", "/etc/restic-defensive-mcp/config.yaml"]
}
}
}
Ferramentas (exatamente sete)
| Ferramenta | Custo | Propósito |
|---|---|---|
restic_capabilities | leve | Versões, limites, backends, avisos |
list_repositories | leve | IDs configurados e listas de permissão (sem URLs) |
list_snapshots | leve | Lista de snapshots limitada |
get_snapshot | leve | Metadados de um snapshot |
browse_snapshot | moderado | Listagem de diretório dentro do caminho permitido |
find_files | moderado–caro | Busca simples por glob (não regex arbitrário) |
repository_stats | moderado–caro | Estatísticas de tamanho/contagem para modos permitidos |
Não há nenhum run_restic, backup, restore, forget, prune, unlock,
check --read-data nem argumento de URL de repositório.
Formas completas de requisição/resposta: docs/tool-contract.md.
Configuração
Veja config.example.yaml. Princípios:
- Chamadores MCP passam apenas
repository_id - Prefira
repository_file+password_fileem vez de segredos inline - Localizações de repositório e credenciais de backend são carregadas e seladas na inicialização; alterar seus arquivos de origem não redireciona um servidor em execução
allowed_hosts/allowed_tags/allowed_pathssão aplicação de regras, não cosméticos- Listas de permissão vazias significam sem restrição para essa dimensão; o servidor registra um
aviso na inicialização (
empty_allowlist) para que operadores percebam - Chaves YAML desconhecidas e múltiplos documentos YAML são rejeitados
- Arquivos de segredo devem ser arquivos regulares, sem symlink; Unix exige modo
0600ou mais restritivo, enquanto implantações Windows devem aplicar ACLs NTFS equivalentes find_filesexige umpathexplícito quando múltiplas raízes estão na lista de permissão- Limites de tempo de execução: zeros se tornam padrões; valores fora do mínimo/máximo absoluto são rejeitados (não ajustados silenciosamente). Os padrões são o ponto de partida recomendado; valores podem ser aumentados apenas até esses tetos
Backends suportados (v0.1)
| Backend | Suportado |
|---|---|
| sistema de arquivos local | sim (somente caminhos absolutos) |
| S3 | sim (credenciais via arquivos de ambiente permitidos) |
| Backblaze B2 | sim |
| servidor REST | sim |
| SFTP | não (inicia ssh) |
| rclone | não (inicia rclone) |
| outros | não |
Notas de compatibilidade: docs/restic-compatibility.md.
Efeitos locais: cache e locks
A inspeção não é um no-op puro no disco nem na tabela de locks do repositório:
- restic pode criar ou atualizar um cache local (
cache_dirou padrão) - restic pode adquirir um lock de repositório durante snapshots/ls/find/stats
Este servidor nunca muta intencionalmente conteúdos de backup ou conjuntos de snapshots.
Ele também nunca executa verificação completa de dados (restic check --read-data).
repository_stats responde apenas perguntas de tamanho/contagem.
Detalhes: SECURITY.md.
Limites de privacidade
Nomes de arquivos de snapshot, caminhos, hosts, tags, tamanhos e timestamps são sensíveis. Este servidor:
- nunca retorna conteúdos de arquivos
- nunca retorna URLs de repositório ou caminhos de arquivos de segredo
- limita listagens e resultados de busca
- sanitiza caracteres de controle em nomes
- mantém logs de auditoria livres de caminhos completos por padrão
Demonstração (repositório temporário local)
make demo
Executa o harness de ponta a ponta contra um repositório restic descartável criado por
internal/testrepo. Ele exercita todas as ferramentas MCP, comprova a negação de caminho e a
ausência de ferramentas de mutação e, em seguida, remove o fixture. As operações do repositório
permanecem locais; downloads normais de módulos Go ainda podem ocorrer em um checkout novo.
Desenvolvimento
make fmt
make lint
make test # unit tests
make race # race detector
make fuzz-smoke # short run of every fuzz target
make integration # real restic temp repo (requires restic)
make vet
Dependências
| Módulo | Por quê |
|---|---|
github.com/modelcontextprotocol/go-sdk | SDK Go oficial do MCP (servidor/cliente stdio) |
gopkg.in/yaml.v3 | Análise de arquivos de configuração |
O próprio Restic é um binário externo, não um módulo Go.
Não-objetivos
- Orquestração ou agendamento de backups
- Restore / forget / prune / unlock / repair
- Proxy genérico de CLI do restic
- Importação de configuração do Autorestic
- API remota multi-tenant
restic check --read-datacompleto como ferramenta casual- Telemetria ou atualização automática
Licença
MIT, veja LICENSE.