SILO-MCP

Servidor MCP que mueve archivos entre tu sistema de archivos y el almacenamiento en la nube.

Documentación

Silo MCP

License: MIT tests Python 3.11+ MCP

Un servidor MCP autoalojado que mueve archivos entre tu sistema de archivos y el almacenamiento en la nube: nueve plataformas, una única superficie de herramientas. Sube, descarga, lista, busca, elimina, genera enlaces de uso compartido y copia archivos directamente de una nube a otra, sin darle a un LLM acceso directo al sistema de archivos ni un montón de credenciales específicas de cada plataforma que gestionar.

No es "local-first": los archivos viven en la nube y cada operación habla con una API remota del proveedor. Lo que permanece local es la parte que importa para la confianza: el servidor se ejecuta como un subproceso en tu máquina, tus credenciales están en el llavero del sistema operativo (nunca en la nube, en un archivo de configuración o en un argumento de llamada de herramienta), y el registro de auditoría de transferencias es un archivo SQLite local.

Almacenes de documentos: Dropbox · Google Drive · OneDrive · Box · Google Photos (solo subida) · Yandex Disk Almacenes de objetos: compatible con S3 (AWS S3, Cloudflare R2, MinIO) · Google Cloud Storage · Azure Blob Storage

¿Qué puedes hacer con Silo MCP?

  • Copiar un archivo directamente de una nube a otra — "copia mi archivo /photos de Dropbox a mi bucket de S3", "migra este archivo de Drive a OneDrive" — en una sola llamada de herramienta, sin descargar y luego subir manualmente. Lo único que una integración de almacenamiento de un solo proveedor estructuralmente no puede hacer.
  • Mover archivos dentro y fuera del almacenamiento en la nube — "sube report.pdf a Dropbox", "descarga notes.txt de Google Drive para poder usarlo" — en las nueve plataformas con un mismo conjunto de herramientas.
  • Explorar y buscar tus almacenes de documentos por carpeta o consulta, y listar los buckets de almacenes de objetos por prefijo de clave.
  • Generar enlaces compartibles a un archivo: URL prefirmadas/firmadas en los almacenes de objetos y Box (con caducidad), enlaces de uso compartido de la plataforma en el resto.
  • Puente hacia otros servidores MCP — un download_file aquí produce una ruta local que puedes pasar directamente a otro servidor (por ejemplo, el media_paths de un servidor de publicación en redes sociales).
  • Mantener un registro de auditoría local — cada subida, descarga, eliminación y enlace de uso compartido se registra en un registro SQLite local que puedes consultar con list_transfers.

Todo se ejecuta a través de tu cliente MCP en lenguaje natural — consulta Ejemplos de flujos de trabajo.

Inicio rápido: pip install -e . → añade silo-mcp a la configuración de tu cliente MCP → silo-mcp-accounts add dropbox --label personal → pide a tu cliente que liste tus archivos de Dropbox. Pasos completos en Instalación y Añadir cuentas a continuación.

Contenido

Por qué

La mayoría de las configuraciones de "dale al LLM tu almacenamiento en la nube" caen en una de dos trampas: una integración de una sola plataforma que muere en cuanto cambias de proveedor, o un acceso local sin restricciones que permite que una conversación manipulada lea o suba cualquier cosa del disco. Silo MCP está construido contra ambas:

  • Una superficie de herramientas, nueve plataformas. upload_file, download_file, list_files, search_files, delete_file, create_share_link se comportan igual independientemente de la plataforma a la que apuntes: los almacenes de objetos (bucket+clave) y los almacenes de documentos (basados en rutas) comparten un único contrato FileStore.
  • Confinado por diseño, no por convención. local_path para subidas y el destino de las descargas son ambos argumentos de llamada de herramienta proporcionados por el LLM, por lo que ambos están estrictamente confinados a directorios raíz configurados: una conversación manipulada no puede pedirle a este servidor que lea una clave SSH ni escribir una descarga donde no debería.
  • Las mutaciones requieren confirm=true. upload_file, delete_file y create_share_link mutan estado remoto o crean un enlace con credencial de portador y requieren confirmación deliberada. download_file/list_files/search_files solo escriben localmente, así que no requieren confirmación.
  • Multi-cuenta desde el principio. Cada herramienta acepta una etiqueta account opcional: ejecuta un Dropbox de trabajo y un Dropbox personal lado a lado sin reconfigurar nada.

Arquitectura

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 llamada de herramienta resuelve un par (platform, account) a una implementación FileStore y una credencial de accounts.py, comprueba cualquier ruta local contra las raíces de subida/descarga, ejecuta contra la API real de la plataforma y registra el resultado: la misma forma independientemente de cuál de los nueve backends esté al otro lado.

