ShieldFive
Mueve archivos fuera de tu computadora a una bóveda cifrada de extremo a extremo: cada copia se lee de vuelta y se verifica antes de que el original vaya a una carpeta de papelera local, sin eliminar nada. También encuentra duplicados y ordena carpetas. Descifra en tu máquina; acceso limitado y revocable.
Documentación
@shieldfive/mcp
Un servidor de Model Context Protocol que permite que Claude, ChatGPT, Cursor o un modelo local trabajen con dos cosas:
- tu bóveda de ShieldFive, cifrada de extremo a extremo: mueve archivos de tu computadora a ella — cada uno cifrado aquí, subido, leído de vuelta y comparado byte por byte antes de que su original se mueva a una carpeta local de papelera, nunca eliminado — y encuentra duplicados, ve qué ocupa espacio, renombra, mueve y mueve a la Papelera. Funciona en las carpetas que concedes, descifra en tu máquina, y cada cambio se puede deshacer;
- carpetas en tu propio disco: los mismos trabajos de ordenamiento, sin acceso a la red en absoluto.
Los servidores de ShieldFive nunca ven un nombre de archivo ni un byte de contenido en claro, y eso se mantiene también con este servidor en ejecución. El descifrado ocurre dentro de este proceso, en tu computadora. Lo que el asistente haga luego con lo que lee es una cuestión aparte, respondida en Modelo de seguridad.
Conecta tu bóveda en 60 segundos
Requiere Node 20 o más reciente.
-
Agrega el servidor a tu asistente. Para Claude Desktop, agrega esto a
claude_desktop_config.json(Cursor usa el mismo bloque en~/.cursor/mcp.json):{ "mcpServers": { "shieldfive": { "command": "npx", "args": ["-y", "@shieldfive/mcp"] } } }Para Claude Code:
claude mcp add shieldfive -- npx -y @shieldfive/mcp -
Reinicia el asistente y pídele que ordene mi bóveda de ShieldFive. Llama a
vault_connect, que abre ShieldFive en tu navegador. -
En esa pestaña, elige las carpetas, Solo lectura o Leer y organizar, y una caducidad (1 hora a 90 días), luego haz clic en Autorizar.
Esa es toda la configuración: la conexión se entrega directamente al servidor
que se ejecuta en tu computadora — a través de 127.0.0.1, nunca a través de ShieldFive — y
se almacena en el llavero de tu sistema. Nada se copia a mano.
Para conectarte antes de iniciar una conversación, ejecuta npx -y @shieldfive/mcp login:
la misma página del navegador, el mismo resultado. login --paste toma una cadena de
conexión que copiaste de Configuración → Asistentes de IA en su lugar, para una máquina sin navegador.
npx @shieldfive/mcp status muestra qué conexión está configurada y si
ShieldFive todavía la acepta. npx @shieldfive/mcp logout la elimina del
llavero. Revocarla en ShieldFive es lo que corta el acceso en todas partes.
Para CI o una máquina sin llavero, establece SHIELDFIVE_GRANT a la cadena de
conexión en su lugar. Cualquier cosa que pueda leer el entorno del servidor puede entonces leer
la conexión, así que prefiere el llavero dondequiera que exista. Establecer
SHIELDFIVE_GRANT=none mantiene un cliente solo local en una máquina cuyo llavero
contiene una conexión para otra.
Cómo se mantiene honesto el traspaso del navegador
- La página nunca acepta una URL de devolución, solo un número de puerto, y construye
http://127.0.0.1:<port>/callbackella misma. Un enlace manipulado no puede enviar tu conexión a ningún lugar excepto a tu propia máquina. - El oyente acepta exactamente una entrega: un POST a
/callback,Hostexactamente la dirección de bucle local (por lo que un nombre DNS reenlazado es rechazado), sinOriginexcepto el de ShieldFive, y un estado de 256 bits comparado en tiempo constante. Luego se cierra. - La cadena de conexión viaja en un cuerpo de formulario, nunca en una URL, por lo que no termina en el historial del navegador.
- El oyente existe solo mientras se autoriza una conexión, y como máximo 10 minutos.
Modelo de seguridad
En términos simples:
- La cadena de conexión contiene dos cosas. Un token que el servidor verifica en cada solicitud, y un secreto que nunca sale de tu máquina. ShieldFive almacena solo un hash del token y nunca ha visto el secreto.
- El secreto abre solo las carpetas que elegiste. Cuando creas una conexión, tu navegador envuelve las claves de esas carpetas bajo una clave derivada del secreto. No envuelve nada más: no tu clave raíz de la bóveda, no tu contraseña, no tu clave secreta post-cuántica. Las subcarpetas se abren a través de la cadena normal de claves de carpeta de la bóveda. Una carpeta que no elegiste no se puede abrir con nada que este servidor contenga.
- ShieldFive aplica alcance, caducidad y revocación en cada solicitud. Las verificaciones en este proceso solo producen errores más claros; el servidor es el límite. Revocar una conexión hace que su próxima solicitud falle. Nada se almacena en caché que sobreviva a una revocación.
- El descifrado ocurre aquí, en memoria. Ningún texto plano, clave o texto cifrado se escribe en el disco. Los módulos de la bóveda no importan el sistema de archivos, y una prueba lo afirma.
- Nada se elimina.
vault_trashmueve elementos a una carpeta en tu Papelera que pertenece a la conexión. No hay herramienta de eliminación permanente, y la API a la que una conexión puede acceder no tiene ruta de eliminación. Cada renombrado, movimiento y papelera aparece en Configuración → Asistentes de IA → Actividad con un botón de Deshacer. - Cada cambio se previsualiza primero. Las herramientas de mutación informan un plan, y la llamada confirmada debe llevar el token de ese plan y se rechaza si los elementos cambiaron mientras tanto.
Lo que esto no protege:
- Tu proveedor de IA ve lo que el asistente lee. Nombres de archivos, y los contenidos de los archivos que el asistente abre, van al asistente, y para un asistente en la nube eso significa a su proveedor, como el resto de tu conversación. La única forma de evitar eso es un modelo local.
- Revocar no puede desleer. Cualquier cosa que el asistente ya haya leído permanece leída. Nada más sobrevive: los contenidos de los archivos se transmiten a través de ShieldFive en cada solicitud, por lo que no hay un enlace de descarga que sobreviva a una revocación.
- Una conexión se construye a partir de lo que el servidor muestra a tu navegador cuando la creas. Cada extensión posterior se verifica contra tus propias claves, por lo que un servidor comprometido no puede ampliar una conexión después. En el momento de la creación, sin embargo, un servidor comprometido podría etiquetar incorrectamente qué carpeta elegiste.
- Una cadena de conexión copiada es una clave viva para las carpetas que cubre hasta que caduque o la revoques. Mantenla en el llavero.
- Los archivos pueden contener instrucciones dirigidas al asistente. Este servidor marca
cada nombre y contenido de archivo como datos, encierra los contenidos de archivos en un bloque que el archivo
no puede cerrar, limita
vault_trasha 50 elementos por llamada, requiere una vista previa para cada cambio, y mantiene cada cambio deshacible. Un modelo aún puede ser convencido de cometer un error reversible dentro de las carpetas que concediste.
El diseño completo, incluido el modelo de amenazas y el razonamiento detrás de cada
decisión, está en
docs/mcp-grants-design.md.
Herramientas de la bóveda
vault_connect está siempre disponible. El resto se registran una vez que existe una conexión
— conectarse a mitad de conversación las anuncia con
notifications/tools/list_changed. Todo lo siguiente nombra cosas por id; las rutas
son para personas.
| Herramienta | Necesita | Qué hace |
|---|---|---|
vault_connect | — | abre ShieldFive en el navegador para autorizar una conexión, y la almacena en el llavero |
vault_list_files | lectura | archivos y carpetas en alcance, con nombres descifrados, rutas, tamaños, fechas |
vault_search_files | lectura | por nombre, ruta, extensión, tamaño o fecha, se ejecuta localmente sobre nombres descifrados |
vault_storage_stats | lectura | totales, las carpetas y archivos más grandes, un desglose por tipo |
vault_find_duplicates | lectura | archivos del mismo tamaño descifrados en memoria y comparados por SHA-256; presupuestado, y dice cuándo un resultado es un límite inferior |
vault_read_file | lectura | archivos de texto como contenido no confiable encerrado (hasta 1 M de caracteres); otros tipos devuelven solo detalles |
vault_rename | organizar | renombrar un archivo o carpeta |
vault_move | organizar | mover a otra carpeta en alcance |
vault_create_folder | organizar | crear una carpeta en alcance |
vault_upload | escritura | cifrar un archivo local aquí y ponerlo en la bóveda, luego leerlo de vuelta y compararlo antes de que se te diga que es seguro eliminar el original |
vault_trash | organizar | hasta 50 elementos a la carpeta de la conexión en la Papelera |
vault_move_in | escritura | liberar espacio: hasta 50 archivos locales subidos y verificados uno por uno, cada original movido a la papelera local solo después de que su copia se lea idéntica — una aprobación, nada eliminado |
Límites que un usuario puede encontrar:
- Archivos post-cuánticos subidos desde un teléfono o la CLI se muestran como
readable: falsehasta que abras ShieldFive en la web nuevamente, lo que agrega la clave que la conexión necesita. Los archivos subidos en la aplicación web están listos de inmediato. - El primer listado de una bóveda grande lleva tiempo. Cada nombre cuesta alrededor de 70 ms de Argon2id, distribuido en los núcleos de tu CPU (alrededor de 20 segundos para 2,000 nombres en 8 núcleos). Los nombres se almacenan en caché en memoria por el resto de la sesión.
- Los elementos en la parte superior de una conexión de toda la bóveda se pueden leer y mover a una carpeta, pero no renombrar en su lugar, y nada se puede mover a la parte superior. Sus nombres están sellados bajo tu clave raíz de la bóveda, que una conexión nunca tiene.
- Las subidas necesitan una conexión que pueda agregar archivos ("Leer, organizar y agregar archivos" cuando la autorizas) y una asignación de subida, que eliges entonces. Cada archivo tiene como máximo 512 MB. Las subidas y movimientos leen archivos locales, por lo que el servidor necesita raíces además de una conexión.
- Mover archivos no libera espacio por sí mismo.
vault_move_inpone cada original verificado en.shieldfive-mcp-trash, con un manifiesto que nombra su copia en la bóveda; el espacio regresa cuando vacías ese directorio.
Archivos locales
Cada ruta después del nombre del paquete es una raíz. Las herramientas locales pueden leer y escribir dentro de esos directorios y en ningún otro lugar, y no hacen ninguna solicitud de red.
npx @shieldfive/mcp ~/Documents ~/Downloads
En claude_desktop_config.json:
{
"mcpServers": {
"shieldfive": {
"command": "npx",
"args": ["-y", "@shieldfive/mcp", "/Users/you/Documents", "/Volumes/Archive"]
}
}
}
Con una conexión configurada y sin raíces, solo se registran las herramientas de la bóveda. Con raíces y sin conexión, solo se registran las herramientas locales, y el servidor se comporta exactamente como lo hizo 0.2.0. Con ambas, obtienes ambas.
SHIELDFIVE_MCP_ROOTS agrega raíces también — las dos se combinan, no son
alternativas — como una lista separada por el separador de ruta de tu plataforma (: en
macOS y Linux, ; en Windows):
SHIELDFIVE_MCP_ROOTS="/Users/you/Documents:/Volumes/Archive" npx @shieldfive/mcp
El espacio en blanco alrededor de una raíz se ignora. En una ruta dada a una herramienta no lo es: allí, cada carácter es parte de la ruta.
Véelo funcionar primero
npm run demo
demo/run-demo.mjs construye cinco archivos en un directorio temporal — dos con
contenidos idénticos bajo nombres diferentes, un señuelo del mismo tamaño, un archivo de 12 MB y
un PDF de dos años — ejecuta las herramientas de lectura sobre ellos, previsualiza una llamada de papelera, luego
la confirma y muestra el manifiesto. No toca nada fuera de ese directorio
y lo elimina al final (--keep lo deja en su lugar).
Lo que las herramientas locales no pueden hacer
No pueden decirte si un archivo local ya está en tu bóveda. Comparar un nombre y tamaño local contra un listado de la bóveda es cómo una herramienta elimina la única copia de algo, y este servidor no adivinará.
No pueden evitar que los resultados lleguen a tu proveedor de IA. Las herramientas locales no hacen ninguna solicitud de red, y eso vale exactamente lo que dice y nada más: todo lo que devuelven — rutas, nombres de archivos, tamaños, fechas, los resúmenes que informan — regresa al cliente de IA que lo llamó, y si ese cliente es un asistente en la nube, esos nombres viajan al proveedor del asistente como el resto de tu conversación. Elige raíces sobre esa base.
Nunca inferirá que dos archivos son iguales por sus nombres y tamaños. La detección de duplicados lee ambos archivos y compara un SHA-256 completo de sus contenidos. La coincidencia de nombres es cómo una herramienta de deduplicación elimina la única copia de algo, y el costo de hacerlo bien es unos segundos de E/S de disco.
El hash está presupuestado, sin embargo, y el presupuesto puede hacer que la respuesta sea incompleta.
Los candidatos se agrupan por tamaño, se examinan con un hash de los primeros 64 KiB donde
los archivos son más grandes que eso, luego se confirman con un resumen completo. Cada lectura de
cualquier tipo cuenta contra max_files_hashed, 20,000 por defecto. Cuando el
presupuesto se agota, el resto queda sin hash — el grupo en el que se agota se procesa en
parte, las copias más antiguas primero — y el resultado dice cuántos archivos y cuánto espacio
nunca se verificaron. Los grupos se procesan del más grande primero, por lo que lo que sobrevive a un
presupuesto ajustado es lo que valía más.
Lo que cuenta como recuperable se calcula por archivo en disco. Los nombres que son enlaces duros a un mismo archivo cuentan como una copia, porque eliminar uno de ellos no libera nada. Los clones de APFS — lo que hace Duplicar de Finder en un volumen APFS — también comparten su almacenamiento, pero nada que este servidor pueda leer distingue un clon de una copia real, por lo que los clones se informan como recuperables cuando enviar uno a la papelera libera poco o nada. La copia nominada para conservar es la modificada más temprano; en caso de empate, gana la ruta más corta y luego la ruta en orden de unidades de código, de modo que el mismo árbol siempre nomina la misma copia.
No elimina nada tuyo, con una excepción. trash_local mueve archivos a un directorio .shieldfive-mcp-trash en el mismo volumen donde están, y escribe un manifest.json registrando dónde estaba cada uno. No se libera espacio en disco hasta que elimines ese directorio tú mismo, en tu propio administrador de archivos, con tu propio deshacer. La herramienta lo dice en su propia salida para que el asistente no pueda informar el espacio como recuperado. La excepción es un move_local entre volúmenes, que tiene que copiar: su origen se elimina, pero solo después de que la copia haya sido verificada — ver Moviendo entre volúmenes.
Eso también aplica a sobrescribir. move_local con overwrite: true mueve el elemento ya en el destino a la papelera y luego toma su lugar; no lo elimina. La vista previa te dice cuántos archivos y cuántos bytes serían desplazados, no solo cuántos se están moviendo. Si el movimiento luego falla, el elemento desplazado se vuelve a colocar.
Cada herramienta que cambia algo no hace nada por defecto. Llámala sin confirm: true y resuelve las rutas, verifica la contención, informa exactamente qué haría y se detiene. La vista previa ejecuta las mismas comprobaciones que la acción, por lo que un plan que informa un rechazo es un rechazo.
Y una llamada confirmada tiene que ser el plan que viste. La vista previa devuelve un plan_token; confirm: true sin él es rechazada. La llamada confirmada planifica de nuevo desde el sistema de archivos tal como está ahora, compara ese plan con el que el token aprobó — las rutas, qué es cada entrada, su tamaño y tiempo de modificación, y los recuentos de archivos y bytes debajo de ella — y rechaza si algo difiere, nombrando qué cambió. Un token realiza un cambio y expira después de diez minutos. Así que un directorio que creció, un destino que apareció, o una ruta que ahora apunta a un archivo diferente detiene la llamada en lugar de ampliarla silenciosamente.
Herramientas locales
| Herramienta | Lee | Escribe |
|---|---|---|
list_local | archivos, tamaños, fechas | — |
find_duplicates | contenidos de archivos (SHA-256) | — |
find_large_files | tamaños | — |
find_old_files | tiempos de modificación | — |
storage_summary | tamaños, por extensión y directorio | — |
move_local | tamaños tanto del origen como de cualquier cosa que desplazaría | mueve un archivo, carpeta o enlace simbólico; mueve un destino desplazado a la papelera; entre volúmenes, copia, verifica y luego elimina el origen |
rename_local | — | renombra en el lugar, nunca sobre un nombre existente |
create_local_folder | — | crea un directorio |
trash_local | tamaños del subárbol que se envía a la papelera | mueve a la papelera en el volumen del propio elemento, escribe un manifiesto |
Valores predeterminados, todos anulables por llamada: list_local devuelve 200 filas, los otros listados 100. find_large_files comienza en min_bytes 100,000,000 (100 MB). find_old_files en older_than_days 365. find_duplicates omite archivos vacíos (min_bytes 1), calcula hash de como máximo max_files_hashed 20,000 de ellos y devuelve 100 grupos, cada uno listando como máximo 50 de sus copias. storage_summary informa las 15 extensiones principales y los 15 directorios principales. Cada escaneo se detiene en max_files 200,000 archivos en todas las raíces, y recorre la raíz y 64 niveles de subdirectorios debajo de ella.
Cada anulación tiene un límite máximo, aplicado por el esquema MCP y nuevamente por la propia herramienta: limit 10,000 filas, max_files 1,000,000, max_files_hashed 1,000,000, paths 1,000 por llamada a trash_local, 4,096 caracteres para una ruta y 255 bytes para new_name. Un rechazo cita solo el comienzo de un valor que era demasiado largo.
find_old_files informa el tiempo de modificación, que es una señal débil: algunas operaciones de copia lo restablecen a la fecha de copia, y un archivo no tocado no es uno no deseado. La herramienta dice esto en su propio resultado en lugar de dejar que el asistente presente una lista corta como veredicto.
El recorrido no es exhaustivo
Cada herramienta de lectura recorre de la misma manera, y omite cosas por defecto:
- Entradas ocultas, a menos que pases
include_hidden: true. - Diecinueve directorios de compilación y caché por nombre, dondequiera que aparezcan:
node_modules,.git,.svn,.hg,.cache,.venv,venv,__pycache__,.next,.turbo,dist,build,target,Pods,.gradle,.tox,.mypy_cache,.pytest_cache, y la propia papelera de este servidor.build,distytargetson nombres de carpetas ordinarios fuera de un árbol de código, por lo que esto puede excluir datos reales — no hay forma de anular la lista todavía. - Enlaces simbólicos, siempre, sin anulación.
Los tres se cuentan e informan en las advertencias del resultado, por lo que un total que parece demasiado pequeño dice por qué. Aún así significa que storage_summary no es una herramienta de uso de disco: apúntala al directorio de inicio de un desarrollador y te lo dirá, pero no te dirá a dónde fue el espacio.
Cuando el presupuesto de max_files se agota antes de que se haya recorrido cada raíz, el resultado lista las raíces que recorrió bajo scanned y las demás bajo not_scanned, y su advertencia las nombra.
Vaciando la papelera
Este servidor no lo hace, y no puede. trash_local mueve cada elemento a .shieldfive-mcp-trash/<batch>/ en el directorio más alto, entre el elemento y su raíz, que esté en el volumen del propio elemento: la raíz misma, a menos que el elemento esté en una unidad montada dentro de la raíz, y entonces el directorio superior de esa unidad. <batch> es una marca de tiempo, un id de proceso y un contador, por lo que no hay dos llamadas que compartan uno. El manifest.json junto a los elementos se escribe antes de que cualquiera de ellos se mueva y lista de dónde vino cada uno; una entrada cuyo trashed_to no existe fue planificada pero no movida. Eliminarlos de verdad es un rm -rf que ejecutas tú mismo, una vez que hayas mirado lo que hay dentro. Nada aquí libera espacio en disco por sí solo.
Un punto de montaje no puede enviarse a la papelera, porque ningún directorio en su propio volumen dentro de la raíz puede contenerlo. Si .shieldfive-mcp-trash es un enlace simbólico o un archivo, trash_local y un move_local que sobrescribe rechazan en lugar de seguirlo.
Moviendo entre volúmenes
rename(2) no puede cruzar volúmenes, por lo que un movimiento entre ellos es una copia seguida de eliminar el origen — el único lugar donde este servidor elimina algo que hiciste. Se hace de modo que una falla en cualquier punto no pierda nada:
- La copia se hace bajo un nombre oculto nuevo junto al destino (
.shieldfive-mcp-incoming-<pid>-<n>), creado exclusivamente, y se coloca sin reemplazar nada. Nada que ya estaba allí se toca. - Una carpeta que contiene un enlace simbólico, un FIFO, un socket o un archivo de dispositivo se rechaza antes de que se elimine cualquier parte, porque una copia no puede llevarlos fielmente.
- Cada archivo se vacía al disco y se compara con su origen — mismo tamaño, mismo SHA-256 — y el origen no debe haber cambiado desde que se copió. Si alguna de las comprobaciones falla, la copia se descarta y el origen permanece.
- El origen se elimina archivo por archivo, cada uno solo si sigue siendo el archivo que se copió, y las carpetas solo una vez que están vacías. Cualquier cosa que cambió o apareció durante el movimiento se deja donde está y se lista en
source_left_in_place.
Un bloqueo en el medio puede dejar una copia parcial bajo ese nombre oculto. El origen está intacto hasta que su copia esté en su lugar.
Cancelación
Una solicitud cancelada no inicia ningún cambio. trash_local se detiene entre elementos, nunca dentro de uno, por lo que cada elemento está movido y registrado o intacto, y el error dice cuál. Un move_local cancelado antes de que su origen comience a eliminarse se deshace, incluido volver a colocar cualquier cosa que desplazó; después de ese punto termina, porque detenerse dejaría media árbol en cada lado. El SDK de MCP no envía respuesta a una solicitud cancelada, por lo que lo que hizo una llamada cancelada se escribe en el registro de stderr del servidor y, para la papelera, en el manifiesto.
Cómo funciona la contención
Cada ruta que un asistente proporciona se usa exactamente como se da, por lo que "report " nunca es "report", y se resuelve con realpath — siguiendo cada enlace simbólico — antes de que algo la lea o escriba a través de ella. El resultado debe estar dentro de una raíz configurada. Una verificación de límite consciente de separadores significa que /data/roots-evil no coincide con la raíz /data/root.
Ese orden es el punto. Una verificación de cadena en la ruta proporcionada se derrota con ..; una verificación después de path.resolve aún se derrota con un enlace simbólico, porque /allowed/link -> /etc se resuelve a una cadena bajo /allowed mientras se lee /etc. Resolver enlaces primero cierra ambos, y es por eso que el recorrido de directorios usa lstat y nunca sigue un enlace — un enlace que el recorrido atravesara sería una ruta que la contención nunca vio.
Los destinos que aún no existen — un objetivo de movimiento, una nueva carpeta — se verifican resolviendo el ancestro existente más cercano y re-agregando el resto, por lo que escribir a través de un padre con enlace simbólico se detecta antes de la escritura en lugar de después. Un enlace simbólico cuyo objetivo no existe se rechaza dondequiera que una escritura pasaría a través de él: realpath lo informa exactamente como una ruta faltante, y tomarlo en su palabra permitiría que una copia aterrice dondequiera que apunte el enlace.
Lo único que no se sigue es el elemento sobre el que actúa una herramienta mutadora. Un enlace simbólico dado a move_local, rename_local o trash_local se mueve, renombra o envía a la papelera él mismo, como lo trata mv, y a lo que apunta no se toca; solo la propia posición del enlace tiene que estar dentro de una raíz. Lo mismo va para el destino de un movimiento: un enlace simbólico allí, colgante o no, es una entrada existente que overwrite: true movería a la papelera, no una carpeta en la que moverse. Da la ruta real de la carpeta para eso.
rename_local y move_local no reemplazan algo que aparece en el destino después de que lo han verificado. Un archivo se enlaza duro a su nuevo nombre y solo entonces se desenlaza del antiguo, un enlace simbólico se recrea, y una carpeta se renombra sobre un marcador vacío hecho un momento antes, por lo que algo que aparece en el medio hace que la operación falle en lugar de ser sobrescrito. Donde no existe tal operación — FIFOs, sockets y archivos de dispositivo, sistemas de archivos sin enlaces duros como FAT y exFAT, y carpetas en Windows — la herramienta verifica y luego renombra, y un archivo creado en ese instante sería reemplazado.
Lo que afirman las pruebas
npm test ejecuta 225 pruebas. Las que vale la pena conocer:
- Se rechaza un enlace simbólico que apunte fuera de una raíz, tanto en el lado de lectura como en el de escritura, y también se rechaza un enlace simbólico colgante en una ruta de escritura.
- Se rechaza un
.shieldfive-mcp-trashque sea un enlace simbólico fuera de la raíz, y no se escribe nada a través de él. - Dos archivos con el mismo nombre y el mismo tamaño pero con contenidos diferentes no se reportan como duplicados, y dos nombres para un mismo archivo no se cuentan como espacio a recuperar.
trash_localdeja los bytes legibles en su nueva ubicación, en el mismo volumen, y reportaspace_freed_bytes: 0.- En un disco RAM montado dentro de una raíz, un movimiento entre volúmenes mantiene una fuente cuya copia llega corrupta o que cambia mientras se copia, deja un archivo existente en su antiguo nombre de preparación, rechaza una carpeta que contenga un FIFO y nunca escribe a través de un enlace simbólico colgante. Estas pruebas se ejecutan en macOS y se omiten en otros lugares.
- Un archivo que aparece con el nuevo nombre entre la comprobación y el cambio de nombre no se reemplaza.
- Una solicitud cancelada no mueve nada, y un lote de papelera cancelado a mitad de camino dice exactamente qué movió.
- Solo
src/vault/api.mjsllama afetch, y solo a un origen ShieldFive https. Ningún módulo de herramienta local importa nada de la mitad de la bóveda, y las únicas variables de entorno que se leen sonSHIELDFIVE_MCP_ROOTS,SHIELDFIVE_GRANTySHIELDFIVE_API_URL. - La entrega al navegador es el único socket entrante y el único subproceso en el paquete:
src/vault/connect.mjsenlaza un puerto aleatorio en127.0.0.1, no abre ninguna conexión propia y lanza el navegador con un comando fijo y sin shell. Se rechaza una entrega desde otro origen, con otro estado, a otroHost, por otro método o después de la primera. - Los módulos de la bóveda no importan ningún módulo del sistema de archivos, por lo que los datos descifrados no se pueden escribir en el disco. Ningún módulo usa un cifrado, HMAC o KDF propio. Toda la criptografía proviene de
@shieldfive/crypto. - Contra un ShieldFive en memoria que sirve texto cifrado real en los tres formatos de bóveda, a través de un cliente MCP real:
- los archivos se descifran solo con las claves de la concesión, y nada fuera del alcance se lista, lee o incluso se solicita;
- una conexión revocada o caducada falla en la siguiente llamada;
- los cambios de nombre y los movimientos vuelven a sellar nombres y claves para que las propias claves del propietario aún los abran;
- el secreto y el token de la concesión nunca aparecen en ningún cuerpo de solicitud ni ruta.
- Un archivo cuyo contenido le dice al asistente que lo tire todo a la papelera vuelve dentro de una valla que no puede cerrar. Leerlo solo emite lecturas, y se rechaza una llamada de papelera de 51 elementos.
- Un cliente MCP real a través de un transporte stdio real ve exactamente las nueve herramientas locales cuando no hay ninguna conexión configurada, incluso cuando el servidor se inicia a través de un enlace simbólico como lo instala npm.
La afirmación de red tiene un límite que vale la pena señalar: prueba lo que hace src/, no lo que el árbol de dependencias podría hacer. @modelcontextprotocol/sdk incluye transportes HTTP para los servidores de otras personas. Lo que cierra esa brecha es que server.mjs importa el transporte stdio y ningún HTTP, lo que también se afirma.
Límites
- La comprobación del plan reduce la brecha entre la vista previa y la acción; no la cierra. La comparación ocurre dentro de la llamada confirmada, por lo que un cambio que llegue entre esa comprobación y la escritura en sí sigue siendo posible. Cada herramienta vuelve a comprobar su propio destino inmediatamente antes de escribir, que es lo que hace que esa ventana sea pequeña en lugar de ausente, y ninguna herramienta basada en rutas puede hacerlo mejor.
- Un plan vincula lo que nombró. Para un directorio, eso es la entrada en sí más los recuentos de archivos y bytes debajo de él, suficiente para detectar contenido que aparece, desaparece o cambia de tamaño, pero no un archivo editado en el lugar con exactamente la misma longitud dentro del mismo segundo.
- Los tamaños son tamaños de contenido de archivo. Excluyen la sobrecarga del directorio e ignoran la compresión del sistema de archivos, los archivos dispersos, los enlaces duros y los clones de APFS, por lo que los totales no coincidirán exactamente con una utilidad de disco;
storage_summarycuenta cada nombre de un archivo con enlaces duros. - Los clones de APFS parecen copias.
find_duplicateslos reporta como recuperables, y tirar uno a la papelera libera poco o nada. - Los escaneos están limitados de forma predeterminada a 200,000 archivos, y a la raíz y 64 niveles de subdirectorios debajo de ella. Cuando se alcanza un límite, el resultado lo dice, tanto en la línea de resumen como en un campo: un escaneo que se detuvo en un límite se lee exactamente como uno que terminó, y el asistente reporta una lista parcial como si fuera completa.
- El comportamiento entre volúmenes se prueba solo en macOS, contra un disco RAM que las pruebas montan dentro de su propio directorio temporal.
- Windows no está probado. El código no usa ninguna API exclusiva de POSIX, y el manejo de rutas pasa por
node:path, pero nadie lo ha ejecutado allí.
SECURITY.md lleva el resto: tiempo de comprobación/tiempo de uso, las ventanas en las que un cambio de nombre aún puede reemplazar algo, los enlaces duros, lo que significa y no significa heredar el entorno, y lo que cubre la afirmación de no red.
Política de privacidad
Este servidor no envía nada a ningún lugar a menos que se configure una conexión ShieldFive, y solo entonces a la API de ShieldFive (https://shieldfive.com, o el origen en SHIELDFIVE_API_URL):
- Lo que envía: solicitudes que las herramientas de la bóveda necesitan: listados, lecturas y cambios por id, y para cargas, el texto cifrado y las claves envueltas que produjo en esta máquina. Los nombres y contenidos de archivos están cifrados antes de salir; una carga de almacenamiento va directamente a una URL de almacenamiento prefirmada y nunca lleva la credencial de conexión.
- Lo que nunca envía: nombres o contenidos en texto plano, rutas locales, nada sobre sus carpetas locales, telemetría o análisis. Las herramientas locales no hacen ninguna solicitud de red.
- Lo que ShieldFive conserva: un registro de la conexión y de cada solicitud que hace (ids, acción, resultado, tiempo, sin nombres, contenidos, dirección IP o agente de usuario), conservado mientras exista su cuenta y eliminado con ella. La sección 3.9 de la Política de privacidad de ShieldFive cubre estos registros, su retención y sus derechos sobre ellos.
- Lo que recibe su asistente: lo que lea a través de este servidor, descifrado aquí, va a quien ejecute el asistente, bajo sus términos, como cualquier otra cosa en esa conversación.
- Credencial: se guarda en el llavero del sistema operativo (o
SHIELDFIVE_GRANT), nunca se registra, devuelve ni escribe en un archivo.
Contacto: support@shieldfive.com, o security@shieldfive.com para vulnerabilidades.
Seguridad
Reporte vulnerabilidades a security@shieldfive.com. Consulte SECURITY.md.
Licencia
MIT. Las versiones hasta la 0.6.3 inclusive se publicaron bajo Apache-2.0.