SILO-MCP
Servidor MCP que move arquivos entre seu sistema de arquivos e armazenamento em nuvem.
Documentação
Silo MCP
Um servidor MCP auto-hospedado que move arquivos entre seu sistema de arquivos e armazenamento em nuvem — nove plataformas, uma única superfície de ferramentas. Envie, baixe, liste, pesquise, exclua, gere links de compartilhamento e copie arquivos diretamente de uma nuvem para outra, sem dar a um LLM acesso bruto ao sistema de arquivos ou um saco de credenciais específicas de plataforma para gerenciar.
Não é "local-first" — os arquivos vivem na nuvem e cada operação fala com uma API de provedor remoto. O que permanece local é a parte que importa para a confiança: o servidor roda como um subprocesso na sua máquina, suas credenciais ficam no chaveiro do sistema operacional (nunca na nuvem, em um arquivo de configuração ou em um argumento de chamada de ferramenta), e o log de auditoria de transferências é um arquivo SQLite local.
Armazenamentos de documentos: Dropbox · Google Drive · OneDrive · Box · Google Photos (somente upload) · Yandex Disk Armazenamentos de objetos: compatível com S3 (AWS S3, Cloudflare R2, MinIO) · Google Cloud Storage · Azure Blob Storage
O que você pode fazer com o Silo MCP?
- Copiar um arquivo diretamente de uma nuvem para outra — "copie meu arquivo
/photosdo Dropbox para meu bucket S3", "migre este arquivo do Drive para o OneDrive" — em uma única chamada de ferramenta, sem download manual seguido de upload. A única coisa que uma integração de armazenamento de um único fornecedor estruturalmente não consegue fazer. - Mover arquivos para dentro e para fora do armazenamento em nuvem — "envie
report.pdfpara o Dropbox", "baixenotes.txtdo Google Drive para que eu possa usá-lo" — em todas as nove plataformas com um único conjunto de ferramentas. - Navegar e pesquisar seus armazenamentos de documentos por pasta ou consulta, e listar buckets de armazenamento de objetos por prefixo de chave.
- Gerar links compartilháveis para um arquivo — URLs pré-assinadas/assinadas nos armazenamentos de objetos e no Box (com expiração), links de compartilhamento da plataforma nos demais.
- Fazer ponte com outros servidores MCP — um
download_fileaqui gera um caminho local que você pode entregar diretamente a outro servidor (por exemplo, omedia_pathsde um servidor de postagem social). - Manter uma trilha de auditoria local — cada upload, download, exclusão e link de
compartilhamento é registrado em um log SQLite local que você pode consultar com
list_transfers.
Tudo isso passa pelo seu cliente MCP em linguagem natural — veja Exemplos de fluxos de trabalho.
Início rápido: pip install -e . → adicione silo-mcp à configuração do seu cliente MCP
→ silo-mcp-accounts add dropbox --label personal → peça ao seu
cliente para listar seus arquivos do Dropbox. Passos completos em
Instalação e Adicionar contas abaixo.
Conteúdo
- O que você pode fazer com o Silo MCP?
- Por quê
- Arquitetura
- Requisitos
- Instalação
- Configure seu cliente MCP
- Clientes suportados
- Uso com Ollama
- Adicionar contas
- Exemplos de fluxos de trabalho
- Ferramentas
- Plataformas e ferramentas suportadas
- Atrito de configuração e formato de credenciais por plataforma
- Segurança de caminhos
- Notas específicas por plataforma
- Segurança
- Proteção
- Testes
- Solução de problemas
- Relacionados
- Licença
Por quê
A maioria das configurações de "dê ao LLM seu armazenamento em nuvem" cai em uma de duas armadilhas: uma integração de plataforma única que morre no momento em que você troca de provedor, ou acesso irrestrito a arquivos locais que permite que uma conversa manipulada leia ou envie qualquer coisa no disco. O Silo MCP é construído contra ambas:
- Uma superfície de ferramentas, nove plataformas.
upload_file,download_file,list_files,search_files,delete_file,create_share_linkse comportam da mesma forma independentemente da plataforma para a qual você os aponta — armazenamentos de objetos (bucket+chave) e armazenamentos de documentos (baseados em caminho) compartilham um único contratoFileStore. - Confinado por design, não por convenção.
local_pathpara uploads e o destino para downloads são ambos argumentos de chamada de ferramenta fornecidos pelo LLM, então ambos são rigidamente confinados a diretórios raiz configurados — uma conversa manipulada não pode pedir a este servidor para ler uma chave SSH ou gravar um download em um lugar onde não deveria. - Mutações exigem
confirm=true.upload_file,delete_fileecreate_share_linktodas alteram estado remoto ou criam um link com credencial de portador e exigem confirmação deliberada.download_file/list_files/search_filesapenas gravam localmente, então não exigem confirmação. - Multi-contas desde o início. Cada ferramenta aceita um rótulo opcional
account— execute um Dropbox de trabalho e um Dropbox pessoal lado a lado sem reconfigurar nada.
Arquitetura
flowchart TB
subgraph Client["MCP Client"]
direction LR
CD["Claude Desktop / Code<br/>(stdio)"]
OL["Ollama bridge<br/>(streamable-http / SSE)"]
end
subgraph Silo["Silo MCP Server (server.py)"]
direction TB
Tools["Tool surface<br/>upload_file · download_file · list_files<br/>search_files · delete_file · create_share_link"]
Paths["paths.py<br/>upload/download root containment"]
Registry["stores/registry.py<br/>resolve(platform, account)"]
Accounts["accounts.py<br/>credential storage + OAuth refresh"]
History[("db.py<br/>SQLite transfer log")]
end
subgraph Backends["FileStore implementations"]
direction LR
Doc["Document stores<br/>Dropbox · Drive · OneDrive<br/>Box · Photos · Yandex Disk"]
Obj["Object stores<br/>S3-compatible · GCS · Azure Blob"]
end
FS[("Local filesystem<br/>upload/download roots")]
Cred[("OS credential store<br/>Windows / macOS / Linux keyring")]
CD --> Tools
OL --> Tools
Tools --> Paths --> FS
Tools --> Registry
Registry --> Doc
Registry --> Obj
Registry --> Accounts --> Cred
Tools --> History
Cada chamada de ferramenta resolve um par (platform, account) para uma implementação FileStore
e uma credencial de accounts.py, verifica qualquer
caminho local contra as raízes de upload/download, executa contra a
API real da plataforma e registra o resultado — o mesmo formato independentemente de qual
dos nove backends está do outro lado.
Requisitos
- Python 3.11+
- Um armazenamento de credenciais do sistema operacional que
keyringpossa usar (Gerenciador de Credenciais do Windows, Chaveiro do macOS ou um provedor de Secret Service no Linux) — credenciais nunca são gravadas em disco em texto puro ou passadas por uma chamada de ferramenta MCP.
Instalação
git clone https://github.com/gouthamkallempudi/silo-mcp.git
cd silo-mcp
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\Activate.ps1
pip install -e .
Os SDKs de armazenamento de objetos são extras opcionais — instale apenas o que precisar:
pip install -e ".[s3]" # AWS S3 / Cloudflare R2 / MinIO
pip install -e ".[gcs]" # Google Cloud Storage
pip install -e ".[azure]" # Azure Blob Storage
pip install -e ".[all]" # all three
Uma instalação principal (sem extras) cobre Dropbox/Drive/OneDrive/Box/Google
Photos/Yandex Disk sem dependência além de httpx — o servidor
degrada graciosamente se um SDK de armazenamento de objetos não estiver instalado, em vez de
falhar ao iniciar.
Configure seu cliente MCP
Adicione à configuração MCP do seu cliente (por exemplo, o
claude_desktop_config.json do Claude Desktop, ou o .mcp.json do Claude Code):
{
"mcpServers": {
"silo-mcp": {
"command": "silo-mcp"
}
}
}
silo-mcp deve ser resolvível em PATH dentro do ambiente a partir do qual seu cliente
inicia o servidor — se você instalou em um virtualenv, aponte
command para o executável silo-mcp desse venv diretamente (por exemplo,
/path/to/silo-mcp/.venv/bin/silo-mcp) em vez de depender da ativação do shell.
Opções de transporte (stdio padrão, HTTP para clientes de rede)
O padrão é stdio, o que todo cliente MCP de desktop (Claude Desktop,
Claude Code, Cursor, etc.) inicia como subprocesso — nenhuma porta de rede é aberta.
Para um cliente que não pode iniciar um subprocesso local e precisa alcançar o
servidor via HTTP (veja Uso com Ollama
abaixo), defina:
SILO_MCP_TRANSPORT=streamable-http SILO_MCP_HOST=127.0.0.1 SILO_MCP_PORT=8000 silo-mcp
SILO_MCP_TRANSPORT também aceita sse (o transporte HTTP mais antigo, mantido
para clientes que ainda não migraram para streamable-http). SILO_MCP_HOST/
SILO_MCP_PORT são lidos apenas para os dois transportes HTTP e o padrão é
127.0.0.1:8000.
[!WARNING] Este servidor não tem autenticação embutida para o modo HTTP — não o vincule a
0.0.0.0nem o exponha além de localhost sem colocar um proxy reverso com autenticação na frente dele, já que cada chamada de ferramenta alcança suas contas de armazenamento em nuvem.
Clientes suportados
Qualquer cliente MCP que possa iniciar um servidor stdio local funciona — o servidor usa apenas chamadas de ferramenta MCP padrão, sem recursos específicos de cliente. Verificados e esperados para funcionar:
| Cliente | Configuração | Notas |
|---|---|---|
| Claude Code | .mcp.json no projeto ({"mcpServers":{"silo-mcp":{"command":"silo-mcp"}}}) | Verificado de ponta a ponta pelo protocolo MCP. |
| Claude Desktop | claude_desktop_config.json — mesmo bloco mcpServers | stdio. |
| Cursor / VS Code (MCP) | mcp.json deles — mesmo bloco mcpServers | stdio. |
| Ollama (via uma ponte) | Aponte a ponte para o transporte HTTP | Veja Uso com Ollama. |
[!TIP] Se
silo-mcpnão estiver noPATHdo shell de inicialização (comum com virtualenvs), definacommandpara o executável do venv diretamente, por exemplo,C:\\path\\to\\silo-mcp\\.venv\\Scripts\\silo-mcp.exeno Windows ou/path/to/.venv/bin/silo-mcpem outros sistemas.
Uso com Ollama
Ollama não fala MCP nativamente — ele precisa de um cliente MCP no meio que transforme a chamada de ferramentas do Ollama em chamadas de ferramenta MCP, o mesmo papel que Claude Desktop/Code desempenham para Claude. Este servidor não inclui essa ponte (mantida fora do escopo para permanecer um pacote de servidor simples), mas qualquer cliente Ollama com suporte a MCP funciona quando você o aponta para streamable-http em vez de stdio:
- Inicie o servidor no modo HTTP:
SILO_MCP_TRANSPORT=streamable-http silo-mcp. - Aponte seu cliente MCP do lado do Ollama para
http://127.0.0.1:8000/mcp. - Use um modelo com capacidade de chamada de ferramentas (por exemplo,
llama3.1,qwen2.5) — o Ollama só roteia chamadas de ferramentas para modelos que suportam o campo de APItools.
Adicionar contas
As credenciais são adicionadas via CLI com entrada oculta, nunca por uma chamada de ferramenta MCP, e armazenadas no armazenamento de credenciais do seu sistema operacional:
silo-mcp-accounts add dropbox --label personal
silo-mcp-accounts add google_drive --label personal
silo-mcp-accounts add onedrive --label personal
silo-mcp-accounts add box --label personal
silo-mcp-accounts add google_photos --label personal
silo-mcp-accounts add yandex_disk --label personal
silo-mcp-accounts add s3 --label personal
silo-mcp-accounts add gcs --label personal
silo-mcp-accounts add azure_blob --label personal
silo-mcp-accounts list
Configuração OAuth pela primeira vez (Drive, Photos, OneDrive, Box)
Estas quatro plataformas precisam de um refresh_token antes que silo-mcp-accounts add
as aceite — e obter o primeiro exige uma autorização única no
navegador, não apenas um par client_id/secret. Registre um aplicativo
no console de desenvolvedor de cada plataforma e depois execute:
silo-mcp-accounts oauth google_drive --label personal
silo-mcp-accounts oauth google_photos --label personal
silo-mcp-accounts oauth onedrive --label personal
silo-mcp-accounts oauth box --label personal
Isso abre seu navegador para a tela de consentimento da plataforma, escuta em
http://localhost:8765/callback para o redirecionamento, troca o código por
um refresh_token e armazena a conta — sem necessidade de executar add depois.
Registro de aplicativo, por plataforma:
- Google (Drive + Photos compartilham um aplicativo): Google Cloud
Console → novo projeto → APIs &
Services → habilite a Google Drive API e a Photos Library API →
tela de consentimento OAuth (Externo é suficiente para testes pessoais, adicione
você mesmo como usuário de teste) → Credenciais → Criar ID de cliente OAuth → tipo
Aplicativo de desktop. Clientes de aplicativo de desktop aceitam qualquer redirecionamento
http://localhost:<port>sem pré-registro, então não é necessário configurar URI de redirecionamento. - OneDrive: Azure Portal → App
registrations → Novo registro → plataforma Aplicativos móveis e de desktop
→ adicione o URI de redirecionamento
http://localhost:8765/callbackexatamente (o Azure exige correspondência exata). Permissões de API → Microsoft Graph → adicioneFiles.ReadWriteeoffline_access(delegadas). Certificados e segredos → novo segredo de cliente. - Box: Box Developer Console
→ Criar novo aplicativo → Aplicativo personalizado → Autenticação de usuário (OAuth 2.0)
→ em Configuração, defina o URI de redirecionamento para
http://localhost:8765/callbackexatamente (o Box também exige correspondência exata) e marque os escopos que você precisa (Leitura/gravação de arquivos).
Se você usar --port para escolher uma porta local diferente, use essa mesma porta
no URI de redirecionamento que você registrar.
Obtendo um token do Yandex Disk
O Yandex Disk usa um token estático como o Dropbox — sem refresh_token, então não faz
parte do fluxo de inicialização silo-mcp-accounts oauth acima. Sua configuração de aplicativo OAuth
usa uma concessão implícita: o token volta diretamente no
navegador, sem etapa de troca de código para script.
- oauth.yandex.com → Criar aplicativo (ou reutilize um existente).
- Em Plataformas, marque Serviços web e defina o URI de redirecionamento
para
https://oauth.yandex.com/verification_code— a página embutida do próprio Yandex que apenas exibe o token, sem necessidade de ouvinte local para este caso. - Em Permissões, conceda acesso ao Disk:
cloud_api:disk.readecloud_api:disk.write(oucloud_api:disk.app_folderem vez dedisk.writese quiser limitar a uma pasta específica do aplicativo em vez de todo o disco). - Salve o aplicativo e anote seu ID.
- Visite
https://oauth.yandex.com/authorize?response_type=token&client_id=<your-app-id>em um navegador, aprove o acesso — o token é mostrado diretamente na página redirecionada. silo-mcp-accounts add yandex_disk --label personal, cole o token.
Configuração em massa mais rápida: importar arquivo ou variáveis de ambiente
Executar o add uma vez por plataforma fica cansativo rapidamente quando você está configurando várias de uma vez. Dois caminhos mais rápidos — ambos ainda terminam no chaveiro do sistema operacional, nunca em um arquivo ou variável de ambiente que este projeto persista por conta própria:
Arquivo de importação — copie o modelo, preencha os valores reais, importe de uma vez. silo-accounts.example.yaml na raiz do repositório tem uma entrada para todas as nove plataformas com os nomes exatos dos campos que cada uma precisa e um comentário sobre onde obter cada valor:
cp silo-accounts.example.yaml silo-accounts.yaml
# edit silo-accounts.yaml with real values, delete platforms you don't use
silo-mcp-accounts import silo-accounts.yaml
JSON também funciona (mesma forma platform -> label -> fields), despachado pela extensão do arquivo — qualquer coisa que não termine em .json é analisada como YAML.
silo-accounts.yaml/.json, credentials.yaml/.json e qualquer *.local.yaml/.json já estão em .gitignore, mas trate isso como uma rede de segurança, não como o plano — exclua o arquivo imediatamente após importá-lo. São segredos em texto puro no disco enquanto existirem, estejam ou não no gitignore.
Variáveis de ambiente — para configuração via script ou CI onde um arquivo não é prático, o add lê SILO_MCP_CRED_<PLATFORM>_<FIELD> antes de solicitar:
SILO_MCP_CRED_DROPBOX_ACCESS_TOKEN=sl.xxx silo-mcp-accounts add dropbox --label personal
Variáveis de ambiente são mais expostas do que um arquivo que você exclui (listagens de processos, histórico do shell, dumps de crash) — prefira o arquivo de importação para qualquer coisa além de configuração automatizada rápida de teste.
Exemplos de fluxos de trabalho
Uma vez que o servidor está conectado, você não chama as ferramentas diretamente — você pede ao seu cliente MCP (Claude Desktop, Claude Code, etc.) em linguagem natural e ele escolhe a ferramenta e os argumentos certos. Esses exemplos foram todos exercitados de ponta a ponta sobre o protocolo MCP real contra contas ativas do Dropbox, Google Drive e Google Photos.
Dropbox / OneDrive / Yandex Disk (caminhos reais):
- "Envie
report.pdfda minha pasta de uploads para o Dropbox." - "O que há na raiz do meu Dropbox? Encontre qualquer coisa chamada
invoice." - "Baixe
notes.txtdo Dropbox e me dê um link compartilhável para ele." - "Exclua
old-draft.txtdo meu Dropbox."
Google Drive / Box (endereçado por id — pesquise primeiro, depois aja no id):
- "Encontre
budget.xlsxno meu Google Drive." → depois "Baixe esse." - "Compartilhe esse arquivo com um link público."
Google Photos (somente upload):
- "Envie esta captura de tela para o meu Google Photos."
Armazenamentos de objetos — S3 / GCS / Azure Blob (precisam de um bucket/contêiner):
- "Envie
backup.zippara o meu bucket S3my-backups." - "Liste tudo sob
logs/no bucketmy-backups." - "Me dê um link pré-assinado de 1 hora para
backup.zipemmy-backups."
Cópia entre nuvens (de uma plataforma direto para outra):
- "Copie
report.pdfdo meu Dropbox para o meu Google Drive." - "Migre tudo o que acabei de encontrar no Drive para o meu bucket S3
archive."
Entre servidores:
- "Pegue minha foto de perfil do Google Drive para eu anexá-la a um post." —
download_fileentrega um caminho local que outro servidor MCP pode usar.
O mapeamento completo de frases para chamadas de ferramenta:
| Você diz | O que é executado |
|---|---|
| "Que armazenamento em nuvem posso usar aqui e quais contas estão configuradas?" | list_supported_stores |
"Envie report.pdf da minha pasta de uploads para o Dropbox." | upload_file(dropbox, …, confirm=true) — o cliente define confirm depois que você concorda |
| "O que há na raiz do meu Dropbox?" | list_files(dropbox) |
"Encontre arquivos chamados invoice no meu Dropbox." | search_files(dropbox, "invoice") |
"Baixe notes.txt do Dropbox para eu poder usá-lo." | download_file(dropbox, "/notes.txt") |
| "Me dê um link compartilhável para esse arquivo." | create_share_link(dropbox, …, confirm=true) |
"Exclua old-draft.txt do Dropbox." | delete_file(dropbox, "/old-draft.txt", confirm=true) |
| "Coloque esta imagem no meu Google Photos." | upload_file(google_photos, …, confirm=true) |
| "Copie meu currículo do Dropbox para um rascunho de tweet." | download_file aqui → entregue o caminho local para o media_paths de outro servidor MCP |
| "Mostre o que movi recentemente." | list_transfers |
Como o Google Drive e o Box endereçam arquivos por id, um fluxo natural lá é em duas etapas — "encontre budget.xlsx no meu Drive" (search_files, retorna o id), depois "baixe esse" / "compartilhe esse" usando o id que o cliente acabou de ver. O cliente cuida desse encadeamento para você.
Ações de mutação (upload_file, delete_file, create_share_link) exigem confirm=true, então um bom cliente mostrará exatamente o que está prestes a fazer e só prosseguirá após sua aprovação — uma exclusão ou um link público nunca acontece silenciosamente a partir de um pedido vago.
Ferramentas
| Ferramenta | Portão de confirmação | Descrição |
|---|---|---|
list_supported_stores() | — | Cada plataforma conhecida, seu tipo (documento vs. armazenamento de objetos), capacidades e contas configuradas. |
list_accounts(platform) | — | Contas configuradas, opcionalmente filtradas. |
upload_file(platform, local_path, remote_path, account, target, confirm) | ✅ | local_path deve estar dentro da raiz de upload. |
download_file(platform, remote_path, local_filename, account, target) | — | Grava na raiz de download e retorna o caminho local. |
list_files(platform, folder_or_prefix, account, target) | — | Listagem de pastas (armazenamentos de documentos) ou listagem de prefixos (armazenamentos de objetos). |
search_files(platform, query, account, target) | — | Erros claros onde a plataforma não suporta pesquisa. |
delete_file(platform, remote_path, account, target, confirm) | ✅ | |
create_share_link(platform, remote_path, account, target, expires_in_seconds, confirm) | ✅ | Um link que qualquer pessoa pode usar para ler o arquivo sem conta, onde houver suporte. Veja Links de compartilhamento. |
copy_file(from_platform, from_remote_path, to_platform, to_remote_path, from_account, to_account, from_target, to_target, confirm) | ✅ | Copie um arquivo direto de uma nuvem para outra. Veja Cópia entre nuvens. |
list_transfers(platform, limit) | — | Log de auditoria local de uploads, downloads, exclusões, links de compartilhamento e cópias entre nuvens. |
get_client_capabilities(platform) | — | Verifique o que uma plataforma suporta antes de chamá-la. |
target é o nome do bucket/contêiner para armazenamentos de objetos — ignorado para armazenamentos de documentos.
Links de compartilhamento
expires_in_seconds é honrado nativamente em S3, GCS, Azure Blob e Box (URLs pré-assinadas/assinadas, ou o unshared_at do Box). Dropbox, Google Drive, OneDrive e Yandex Disk também criam um link, mas nenhuma de suas APIs suporta expiração em conta pessoal/não comercial, então o parâmetro é aceito para consistência de interface, mas não é aplicado lá. Não disponível no Google Photos (somente upload).
Protegido por confirm=true mesmo que não mova ou exclua dados — a URL retornada é em si uma credencial de portador, a mesma preocupação de exfiltração que upload_file tem.
Cópia entre nuvens
copy_file move um arquivo diretamente de uma plataforma para outra — "copie meu /photos/id.png do Dropbox para meu bucket backups do S3", "migre este arquivo do Drive para o OneDrive" — em uma única chamada de ferramenta. Esta é a única coisa que uma integração de armazenamento de fornecedor único estruturalmente não pode fazer; é a recompensa de colocar todos os backends atrás de uma única interface.
sequenceDiagram
actor User
participant Client as MCP Client<br/>(Claude)
participant Silo as Silo MCP
participant Src as Source cloud<br/>(Dropbox)
participant Dst as Destination cloud<br/>(Google Drive)
User->>Client: "Copy report.pdf from Dropbox to my Google Drive"
Client->>Silo: copy_file(from=dropbox, to=google_drive, confirm=false)
Silo-->>Client: dry run — will copy /report.pdf → google_drive:report.pdf
Client-->>User: About to copy Dropbox → Google Drive. Approve?
User->>Client: yes
Client->>Silo: copy_file(…, confirm=true)
Note over Silo: stream through a temp file<br/>the server controls
Silo->>Src: download /report.pdf
Src-->>Silo: bytes → temp file on disk
Silo->>Dst: upload from temp file
Dst-->>Silo: new file id + metadata
Note over Silo: delete temp file,<br/>log 'copy' to the audit trail
Silo-->>Client: copied ✓
Client-->>User: Done — report.pdf is now in your Google Drive
O LLM nunca toca nos bytes do arquivo ou em um caminho intermediário — ele apenas emite uma chamada copy_file e o servidor cuida do download → temp → upload → limpeza, protegido pela sua aprovação.
- Ele transmite através de um arquivo local temporário que o servidor cria e exclui — você nunca lida com um download/upload intermediário, e o caminho temporário nunca é um argumento fornecido pelo chamador (portanto, não está sujeito à verificação de contenção da raiz de upload da mesma forma que
upload_fileestá). from_remote_pathé endereçado da forma que a plataforma de origem espera para um download (um caminho para Dropbox/OneDrive/Yandex/armazenamentos de objetos; um id de arquivo para Google Drive/Box — pesquise primeiro para obtê-lo).to_remote_pathassume o nome base da origem por padrão; passe-o explicitamente quando a origem for endereçada por id.from_target/to_targetsão os nomes de bucket/contêiner quando qualquer extremidade é um armazenamento de objetos.- Exige
confirm=true— ele grava no destino. Registrado no log de auditoria como umcopy, com ambas as extremidades capturadas.
[!NOTE] A cópia é limitada pelos mesmos limites de 5 GiB de download/upload, e o download da origem é transmitido para o disco, então uma cópia grande entre nuvens não armazenará o arquivo inteiro em memória.
Plataformas e ferramentas suportadas
Quais operações cada plataforma suporta e seu modelo de autenticação. ✅ suportado · — não suportado. target = o nome do bucket/contêiner que os armazenamentos de objetos exigem.
| Plataforma | Tipo | Upload | Download | Listar | Pesquisar | Excluir | Link de compartilhamento | Auth |
|---|---|---|---|---|---|---|---|---|
| Dropbox | documento | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | Token estático |
| Google Drive | documento | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | OAuth2 refresh |
| OneDrive | documento | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | OAuth2 refresh |
| Box | documento | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ (com expiração) | OAuth2 refresh |
| Google Photos | documento | ✅ | — | — | — | — | — | OAuth2 refresh |
| Yandex Disk | documento | ✅ | ✅ | ✅ | — | ✅ | ✅ | Token estático |
| Compatível com S3 | objeto (precisa de target) | ✅ | ✅ | ✅ | — | ✅ | ✅ (pré-assinado) | Chave/segredo estáticos |
| Google Cloud Storage | objeto (precisa de target) | ✅ | ✅ | ✅ | — | ✅ | ✅ (assinado) | JSON de conta de serviço |
| Azure Blob | objeto (precisa de target) | ✅ | ✅ | ✅ | — | ✅ | ✅ (SAS) | String de conexão |
[!NOTE] Google Photos é somente upload — o Google removeu o acesso à API de leitura da biblioteca em março de 2025. Armazenamentos de objetos e Yandex Disk não têm pesquisa de conteúdo, apenas listagem por prefixo/caminho. Detalhes em Notas específicas da plataforma.
Fricção de configuração e formato de credenciais por plataforma
Tabela de formato de credenciais
| Plataforma | Credencial | Modelo de auth | Configuração |
|---|---|---|---|
| Dropbox | access_token | Token estático | App Console → gerar token. Sem dança de refresh. Veja escopos abaixo — um erro missing_scope significa regenerar, não reconfigurar. |
| Yandex Disk | access_token | Token estático, concessão implícita (sem etapa de troca de código) | Veja Obtendo um token do Yandex Disk acima. |
| Azure Blob | connection_string | Estático | Conta de armazenamento → Chaves de acesso. O mais simples dos armazenamentos de objetos. |
| S3 | access_key_id, secret_access_key, opcional region/endpoint_url | Estático | Usuário IAM da AWS, ou credenciais R2/MinIO + endpoint_url. |
| GCS | service_account_json | JWT (conta de serviço) | Google Cloud Console → criar uma chave de conta de serviço, cole o JSON inteiro. |
| Google Drive | client_id, client_secret, refresh_token | OAuth2, atualizado a cada chamada | Tela de consentimento OAuth do Google Cloud + uma autorização única para obter o token de refresh inicial. |
| Google Photos | igual ao Drive | OAuth2, escopo photoslibrary.appendonly | Mesmo aplicativo do Google Cloud; somente upload, veja abaixo. |
| OneDrive | client_id, client_secret, refresh_token | OAuth2, atualizado a cada chamada | Registro de aplicativo no Azure AD. |
| Box | client_id, client_secret, refresh_token | OAuth2, atualizado a cada chamada, token rotaciona | Aplicativo de desenvolvedor Box. Cada refresh emite um novo token de refresh automaticamente e este servidor o persiste de volta no chaveiro — não reutilize um antigo manualmente. |
Dropbox, Yandex Disk, S3, GCS e Azure Blob usam credenciais estáticas lidas uma vez. Google Drive, OneDrive, Box e Google Photos são todos OAuth2 de grandes empresas de tecnologia com tokens de acesso de curta duração (~1h) — este servidor chama o endpoint de token de cada plataforma novamente antes de cada solicitação de API, em vez de armazenar em cache, mantendo a história de correção simples ao custo de uma solicitação extra rápida (~200ms) por chamada.
Permissões/escopos necessários por plataforma
Os campos de credencial acima só lhe dão um token — o token também precisa do escopo certo, ou cada chamada falha com um erro de permissão, independentemente de quão corretamente esteja armazenado. Configurado no lado da plataforma, não aqui:
| Plataforma | Escopo(s) obrigatório(s) | Onde configurar |
|---|---|---|
| Dropbox | files.content.write, files.content.read, files.metadata.read, sharing.write (para create_share_link) | App Console → aba Permissões → marque os escopos → clique em Enviar. Os escopos são fixados no momento da emissão do token — você deve gerar um token novo após alterar os escopos; um token já emitido não os adquire retroativamente. |
| Yandex Disk | Acesso total ao disco (leitura/gravação) | configuração do app em oauth.yandex.com → marque a permissão de leitura/gravação do Disco ao criar o app, antes de emitir o token. |
| Google Drive | https://www.googleapis.com/auth/drive | Solicitado automaticamente pelo silo-mcp-accounts oauth google_drive — nada a configurar manualmente além de ativar a API do Drive no projeto. |
| Google Photos | https://www.googleapis.com/auth/photoslibrary.appendonly | Igual ao acima, via silo-mcp-accounts oauth google_photos; ative a API da Biblioteca de Fotos no projeto. |
| OneDrive | Files.ReadWrite, offline_access (delegado) | Portal do Azure → registro do app → Permissões de API → Microsoft Graph → adicione ambas e depois Conceda consentimento do administrador se o seu locatário exigir. Também solicitado automaticamente pelo silo-mcp-accounts oauth onedrive. |
| Box | "Ler e gravar todos os arquivos e pastas armazenados no Box" (ou mais restrito, conforme sua necessidade) | Developer Console → app → aba Configuração → Escopos do aplicativo. |
| S3 | s3:GetObject, s3:PutObject, s3:ListBucket, s3:DeleteObject no bucket de destino (além disso, a geração de URLs pré-assinadas não exige permissão extra — é uma operação de assinatura local) | política do IAM anexada ao usuário/papel cujas access_key_id/secret_access_key você está usando. |
| GCS | Storage Object Admin (ou Object Viewer + Object Creator para uma concessão mais restrita) no bucket/projeto | IAM e Administrador → conceda o papel à conta de serviço antes de gerar a chave dela. |
| Azure Blob | Acesso total à conta pela chave da conta na cadeia de conexão — não existe o conceito de escopo separado | N/A — a própria cadeia de conexão é o limite de permissão; use uma cadeia de conexão restrita por SAS se quiser limitar o escopo. |
[!TIP] O Dropbox é o que tem mais chance de te surpreender: um 401
missing_scopecom um token aparentemente correto quase sempre significa que os escopos foram alterados depois que o token foi gerado. Regere o token, não apenas salve-o novamente.
Segurança de caminhos
local_path para uploads e o nome do arquivo de destino para downloads são
ambos argumentos de chamada de ferramenta fornecidos pelo LLM, então ambos ficam
confinados a uma raiz configurada cada, nas duas direções:
SILO_MCP_UPLOAD_ROOT(padrão~/silo-mcp/uploads) — arquivos fora deste diretório não podem ser enviados. Isso importa muito aqui: sem isso, uma conversa manipulada poderia pedir ao servidor para enviar um arquivo local arbitrário (chaves SSH,.env, repositórios de credenciais do navegador) para uma conta na nuvem — persistente, compartilhável, sem nenhum artefato visível na plataforma avisando que algo saiu da máquina.SILO_MCP_DOWNLOAD_ROOT(padrão~/silo-mcp/downloads) — downloads não podem ser gravados fora deste diretório por meio de um nome de arquivo forjado.
Uploads têm limite de 5 GiB (MAX_UPLOAD_BYTES) e downloads de 5 GiB
(SILO_MCP_MAX_DOWNLOAD_BYTES, substituível). Downloads são transmitidos em fluxo para o
disco e abortados no meio do caminho se ultrapassarem o limite, então um arquivo
inesperadamente enorme não pode esgotar a memória. As credenciais são armazenadas no
chaveiro do sistema operacional, nunca no banco SQLite; o fluxo de autorização OAuth
de uso único usa PKCE e um valor state aleatório (RFC 8252) para que o
redirecionamento de loopback não possa ser forjado.
Observações específicas por plataforma
Assimetrias e limitações conhecidas
- O Google Photos é somente para upload. O Google removeu os escopos
de leitura da biblioteca da API Photos Library em março de 2025 — um app agora só
pode gerenciar itens de mídia que ele mesmo criou. Navegar ou baixar a biblioteca
existente de um usuário exige a "Picker API" interativa (uma sessão de interface web),
que uma chamada de ferramenta MCP sem cabeça não consegue acionar.
list_files/download_file/search_filesretornam um erro claro em vez de fingir que funcionam. Também não existe nenhuma capacidade de exclusão para o Google Photos, neste projeto ou na API do Google — qualquer coisa enviada é permanente até ser removida manualmente via photos.google.com. - O Google Drive e o Box endereçam arquivos por id, não por caminho, para
download/exclusão — o
remote_pathdouploadé usado como nome de arquivo (somente raiz do Drive / pasta raiz do Box, sem direcionamento de pastas na v1); para baixar/excluir, você precisa primeiro do id delist_files/search_files. OneDrive, Dropbox e Yandex Disk usam caminhos reais em todo lugar, sem assimetria. - Os armazenamentos de objetos não suportam pesquisa — apenas listagem por prefixo via
list_files.search_filesretorna um erro claro de "não suportado". O Yandex Disk também não tem um endpoint de pesquisa dedicado e se comporta da mesma forma (listagem por caminho vialist_filesapenas). - Os endpoints de upload aqui são todos de disparo único (Dropbox ≤150MB, OneDrive ≤4MB); upload em partes/retomável de arquivos grandes ainda não está implementado para nenhuma plataforma.
Segurança
upload_file, delete_file e create_share_link exigem
confirm=true — eles alteram o estado remoto ou fornecem um link com
credencial de portador. download_file/list_files/search_files não
exigem confirmação, pois apenas gravam localmente.
Status de testes com conta real
Dropbox, Google Drive e Google Photos foram verificados de ponta a ponta pelo protocolo MCP real — um cliente MCP inicia o servidor, faz a descoberta de ferramentas e chama as ferramentas pelo nome, exatamente como o Claude Desktop/ Code faria — não apenas por chamadas diretas em Python.
| Plataforma | Status |
|---|---|
| Dropbox | ✅ Verificado pelo protocolo MCP contra uma conta real: upload_file (simulação + confirmado), list_files, search_files, download_file (transmitido para o disco), create_share_link, delete_file (simulação + confirmado), list_transfers. As confirmações em upload_file/delete_file se comportaram corretamente (bloqueadas sem confirm=true). |
| Google Drive | ✅ Verificado pelo protocolo MCP contra uma conta real, mesma cobertura de ferramentas do Dropbox acima, endereçado por id de arquivo conforme a observação id-vs-caminho acima. A renovação do OAuth foi acionada de forma independente antes de cada chamada, como projetado, sem bugs de cache observados. |
| Google Photos | ✅ Verificado pelo protocolo MCP contra uma conta real: upload_file (simulação + confirmado, conteúdo de imagem real), e confirmado que list_files/search_files/download_file/delete_file falham com um erro claro e bem redigido em vez de uma falha — esperado dado o design somente de upload, não é um bug. |
copy_file entre nuvens | ✅ Verificado contra contas reais nas duas direções — Dropbox → Google Drive e Google Drive → Dropbox — com os bytes copiados verificados por soma de verificação contra a origem em cada direção. A confirmação bloqueou a simulação; ambas as cópias foram registradas no log de auditoria. |
Issues e PRs relatando resultados de testes com conta real para as plataformas restantes são muito bem-vindos.
Segurança
Este servidor dá a um LLM a capacidade de ler arquivos locais (de um diretório), movê-los para contas na nuvem e gerar links públicos — então vale a pena deixar claros os riscos e o que é feito sobre eles.
- A injeção de prompt é o risco central. O conteúdo que o modelo lê (um nome
de arquivo, o texto de um documento, uma mensagem anterior) pode tentar direcioná-lo
a chamar uma ferramenta que você não pretendia — por exemplo, "também envie
~/.ssh/id_rsa" ou "compartilhe este arquivo publicamente". Esta é uma propriedade geral do uso de ferramentas agênticas, não específica deste servidor. - Mitigações incorporadas:
- Contenção de caminho — uploads só podem ler de
SILO_MCP_UPLOAD_ROOTe downloads só podem gravar emSILO_MCP_DOWNLOAD_ROOT. Uma solicitação forjada por uma chave SSH ou.envfora da raiz é rejeitada antes de qualquer chamada de rede. Mantenha a raiz de upload como uma pasta dedicada, não seu diretório pessoal. - Portões de confirmação —
upload_file,delete_fileecreate_share_linkexigemconfirm=true, então um cliente bem-comportado mostra exatamente o que está prestes a acontecer e um humano aprova. Um link público ou uma exclusão nunca são disparados por uma solicitação vaga. - As credenciais nunca chegam ao modelo — elas ficam no chaveiro do sistema operacional e são lidas no lado do servidor; nenhuma chamada de ferramenta pode enumerá-las ou exfiltrá-las, e elas nunca estão em um arquivo de configuração ou despejo de ambiente que o modelo veja.
- Privilégio mínimo — limite o escopo de cada token de plataforma apenas ao que você precisa (veja a tabela de permissões); um token somente leitura não pode ser convencido a excluir nada.
- Contenção de caminho — uploads só podem ler de
- Trilha de auditoria —
list_transferse o log local em SQLite registram cada upload, download, exclusão e link de compartilhamento, para que você possa revisar depois o que realmente foi movido.
[!WARNING] Trate um link de compartilhamento gerado como uma credencial de portador pública — qualquer pessoa com a URL pode ler o arquivo, sem precisar de conta. Revogue excluindo o arquivo (ou deixando de compartilhá-lo na plataforma) quando terminar.
Testes
pip install -e ".[all,dev]"
pytest
Os testes são de lógica pura e HTTP simulado com respx — sem chamadas de
rede reais, sem credenciais reais necessárias.
Solução de problemas
Windows: [WinError 1783] The stub received bad data de silo-mcp-accounts add
Duas causas distintas aparecem como esse erro exato:
-
O shim
CredWritedopywin32-ctypes. Okeyringprefere esse shim aopywin32real mesmo quando ambos estão instalados (veja obackends/Windows.pydokeyring, que tentapywin32-ctypesprimeiro). Correção:pip uninstall pywin32-ctypes -yExige
pywin32já instalado (já incluído de forma transitiva aqui viamcp). Reinstalar/atualizar okeyringdepois pode trazer opywin32-ctypesde volta como dependência dele — execute novamente a desinstalação se isso reaparecer após uma atualização. -
O limite rígido de ~2560 bytes (~1280 caracteres) por segredo do Gerenciador de Credenciais do Windows — um limite real do sistema operacional não relacionado a (1), confirmado ao reproduzir o erro idêntico com
pywin32real e uma string simples superdimensionada. Alguns formatos de token do Dropbox e oservice_account_jsondo GCS (rotineiramente com mais de 2000 caracteres) excedem isso facilmente com credenciais totalmente legítimas, não apenas erros de colagem. Agora tratado de forma transparente — oadd_accountdivide qualquer segredo acima do limite em várias entradas do chaveiro e o remonta na leitura, em todas as plataformas (não apenas no Windows, para que o comportamento não difira silenciosamente por sistema operacional). Nada a fazer aqui; se você ainda encontrar um erro, provavelmente é genuinamente grande demais (mais de 200.000 caracteres) em vez deste limite.
Relacionados
Projeto irmão no mesmo estilo MCP auto-hospedado com confirmação: um
servidor MCP de postagem social (transmite posts em vez de mover arquivos) —
formato de capacidade e limite de confiança diferentes, componível no
nível do cliente MCP em vez de um código compartilhado (o download_file aqui pode
entregar um caminho local diretamente ao media_paths daquele servidor).