Requisitos

  • Python 3.11+
  • Un almacén de credenciales del sistema operativo que keyring pueda usar (Administrador de credenciales de Windows, Llavero de macOS o un proveedor de Secret Service en Linux): las credenciales nunca se escriben en disco en texto plano ni se pasan a través de una llamada de herramienta MCP.

Instalación

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 .

Los SDK de almacenes de objetos son extras opcionales: instala solo lo que necesites:

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

Una instalación básica (sin extras) cubre Dropbox/Drive/OneDrive/Box/Google Photos/Yandex Disk sin más dependencia que httpx: el servidor degrada con elegancia si un SDK de almacén de objetos no está instalado, en lugar de fallar al iniciar.

Configurar tu cliente MCP

Añade a la configuración MCP de tu cliente (por ejemplo, claude_desktop_config.json de Claude Desktop, o .mcp.json de Claude Code):

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

silo-mcp debe resolverse en PATH dentro del entorno desde el que tu cliente lanza el servidor: si instalaste en un virtualenv, apunta command al ejecutable silo-mcp de ese venv directamente (por ejemplo, /path/to/silo-mcp/.venv/bin/silo-mcp) en lugar de depender de la activación del shell.

Opciones de transporte (stdio por defecto, HTTP para clientes de red)

Por defecto usa stdio, que es lo que todo cliente MCP de escritorio (Claude Desktop, Claude Code, Cursor, etc.) lanza como subproceso: no se abre ningún puerto de red. Para un cliente que no puede lanzar un subproceso local y necesita alcanzar el servidor por HTTP (consulta Uso con Ollama a continuación), configura:

SILO_MCP_TRANSPORT=streamable-http SILO_MCP_HOST=127.0.0.1 SILO_MCP_PORT=8000 silo-mcp

SILO_MCP_TRANSPORT también acepta sse (el transporte HTTP más antiguo, mantenido para clientes que aún no han migrado a streamable-http). SILO_MCP_HOST/SILO_MCP_PORT solo se leen para los dos transportes HTTP y por defecto son 127.0.0.1:8000.

[!WARNING] Este servidor no tiene autenticación integrada para el modo HTTP: no lo vincules a 0.0.0.0 ni lo expongas más allá de localhost sin poner un proxy inverso con autenticación delante, ya que cada llamada de herramienta llega a tus cuentas de almacenamiento en la nube.

Clientes compatibles

Cualquier cliente MCP que pueda lanzar un servidor stdio local funciona: el servidor usa solo llamadas de herramienta MCP estándar, sin características específicas de cliente. Clientes verificados y con funcionamiento esperado:

ClienteConfiguraciónNotas
Claude Code.mcp.json en el proyecto ({"mcpServers":{"silo-mcp":{"command":"silo-mcp"}}})Verificado de extremo a extremo sobre el protocolo MCP.
Claude Desktopclaude_desktop_config.json — mismo bloque mcpServersstdio.
Cursor / VS Code (MCP)Su mcp.json — mismo bloque mcpServersstdio.
Ollama (a través de un puente)Apunta el puente al transporte HTTPConsulta Uso con Ollama.

[!TIP] Si silo-mcp no está en el PATH del shell que lanza (común con virtualenvs), configura command al ejecutable del venv directamente, por ejemplo C:\\path\\to\\silo-mcp\\.venv\\Scripts\\silo-mcp.exe en Windows o /path/to/.venv/bin/silo-mcp en otros sistemas.

Uso con Ollama

Ollama no habla MCP de forma nativa: necesita un cliente MCP en el bucle que convierta la llamada a herramientas de Ollama en llamadas de herramienta MCP, el mismo papel que Claude Desktop/Code juegan para Claude. Este servidor no incluye ese puente (se mantiene fuera del alcance para seguir siendo un paquete de servidor simple), pero cualquier cliente Ollama compatible con MCP funciona una vez que lo apuntas a streamable-http en lugar de stdio:

  1. Inicia el servidor en modo HTTP: SILO_MCP_TRANSPORT=streamable-http silo-mcp.
  2. Apunta tu cliente MCP del lado de Ollama a http://127.0.0.1:8000/mcp.
  3. Usa un modelo con capacidad de llamada a herramientas (por ejemplo, llama3.1, qwen2.5): Ollama solo enruta llamadas a herramientas para modelos que admiten el campo de API tools.

Añadir cuentas

Las credenciales se añaden mediante una CLI con entrada oculta, nunca a través de una llamada de herramienta MCP, y se almacenan en el almacén de credenciales de tu sistema operativo:

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
Configuración OAuth por primera vez (Drive, Photos, OneDrive, Box)

Estas cuatro plataformas necesitan un refresh_token antes de que silo-mcp-accounts add las acepte — y obtener el primero requiere una autorización de navegador única, no solo un par client_id/secret. Registra una aplicación en la consola de desarrollador de cada plataforma y luego ejecuta:

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

Esto abre tu navegador a la pantalla de consentimiento de la plataforma, escucha en http://localhost:8765/callback para la redirección, intercambia el código por un refresh_token y almacena la cuenta: no necesitas ejecutar add después.

Registro de aplicaciones, por plataforma:

  • Google (Drive + Photos comparten una aplicación): https://console.cloud.google.com → nuevo proyecto → APIs & Services → habilita la Google Drive API y la Photos Library API → pantalla de consentimiento OAuth (External es suficiente para pruebas personales, añádate como usuario de prueba) → Credentials → Create OAuth client ID → tipo Desktop app. Los clientes de aplicación de escritorio aceptan cualquier redirección http://localhost:<port> sin pre-registrarla, así que no se necesita configuración de URI de redirección.
  • OneDrive: Azure Portal → App registrations → New registration → plataforma Mobile and desktop applications → añade la URI de redirección http://localhost:8765/callback exactamente (Azure requiere coincidencia exacta). API permissions → Microsoft Graph → añade Files.ReadWrite y offline_access (delegadas). Certificates & secrets → nuevo client secret.
  • Box: Box Developer Console → Create new app → Custom AppUser Authentication (OAuth 2.0) → en Configuration, establece Redirect URI a http://localhost:8765/callback exactamente (Box también requiere coincidencia exacta) y marca los scopes que necesites (Read/write files).

Si usas --port para elegir un puerto local diferente, usa ese mismo puerto en la URI de redirección que registres.

Obtener un token de Yandex Disk

Yandex Disk usa un token estático como Dropbox: no tiene refresh_token, así que no forma parte del flujo de arranque silo-mcp-accounts oauth anterior. Su configuración de aplicación OAuth usa una concesión implícita: el token vuelve directamente en el navegador, sin paso de intercambio de código que scriptear.

  1. oauth.yandex.comCreate app (o reutiliza una existente).
  2. En Platforms, marca Web services y establece la URI de redirección a https://oauth.yandex.com/verification_code — la página integrada de Yandex que simplemente muestra el token, sin necesidad de listener local para esta.
  3. En Permissions, concede acceso a Disk: cloud_api:disk.read y cloud_api:disk.write (o cloud_api:disk.app_folder en lugar de disk.write si quieres limitarlo a una carpeta específica de la aplicación en lugar de todo el disco).
  4. Guarda la aplicación y anota su ID.
  5. Visita https://oauth.yandex.com/authorize?response_type=token&client_id=<your-app-id> en un navegador, aprueba el acceso: el token se muestra directamente en la página redirigida.
  6. silo-mcp-accounts add yandex_disk --label personal, pega el token.
Configuración masiva más rápida: importar archivo o variables de entorno

Ejecutar add una vez por plataforma se vuelve tedioso rápido cuando configuras varias a la vez. Dos rutas más rápidas — ambas terminan igualmente en el llavero del sistema operativo, nunca en un archivo o variable de entorno que este proyecto persista por sí mismo:

Archivo de importación — copia la plantilla, completa los valores reales, importa de una sola vez. silo-accounts.example.yaml en la raíz del repositorio tiene una entrada para las nueve plataformas con los nombres de campo exactos que cada una necesita y un comentario sobre dónde obtener 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 también funciona (misma forma platform -> label -> fields), se detecta por la extensión del archivo — cualquier cosa que no termine en .json se analiza como YAML.

silo-accounts.yaml/.json, credentials.yaml/.json, y cualquier *.local.yaml/.json ya están en .gitignore, pero trátalo como un respaldo, no como el plan — elimina el archivo inmediatamente después de importarlo. Son secretos en texto plano en el disco mientras exista, esté en gitignore o no.

Variables de entorno — para configuración mediante scripts o CI donde un archivo no es práctico, add lee SILO_MCP_CRED_<PLATFORM>_<FIELD> antes de solicitar entrada:

SILO_MCP_CRED_DROPBOX_ACCESS_TOKEN=sl.xxx silo-mcp-accounts add dropbox --label personal

Las variables de entorno están más expuestas que un archivo que eliminas (listados de procesos, historial de shell, volcados de memoria) — prefiere el archivo de importación para cualquier cosa más allá de una configuración rápida de pruebas automatizadas.

Flujos de trabajo de ejemplo

Una vez que el servidor está conectado, no llamas a las herramientas directamente — le pides a tu cliente MCP (Claude Desktop, Claude Code, etc.) en lenguaje natural y él elige la herramienta y los argumentos correctos. Estos ejemplos se probaron de extremo a extremo sobre el protocolo MCP real contra cuentas en vivo de Dropbox, Google Drive y Google Photos.

Dropbox / OneDrive / Yandex Disk (rutas reales):

  • "Sube report.pdf desde mi carpeta de subidas a Dropbox."
  • "¿Qué hay en la raíz de mi Dropbox? Encuentra cualquier cosa llamada invoice."
  • "Descarga notes.txt de Dropbox y dame un enlace compartible."
  • "Elimina old-draft.txt de mi Dropbox."

Google Drive / Box (direccionado por id — busca primero, luego actúa sobre el id):

  • "Encuentra budget.xlsx en mi Google Drive." → luego "Descarga ese."
  • "Comparte ese archivo con un enlace público."

Google Photos (solo subida):

  • "Sube esta captura de pantalla a mi Google Photos."

Almacenes de objetos — S3 / GCS / Azure Blob (necesitan un bucket/contenedor):

  • "Sube backup.zip a mi bucket S3 my-backups."
  • "Lista todo lo que esté bajo logs/ en el bucket my-backups."
  • "Dame un enlace prefirmado de 1 hora para backup.zip en my-backups."

Copia entre nubes (de una plataforma directamente a otra):

  • "Copia report.pdf de mi Dropbox a mi Google Drive."
  • "Migra todo lo que acabo de encontrar en Drive a mi bucket S3 archive."

Entre servidores:

  • "Toma mi foto de perfil de Google Drive para adjuntarla a una publicación." — download_file entrega una ruta local que otro servidor MCP puede usar.

El mapeo completo de frases a llamadas de herramientas:

Tú dicesQué se ejecuta
"¿Qué almacenamiento en la nube puedo usar aquí y qué cuentas están configuradas?"list_supported_stores
"Sube report.pdf desde mi carpeta de subidas a Dropbox."upload_file(dropbox, …, confirm=true) — el cliente establece confirm después de que aceptes
"¿Qué hay en la raíz de mi Dropbox?"list_files(dropbox)
"Encuentra archivos llamados invoice en mi Dropbox."search_files(dropbox, "invoice")
"Descarga notes.txt de Dropbox para poder usarlo."download_file(dropbox, "/notes.txt")
"Dame un enlace compartible para ese archivo."create_share_link(dropbox, …, confirm=true)
"Elimina old-draft.txt de Dropbox."delete_file(dropbox, "/old-draft.txt", confirm=true)
"Pon esta imagen en mi Google Photos."upload_file(google_photos, …, confirm=true)
"Copia mi currículum de Dropbox a un borrador de tweet."download_file aquí → pasa la ruta local al media_paths de otro servidor MCP
"Muéstrame lo que he movido recientemente."list_transfers

Debido a que Google Drive y Box direccionan archivos por id, un flujo natural allí es de dos pasos — "encuentra budget.xlsx en mi Drive" (search_files, devuelve el id), luego "descarga ese" / "comparte ese" usando el id que el cliente acaba de ver. El cliente maneja esa cadena por ti.

Las acciones mutadoras (upload_file, delete_file, create_share_link) requieren confirm=true, así que un buen cliente te mostrará exactamente lo que está a punto de hacer y solo continuará cuando lo apruebes — una eliminación o un enlace público nunca ocurren en silencio a partir de una solicitud vaga.

Herramientas

HerramientaPuerta de confirmaciónDescripción
list_supported_stores()Cada plataforma conocida, su tipo (documento vs. almacén de objetos), capacidades y cuentas configuradas.
list_accounts(platform)Cuentas configuradas, opcionalmente filtradas.
upload_file(platform, local_path, remote_path, account, target, confirm)local_path debe estar dentro de la raíz de subida.
download_file(platform, remote_path, local_filename, account, target)Escribe en la raíz de descarga y devuelve la ruta local.
list_files(platform, folder_or_prefix, account, target)Listado de carpetas (almacenes de documentos) o listado por prefijo (almacenes de objetos).
search_files(platform, query, account, target)Indica errores claramente donde la plataforma no admite búsqueda.
delete_file(platform, remote_path, account, target, confirm)
create_share_link(platform, remote_path, account, target, expires_in_seconds, confirm)Un enlace que cualquiera puede usar para leer el archivo sin cuenta, donde se admita. Ver Enlaces compartibles.
copy_file(from_platform, from_remote_path, to_platform, to_remote_path, from_account, to_account, from_target, to_target, confirm)Copia un archivo directamente de una nube a otra. Ver Copia entre nubes.
list_transfers(platform, limit)Registro de auditoría local de subidas, descargas, eliminaciones, enlaces compartibles y copias entre nubes.
get_client_capabilities(platform)Verifica qué admite una plataforma antes de llamarla.

target es el nombre del bucket/contenedor para almacenes de objetos — se ignora para almacenes de documentos.

Enlaces compartibles

expires_in_seconds se respeta de forma nativa en S3, GCS, Azure Blob y Box (URLs prefirmadas/firmadas, o el unshared_at de Box). Dropbox, Google Drive, OneDrive y Yandex Disk también crean un enlace, pero ninguna de sus APIs admite caducidad en una cuenta personal/no Business, así que el parámetro se acepta por consistencia de interfaz pero no se aplica allí. No disponible en Google Photos (solo subida).

Protegido detrás de confirm=true aunque no mueve ni elimina datos — la URL devuelta es en sí misma una credencial de portador, la misma preocupación de exfiltración que tiene upload_file.

Copia entre nubes

copy_file mueve un archivo directamente de una plataforma a otra — "copia mi /photos/id.png de Dropbox a mi bucket S3 backups", "migra este archivo de Drive a OneDrive" — en una sola llamada de herramienta. Esto es lo único que una integración de almacenamiento de un solo proveedor estructuralmente no puede hacer; es la recompensa de poner cada backend detrás de una sola interfaz.

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

El LLM nunca toca los bytes del archivo ni una ruta intermedia — solo emite una llamada copy_file y el servidor maneja la descarga → temporal → subida → limpieza, condicionada a tu aprobación.

  • Se transmite a través de un archivo local temporal que el servidor crea y elimina — nunca manejas una descarga/subida intermedia, y la ruta temporal nunca es un argumento proporcionado por el llamador (por lo que no está sujeta a la verificación de contención de la raíz de subida como lo está upload_file).
  • from_remote_path se direcciona como la plataforma origen espera para una descarga (una ruta para Dropbox/OneDrive/Yandex/almacenes de objetos; un id de archivo para Google Drive/Box — busca primero para obtenerlo). to_remote_path toma por defecto el nombre base del origen; pásalo explícitamente cuando el origen esté direccionado por id.
  • from_target/to_target son los nombres de bucket/contenedor cuando cualquiera de los extremos es un almacén de objetos.
  • Requiere confirm=true — escribe en el destino. Se registra en el registro de auditoría como copy, con ambos extremos capturados.

[!NOTE] La copia está limitada por los mismos topes de 5 GiB de descarga/subida, y la descarga del origen se transmite al disco, así que una copia grande entre nubes no almacenará todo el archivo en memoria.

Plataformas admitidas y herramientas

Qué operaciones admite cada plataforma y su modelo de autenticación. ✅ admitido · — no admitido. target = el nombre del bucket/contenedor que los almacenes de objetos requieren.

PlataformaTipoSubidaDescargaListarBuscarEliminarEnlace compartibleAutenticación
DropboxdocumentoToken estático
Google DrivedocumentoRefresco OAuth2
OneDrivedocumentoRefresco OAuth2
Boxdocumento✅ (con caducidad)Refresco OAuth2
Google PhotosdocumentoRefresco OAuth2
Yandex DiskdocumentoToken estático
S3-compatibleobjeto (necesita target)✅ (prefirmado)Clave/secreto estático
Google Cloud Storageobjeto (necesita target)✅ (firmado)JSON de cuenta de servicio
Azure Blobobjeto (necesita target)✅ (SAS)Cadena de conexión

[!NOTE] Google Photos es solo subida — Google eliminó el acceso a la API de lectura de biblioteca en marzo de 2025. Los almacenes de objetos y Yandex Disk no tienen búsqueda de contenido, solo listado por prefijo/ruta. Detalles en Notas específicas por plataforma.

Fricción de configuración y forma de credenciales por plataforma

Tabla de formas de credenciales
PlataformaCredencialModelo de autenticaciónConfiguración
Dropboxaccess_tokenToken estáticoConsola de la aplicación → generar token. Sin baile de refresco. Ver alcances abajo — un error missing_scope significa regenerar, no reconfigurar.
Yandex Diskaccess_tokenToken estático, concesión implícita (sin paso de intercambio de código)Ver Cómo obtener un token de Yandex Disk arriba.
Azure Blobconnection_stringEstáticoCuenta de almacenamiento → Claves de acceso. El más simple de los almacenes de objetos.
S3access_key_id, secret_access_key, region/endpoint_url opcionalEstáticoUsuario IAM de AWS, o credenciales R2/MinIO + endpoint_url.
GCSservice_account_jsonJWT (cuenta de servicio)Consola de Google Cloud → crea una clave de cuenta de servicio, pega todo el JSON.
Google Driveclient_id, client_secret, refresh_tokenOAuth2, refrescado en cada llamadaPantalla de consentimiento OAuth de Google Cloud + una autorización única para obtener el token de refresco inicial.
Google Photosigual que DriveOAuth2, alcance photoslibrary.appendonlyMisma aplicación de Google Cloud; solo subida, ver abajo.
OneDriveclient_id, client_secret, refresh_tokenOAuth2, refrescado en cada llamadaRegistro de aplicación en Azure AD.
Boxclient_id, client_secret, refresh_tokenOAuth2, refrescado en cada llamada, el token rotaAplicación de desarrollador de Box. Cada refresco emite un nuevo token de refresco automáticamente y este servidor lo persiste de vuelta al llavero — no reutilices uno antiguo manualmente.

Dropbox, Yandex Disk, S3, GCS y Azure Blob usan credenciales estáticas leídas una vez. Google Drive, OneDrive, Box y Google Photos son todas OAuth2 de grandes empresas tecnológicas con tokens de acceso de corta duración (~1h) — este servidor llama al endpoint de token de cada plataforma de nuevo antes de cada solicitud de API en lugar de almacenar en caché, manteniendo la historia de corrección simple a costa de una solicitud extra rápida (~200ms) por llamada.

Permisos/alcances requeridos por plataforma

Los campos de credenciales anteriores solo te dan un token — el token también necesita el alcance correcto, o cada llamada fallará con un error de permisos sin importar cuán correctamente esté almacenado. Se configura en el lado de la plataforma, no aquí:

PlataformaÁmbitos requeridosDónde configurarlos
Dropboxfiles.content.write, files.content.read, files.metadata.read, sharing.write (para create_share_link)Consola de la aplicación → pestaña Permisos → marcar los ámbitos → hacer clic en Enviar. Los ámbitos se fijan en el momento de emitir el token: debes generar un token nuevo después de cambiar los ámbitos; un token ya emitido no los adquiere retroactivamente.
Yandex DiskAcceso completo al disco (lectura/escritura)Configuración de la aplicación en oauth.yandex.com → marcar el permiso de lectura/escritura del disco al crear la aplicación, antes de emitir el token.
Google Drivehttps://www.googleapis.com/auth/driveSolicitado automáticamente por silo-mcp-accounts oauth google_drive — no hay nada que configurar manualmente más allá de habilitar la API de Drive en el proyecto.
Google Photoshttps://www.googleapis.com/auth/photoslibrary.appendonlyIgual que arriba, mediante silo-mcp-accounts oauth google_photos; habilitar la API de Photos Library en el proyecto.
OneDriveFiles.ReadWrite, offline_access (delegado)Azure Portal → registro de la aplicación → Permisos de API → Microsoft Graph → agregar ambos, luego Conceder consentimiento de administrador si tu inquilino lo requiere. También se solicita automáticamente mediante silo-mcp-accounts oauth onedrive.
Box"Leer y escribir todos los archivos y carpetas almacenados en Box" (o más restringido, según lo que necesites)Consola de desarrollador → aplicación → pestaña ConfiguraciónÁmbitos de la aplicación.
S3s3:GetObject, s3:PutObject, s3:ListBucket, s3:DeleteObject en el bucket de destino (además, la generación de URL prefirmadas no requiere permiso adicional — es una operación de firma local)Política de IAM adjunta al usuario/rol cuyas access_key_id/secret_access_key estás usando.
GCSStorage Object Admin (o Object Viewer + Object Creator para una concesión más restringida) en el bucket/proyectoIAM & Admin → otorgar el rol a la cuenta de servicio antes de generar su clave.
Azure BlobAcceso completo a la cuenta mediante la clave de cuenta de la cadena de conexión — no existe un concepto de ámbito separadoN/A — la propia cadena de conexión es el límite de permisos; usa una cadena de conexión restringida por SAS si quieres limitarla.

[!TIP] Dropbox es el que más probablemente te muerda: un 401 missing_scope con un token por lo demás correcto casi siempre significa que los ámbitos se cambiaron después de generar el token. Regenera el token, no solo lo vuelvas a guardar.

Seguridad de rutas

local_path para subidas y el nombre de archivo de destino para descargas son argumentos de llamada a herramientas proporcionados por el LLM, por lo que ambos se limitan a una raíz configurada cada uno, en ambas direcciones:

  • SILO_MCP_UPLOAD_ROOT (por defecto ~/silo-mcp/uploads) — los archivos fuera de este directorio no se pueden subir. Esto importa mucho aquí: sin ello, una conversación manipulada podría pedir al servidor que suba un archivo local arbitrario (claves SSH, .env, almacenes de credenciales del navegador) a una cuenta en la nube — persistente, compartible, sin ningún artefacto visible en la plataforma que advierta a alguien de que algo salió de la máquina.
  • SILO_MCP_DOWNLOAD_ROOT (por defecto ~/silo-mcp/downloads) — las descargas no se pueden escribir fuera de este directorio mediante un nombre de archivo manipulado.

Las subidas están limitadas a 5 GiB (MAX_UPLOAD_BYTES) y las descargas a 5 GiB (SILO_MCP_MAX_DOWNLOAD_BYTES, sobreescribible). Las descargas se transmiten a disco y se abortan a mitad de camino si superan el límite, de modo que un archivo inesperadamente grande no pueda agotar la memoria. Las credenciales se almacenan en el llavero del sistema operativo, nunca en la base de datos SQLite; el flujo de autorización OAuth de una sola vez usa PKCE y un valor state aleatorio (RFC 8252) para que la redirección de bucle local no pueda ser falsificada.

Notas específicas de la plataforma

Asimetrías y limitaciones conocidas
  • Google Photos es solo de subida. Google eliminó los ámbitos de lectura de la biblioteca de la API de Photos Library en marzo de 2025 — una aplicación ahora solo puede gestionar elementos multimedia que ella misma haya creado. Navegar o descargar la biblioteca existente de un usuario requiere la "Picker API" interactiva (una sesión de interfaz web), que una llamada de herramienta MCP sin interfaz no puede manejar. list_files/download_file/ search_files devuelven un error claro en lugar de fingir que funcionan. Tampoco hay ninguna capacidad de eliminación para Google Photos, ni en este proyecto ni en la API de Google — cualquier cosa subida es permanente hasta que se elimine manualmente a través de photos.google.com.
  • Google Drive y Box direccionan archivos por id, no por ruta, para descarga/eliminación — el upload de remote_path se usa como nombre de archivo (solo raíz de Drive / raíz de Box, sin direccionamiento de carpetas en v1); para descargar/eliminar necesitas el id de list_files/search_files primero. OneDrive, Dropbox y Yandex Disk usan rutas reales en todo momento, sin asimetría.
  • Los almacenes de objetos no admiten búsqueda — solo listado por prefijo mediante list_files. search_files devuelve un error claro de "no compatible". Yandex Disk tampoco tiene un endpoint de búsqueda dedicado y se comporta de la misma manera (solo listado por ruta mediante list_files).
  • Los endpoints de subida aquí son todos de una sola vez (Dropbox ≤150MB, OneDrive ≤4MB); la subida por fragmentos/reanudable para archivos grandes no está implementada en ninguna plataforma todavía.

Seguridad

upload_file, delete_file y create_share_link requieren confirm=true — o mutan el estado remoto o entregan un enlace con credencial de portador. download_file/list_files/search_files no tienen compuerta, ya que solo escriben localmente.

Estado de pruebas con cuentas reales

Dropbox, Google Drive y Google Photos se han verificado de extremo a extremo a través del protocolo MCP real — un cliente MCP inicia el servidor, realiza descubrimiento de herramientas y llama a las herramientas por nombre, exactamente como lo haría Claude Desktop/ Code — no solo mediante llamadas directas a Python.

PlataformaEstado
Dropbox✅ Verificado a través del protocolo MCP contra una cuenta real: upload_file (simulación + confirmado), list_files, search_files, download_file (transmitido a disco), create_share_link, delete_file (simulación + confirmado), list_transfers. Las compuertas de confirmación en upload_file/delete_file se comportaron correctamente (bloqueadas sin confirm=true).
Google Drive✅ Verificado a través del protocolo MCP contra una cuenta real, misma cobertura de herramientas que Dropbox arriba, direccionado por id de archivo según la nota de id-vs-ruta anterior. El refresco de OAuth se disparó de forma independiente antes de cada llamada como estaba diseñado, sin errores de caché observados.
Google Photos✅ Verificado a través del protocolo MCP contra una cuenta real: upload_file (simulación + confirmado, contenido de imagen real), y confirmado que list_files/search_files/download_file/delete_file fallan con un error claro y correctamente redactado en lugar de un bloqueo — esperado dado el diseño de solo subida, no un error.
copy_file entre nubes✅ Verificado contra cuentas reales en ambas direcciones — Dropbox → Google Drive y Google Drive → Dropbox — con los bytes copiados verificados por suma de comprobación contra el origen en cada dirección. La compuerta de confirmación bloqueó la simulación; ambas copias se registraron en el registro de auditoría.

Los problemas y PRs que informen resultados de pruebas con cuentas reales para las plataformas restantes son muy bienvenidos.

Seguridad

Este servidor da a un LLM la capacidad de leer archivos locales (de un directorio), moverlos a cuentas en la nube y generar enlaces públicos — por lo que vale la pena ser claro sobre los riesgos y lo que se hace al respecto.

  • La inyección de prompts es el riesgo central. El contenido que el modelo lee (un nombre de archivo, el texto de un documento, un mensaje anterior) puede intentar dirigirlo a llamar a una herramienta que no pretendías — por ejemplo, "también sube ~/.ssh/id_rsa" o "comparte este archivo públicamente". Esta es una propiedad general del uso de herramientas agénticas, no específica de este servidor.
  • Mitigaciones integradas:
    • Contención de rutas — las subidas solo pueden leer desde SILO_MCP_UPLOAD_ROOT y las descargas solo pueden escribir en SILO_MCP_DOWNLOAD_ROOT. Una solicitud manipulada para una clave SSH o .env fuera de la raíz se rechaza antes de cualquier llamada de red. Mantén la raíz de subida como una carpeta dedicada, no tu directorio de inicio.
    • Compuertas de confirmaciónupload_file, delete_file y create_share_link requieren confirm=true, de modo que un cliente bien comportado muestra exactamente lo que está a punto de suceder y un humano lo aprueba. Un enlace público o una eliminación nunca se disparan a partir de una solicitud vaga.
    • Las credenciales nunca llegan al modelo — viven en el llavero del sistema operativo y se leen en el lado del servidor; ninguna llamada de herramienta puede enumerarlas o exfiltrarlas, y nunca están en un archivo de configuración o volcado de entorno que el modelo vea.
    • Privilegio mínimo — limita cada token de plataforma a solo lo que necesitas (ver la tabla de permisos); un token de solo lectura no puede ser convencido de eliminar nada.
  • Registro de auditoríalist_transfers y el registro SQLite local registran cada subida, descarga, eliminación y enlace de compartir, para que puedas revisar después qué se movió realmente.

[!WARNING] Trata un enlace de compartir generado como una credencial de portador pública — cualquiera con la URL puede leer el archivo, sin necesidad de cuenta. Revócalo eliminando el archivo (o dejando de compartirlo en la plataforma) cuando hayas terminado.

Pruebas

pip install -e ".[all,dev]"
pytest

Las pruebas son de lógica pura y HTTP simulado con respx — sin llamadas de red reales, sin credenciales reales requeridas.

Solución de problemas

Windows: [WinError 1783] El stub recibió datos incorrectos de silo-mcp-accounts add

Dos causas distintas se manifiestan como este error exacto:

  1. El shim pywin32-ctypes de CredWrite. keyring prefiere este shim sobre el pywin32 real incluso cuando ambos están instalados (ver el backends/Windows.py de keyring, que intenta pywin32-ctypes primero). Solución:

    pip uninstall pywin32-ctypes -y
    

    Requiere que pywin32 ya esté instalado (ya se incluye transitivamente aquí mediante mcp). Reinstalar/actualizar keyring más tarde puede traer pywin32-ctypes de vuelta como su dependencia — vuelve a ejecutar la desinstalación si esto reaparece después de una actualización.

  2. El límite duro de ~2560 bytes (~1280 caracteres) por secreto del Administrador de credenciales de Windows — un límite real del sistema operativo no relacionado con (1), confirmado al reproducir el error idéntico con pywin32 real y una cadena sobredimensionada simple. Algunos formatos de token de Dropbox y el service_account_json de GCS (rutinariamente más de 2000 caracteres) superan esto fácilmente con credenciales completamente legítimas, no solo errores de pegado. Se maneja de forma transparente ahora — add_account divide cualquier secreto que supere el límite en múltiples entradas del llavero y lo reensambla al leer, en todas las plataformas (no solo Windows, para que el comportamiento no difiera silenciosamente por sistema operativo). No hay nada que hacer aquí; si aún encuentras un error, es probablemente demasiado grande (más de 200,000 caracteres) en lugar de este límite.

Relacionado

Proyecto hermano en el mismo estilo MCP autoalojado y con compuerta de confirmación: un servidor MCP de publicación social (publica mensajes en lugar de mover archivos) — diferente forma de capacidad y límite de confianza, componible a nivel de cliente MCP en lugar de un código base compartido (download_file aquí puede pasar una ruta local directamente al media_paths de ese servidor).

Licencia

MIT