cmdshellmcp
Un servidor MCP de comandos y operaciones de archivos restringidos para agentes de IA. Limita la ejecución de comandos mediante una lista de permitidos explícita, permite deshabilitar cada herramienta individualmente y admite tokens de autenticación generados automáticamente. Proporciona comandos Unix restringidos, operaciones de archivos, parches y recuperación de URL sin exponer un shell sin restricciones.
Documentación
cmdshellmcp
cmdshellmcp es un servidor MCP de shell de comandos restringido para agentes de IA. Expone un pequeño conjunto de comandos Unix permitidos, operaciones de archivos relativamente seguras, aplicación de parches y obtención de URL para que un cliente MCP pueda realizar tareas locales limitadas sin acceso shell sin restricciones.
El servidor está implementado en Python y se ejecuta como servidor MCP utilizando el paquete fastmcp. Por defecto escucha en 127.0.0.1:8003 utilizando el transporte HTTP transmisible a menos que se seleccione --sse.
[!CAUTION]
Este servidor proporciona ejecución remota de comandos (RCE), que normalmente se considera una vulnerabilidad de seguridad crítica. Permitir comandos potentes—como bash, sh, python, perl, sudo, docker, o comandos capaces de escribir archivos—puede permitir que un atacante o un LLM no confiable eluda las restricciones previstas y tome control del sistema. Por ejemplo, permitir python o bash puede efectivamente permitir ejecución arbitraria de código y acceso a archivos. Si el servidor carece de autenticación fuerte, es accesible por clientes no confiables, o está controlado por un LLM no confiable o con inyección de prompts, puede causar daños graves, incluyendo pérdida de datos, robo de credenciales, instalación de malware o compromiso de otros sistemas. Ejecute cmdshellmcp (cmdshellmcp2.py) solo en un entorno aislado protegido y desechable con privilegios cuidadosamente limitados a los requeridos para su tarea prevista y con acceso limitado a archivos, credenciales, dispositivos y redes—por ejemplo, un contenedor Docker efímero o una máquina virtual que pueda destruirse de forma segura después de su uso.
Advertencia
Esta es una aplicación experimental / de prueba que evolucionó a partir del uso de un servidor MCP (herramientas) que permiten ejecutar comandos shell con fines de programación. Desafortunadamente, para tal propósito, a menudo es necesario proporcionar al cliente LLM (modelo) comandos shell bastante potentes para "hacer su trabajo" para un alcance / contexto / intención particular.
Los comandos permitidos por defecto no son necesariamente seguros, es decir, los agentes LLM o prácticamente los clientes que llaman
a la API MCP pueden 'escaparse' y hacer cosas fuera de un contexto, por ejemplo, el directorio de trabajo definido con la opción --cwd.
Tampoco valida si los argumentos son seguros después de todo.
También hay herramientas (funciones MCP expuestas) que exponen operaciones de escritura y modificación de archivos, incluyendo la ejecución de comandos shell.
- La autenticación está habilitada por defecto. Mantenga el token generado aleatoriamente, o establezca
un auth_token fijo usando el campo auth en el archivo de configuración o
--auth. Usar--noauthprácticamente significa que está otorgando ejecución remota de comandos (RCE) a cualquier cliente (incluyendo posiblemente maliciosos o fraudulentos) que pueda alcanzar el servidor. - Ejecute esto como un usuario sin privilegios. Ejecutar como
rootes en el mejor de los casos una tontería - No use esto con clientes no confiables o LLMs no confiables
- Úselo en un entorno aislado desechable, por ejemplo, un contenedor Docker independiente o una máquina virtual que pueda permitirse desechar incluyendo su contenido
- Revise la lista de permitidos en
cmdshellmcp.jsony los valores predeterminados codificados, revíselos antes de usarlos.
Características
- Ejecución shell permitida para un conjunto seleccionado de comandos
- Operaciones de lectura/escritura/listado de archivos bajo un directorio de trabajo configurado
- Edición transaccional de archivos de texto con
sed, copias de seguridad numeradas y diffs unificados - Aplicación de parches de diff unificado mediante
patch - Soporte de obtención HTTP con embellecimiento HTML opcional
- Autenticación con token Bearer con un token seguro generado aleatoriamente por defecto
- Registro de auditoría en stdout y/o un archivo
- Restricciones de ruta para evitar escapar del directorio de trabajo actual
Uso de IA en este repositorio
Esta aplicación y su contenido, por ejemplo, esta página, se creó con la ayuda de LLM (modelos de lenguaje grandes) como
- ChatGPT 5.6 sol (light), Codex
- Github Co-pilot MAI-Code-1.1-Flash
El código inicial fue escrito por el autor y refactorizado con la ayuda de los LLMs, y las actualizaciones también se realizan parcialmente de forma manual. Después de agregar o cambiar características, a menudo se realizan pruebas adicionales ejecutándolas manualmente, por ejemplo, en la interfaz web de llama-server de llama.cpp
Instalación
- Clone el repositorio.
- Cree y active un entorno virtual si lo desea.
- Instale las dependencias:
python -m venv .venv
source .venv/bin/activate
pip install fastmcp requests beautifulsoup4
Si su entorno usa un requirements.txt, también puede instalar desde allí:
pip install -r requirements.txt
La herramienta editFile también requiere GNU sed (incluyendo su opción --sandbox)
y diff instalados en el servidor. Estos programas se invocan directamente por
la herramienta dedicada y no necesitan aparecer en allowed_commands.
Configuración
Cuando no se proporciona --conf, el servidor lee el archivo de configuración opcional cmdshellmcp.json
del directorio actual. Si el archivo no existe, el
servidor usa valores predeterminados de línea de comandos e integrados.
Ejemplo:
{
"host": "127.0.0.1",
"port": 8003,
"quiet": false,
"auditlog": null,
"disableTools": ["writeFile", "editFile", "applyPatch"],
"allowed_commands": [
"ls", "pwd", "date", "cat", "grep", "egrep",
"whoami", "head", "tail", "sed", "wc", "file", "du", "df",
"free", "ps", "uname", "hostname", "uptime", "w", "last",
"mkdir", "cp", "mv", "awk"
],
"auth": "_my_secret_auth_token_"
}
Claves de configuración admitidas:
host: host de enlace; predeterminado127.0.0.1port: puerto de enlace; predeterminado8003quiet: suprime la salida de auditoría en stdout cuandotrueauditlog: ruta opcional a un archivo de registro de auditoríaallowed_commands: lista de comandos permitidos para ejecucióndisableTools: lista de nombres de herramientas MCP a omitir del servidor, sensible a mayúsculas y se requiere coincidencia exacta del nombreauth: cadena de token Bearer fija opcional; cuando se omite, se genera un token aleatorio al inicio
Ejecutar el servidor
Inicie el servidor con la configuración predeterminada:
python cmdshellmcp2.py
Cuando se omite --cwd, el servidor solicita un directorio de trabajo y muestra el
directorio actual del proceso como predeterminado. Presione Enter para aceptarlo. Si la entrada
estándar no está disponible (por ejemplo, cuando se ejecuta como servicio), el directorio
actual se selecciona automáticamente. El servidor luego se inicia en 127.0.0.1:8003
usando el transporte HTTP transmisible.
Modo SSE
python cmdshellmcp2.py --sse
Esto ejecuta el servidor en el transporte SSE en lugar de HTTP transmisible.
Clientes de navegador y CORS
Ambos transportes HTTP incluyen middleware CORS para clientes MCP basados en navegador. El
servidor acepta solicitudes de cualquier origen, admite los métodos MCP GET, POST y
DELETE y solicitudes de verificación previa OPTIONS del navegador, y expone el
encabezado de respuesta mcp-session-id al JavaScript del navegador.
Debido a que se permiten todos los orígenes, no exponga el servidor a una red no confiable
sin autenticación y controles de red apropiados. Para restringir
el acceso del navegador, reemplace allow_origins=["*"] en CORS_MIDDLEWARE con los
orígenes confiables específicos.
Directorio de trabajo personalizado
python cmdshellmcp2.py --cwd /path/to/project
Esto establece el directorio de trabajo utilizado por las herramientas de archivos y shell sin solicitar.
La ruta debe existir y debe ser un directorio; ~ se expande y la ruta
seleccionada se normaliza a una ruta absoluta.
Host y puerto personalizados
python cmdshellmcp2.py --host 0.0.0.0 --port 9000
Autenticación
La autenticación está habilitada por defecto. Si ni --auth ni un valor auth en
el archivo de configuración proporcionan un token fijo, el servidor genera un
token codificado en base64 criptográficamente seguro y lo muestra en el registro
de inicio. El token generado se muestra en negrita cuando stdout admite estilo ANSI.
Configure el cliente MCP para enviar ese valor como su token Bearer.
Para usar un token fijo en su lugar:
python cmdshellmcp2.py --auth my-secret-token
Para ejecutar explícitamente sin autenticación:
python cmdshellmcp2.py --noauth
--auth y --noauth son mutuamente excluyentes. --noauth también anula un
valor auth en el archivo de configuración. Deshabilitar la autenticación es inseguro en
cualquier red que no sea completamente confiable.
Registro de auditoría
python cmdshellmcp2.py --quiet --auditlog /tmp/cmdshellmcp.log
--quietdeshabilita el registro de auditoría en stdout.--auditlogagrega eventos de auditoría al archivo especificado.
Opciones de línea de comandos
python cmdshellmcp2.py [--cwd PATH] [--host HOST] [--port PORT] \
[--allow COMMAND [COMMAND ...]] [--conf FILE] [--auth TOKEN | --noauth] \
[--disableTools TOOL[,TOOL...]] [--editdelbk] [--sse] [--quiet] \
[--auditlog FILE]
Opciones:
--cwd: directorio de trabajo utilizado para operaciones de archivos y shell; cuando se omite, solicita con el directorio actual del proceso como predeterminado--host: host de enlace del servidor--port: puerto de enlace del servidor--allow: anula la lista de permitidos para el proceso actual; puede repetirse--disableTools: nombres de herramientas MCP separados por comas a omitir; anula la listadisableToolsdel archivo de configuración; sensible a mayúsculas y se requiere coincidencia exacta del nombre--editdelbk: elimina la copia de seguridad numerada después de queeditFilehaya completado exitosamente y compuesto su respuesta de diff unificado--conf: ruta del archivo de configuración JSON; cuando se omite, predeterminado acmdshellmcp.jsonen el directorio actual--auth: usa un token Bearer fijo en lugar de generar uno--noauth: deshabilita explícitamente la autenticación Bearer; mutuamente excluyente con--authe inseguro en redes no confiables--sse: usa transporte SSE en lugar de HTTP transmisible--quiet: suprime la salida de auditoría en stdout--auditlog: escribe registros de auditoría en un archivo dado
Anulación de la lista de permitidos
python cmdshellmcp2.py --allow ls pwd date whoami cat grep
Esto anula allowed_commands del archivo de configuración para ese proceso.
Deshabilitar herramientas
python cmdshellmcp2.py --disableTools writeFile,editFile,applyPatch,fetch
Esto evita que las herramientas coincidentes se registren en el servidor. Los nombres de las herramientas
son sensibles a mayúsculas y deben coincidir con los nombres de funciones en la sección Herramientas MCP expuestas a agentes de IA a continuación.
La opción de línea de comandos anula la lista disableTools del archivo de configuración.
Modelo de seguridad
Este servidor está intencionalmente restringido. Está diseñado para ser relativamente seguro en un entorno controlado en lugar de un shell general sin restricciones.
Las características de seguridad incluyen:
- Los comandos shell deben estar explícitamente presentes en la lista de permitidos
- Los nombres de comandos se verifican antes de la ejecución
- La herramienta
cmdshellespera un nombre de comando y una matriz de argumentos, no una cadena shell cruda - La canalización (piping) no está soportada por diseño
- Para varias herramientas, el servidor MCP valida rutas para prevenir acceso o escritura fuera de su directorio de trabajo dado
https://github.com/ag88/cmdshellmcp/blob/main/cmdshellmcp2.py#L153.
Sin embargo, para ejecutar comandos Unix/Linux
allow_listedreales, esta verificación no se realiza para los argumentos. Esto se debe a que hay situaciones donde es necesario acceder a recursos compartidos, por ejemplo, un archivo/recurso en digamos/usr/share,/usr/include, etc. Restricciones estrechas significarían configuraciones de lista de permitidos verbosas por comando + argumentos específicos que serían una lista muy grande y detallada, difícil de mantener (manualmente) y posiblemente lenta ya que necesita realizar la verificación cada vez. Por lo tanto, uno debe considerar cuidadosamente los comandos Unix/Linuxallow_listespecíficos para su contexto / uso / intención, al configurarlos por ejemplo encmdshellmcp.json - Las herramientas de archivos rechazan rutas absolutas y rutas que contienen
.. - Las escrituras se limitan a ubicaciones debajo del
cwdconfigurado editFileacepta solo una pequeña lista de permitidos de opcionessedque no seleccionan archivos, ejecuta GNUseden modo sandbox y no invoca un shelleditFileescribe la salida exitosa en un archivo temporal antes de reemplazar atómicamente el origen; las ejecuciones fallidas deseddejan el origen sin cambios- La aplicación de parches bloquea opciones peligrosas que cambian rutas
En resumen: el shell es un sandbox estrecho para operaciones controladas de lectura/escritura, no un terminal de host completo.
Herramientas MCP expuestas a agentes de IA
El servidor registra las siguientes herramientas:
1. cmdshell(command, args)
Ejecuta un comando Unix configurado con argumentos.
Parámetros:
command: el nombre del comando, que debe aparecer en la lista de permitidosargs: lista de argumentos/banderas para pasar al comando
Ejemplo:
cmdshell("ls", ["-la"])
cmdshell("grep", ["-R", "needle", "."])
Notas:
- El nombre del comando debe estar en la lista de permitidos.
- Los argumentos se pasan como una lista, reduciendo el riesgo de inyección de shell.
- Los patrones glob pueden expandirse automáticamente.
- Los globs entre comillas pueden pasarse literalmente para prevenir la expansión.
2. writeFile(file, text, append=False, newline=True)
Escribe texto a un archivo dentro del directorio de trabajo actual.
Parámetros:
file: una ruta relativa bajocwdtext: contenido a escribirappend: sitrue, añade en lugar de sobrescribirnewline: añade una nueva línea al final cuandotrue
Ejemplo:
writeFile("notes.txt", "hello from the agent")
Esto está restringido a rutas relativas por debajo del directorio de trabajo configurado.
3. readFile(file)
Lee un archivo de texto UTF-8 dentro del directorio de trabajo actual.
Ejemplo:
readFile("README.md")
4. listFiles(path=".")
Lista las entradas en un directorio dentro del directorio de trabajo configurado.
Ejemplo:
listFiles(".")
listFiles("src")
Devuelve una lista de entradas separadas por nuevas líneas, con / añadido para directorios.
5. editFile(file, script, args=None)
Edita un archivo de texto existente dentro del directorio de trabajo configurado usando GNU
sed. El parámetro dedicado script es la única fuente del programa de
edición; el comando se ejecuta con una lista de argumentos en lugar de a través de un
shell.
Parámetros:
file: ruta relativa de un archivo regular existente bajocwdscript: una expresión o programa de ediciónsed, comos/old/new/g,/pattern/d, o10,20s/old/new/gargs: opciones seguras opcionales desed, como-no-E; las opciones que habilitan la edición en el lugar, proporcionan otra expresión o archivo de programa, o seleccionan archivos de entrada/salida adicionales son rechazadas
Ejemplo:
editFile("src/example.py", "s/old_name/new_name/g")
Antes de ejecutar sed, la herramienta copia el origen al siguiente respaldo numerado no utilizado.
Por ejemplo, la primera edición anterior crea src/example.py.bk1; si ese
nombre existe, usa .bk2, luego .bk3, y así sucesivamente. Los respaldos existentes nunca se
sobrescriben.
sed escribe su resultado propuesto en memoria mientras se ejecuta en modo sandbox, lo que
bloquea comandos GNU sed que leen archivos, escriben archivos o ejecutan programas. El
origen se reemplaza desde un archivo temporal en el mismo directorio solo después de que sed sale
exitosamente. Una ejecución fallida de sed deja el origen sin cambios y elimina el nuevo
respaldo innecesario. Si el reemplazo ha comenzado y un paso posterior falla, el respaldo se
conserva para recuperación.
En caso de éxito, la respuesta identifica el respaldo e incluye la salida de:
diff -u src/example.py.bk1 src/example.py
El respaldo es la versión anterior y el archivo actual es la versión nueva. Una edición sin cambios se informa explícitamente y aún conserva su respaldo numerado.
Inicie el servidor con --editdelbk para eliminar cada respaldo numerado después de una
edición exitosa. La herramienta primero ejecuta diff y compone la respuesta completa,
por lo que el diff unificado devuelto permanece disponible incluso si el respaldo ha sido
eliminado. El mensaje de éxito identifica el respaldo eliminado. Los respaldos aún se
conservan cuando el reemplazo o la generación del diff falla, por lo que permanecen disponibles
para recuperación. Si la eliminación del respaldo en sí falla, la respuesta comienza con Error:
e informa que la edición se completó pero el respaldo permanece.
Nota de seguridad: los respaldos contienen el archivo completo previo a la edición, incluidos los secretos que contenía. A menos que
--editdelbkesté habilitado, permanecen en el disco después de ediciones exitosas. Protéjalos y elimínelos según la misma política de retención que el archivo de origen.
6. applyPatch(file, diff, pnum=2, args=None)
Aplica un diff a un archivo explícitamente nombrado usando GNU patch. El diff es
normalmente un diff unificado y se pasa directamente a patch a través de la entrada estándar.
Parámetros:
file: archivo regular existente dentro del directorio actual configuradodiff: texto del parche, normalmente un diff unificadopnum: número de componentes de ruta iniciales a eliminar, correspondiente a GNU patch's-pNUM; predeterminado2args: banderas GNU patch permitidas opcionales; las banderas que pueden seleccionar otro objetivo, entrada, salida, directorio, destino de respaldo/rechazo o valor de eliminación son rechazadas
Ejemplo:
applyPatch(
file="src/example.py",
pnum=2,
diff="--- a/src/example.py\n+++ b/src/example.py\n@@ -1 +1 @@\n-old\n+new\n",
)
El file explícito es autoritativo; los nombres de archivo incrustados en el diff no se
usan para elegir un objetivo. Las rutas absolutas y el recorrido de directorios padre son rechazados, y
el objetivo resuelto debe permanecer dentro del directorio actual configurado.
7. fetch(url, prettify=False)
Obtiene una URL usando requests. Si prettify es true, analiza el HTML con BeautifulSoup y lo imprime de forma ordenada.
Ejemplo:
fetch("https://example.com")
fetch("https://example.com", prettify=True)
Inicio de ejemplo
python cmdshellmcp2.py \
--cwd /workspace/project \
--host 0.0.0.0 \
--port 8003 \
--auth mytoken \
--allow ls pwd date cat grep head tail wc
Esto inicia un servidor con un directorio de trabajo fijo, host de enlace, puerto, autenticación y una lista de comandos permitidos mínima.
Notas
- Transporte predeterminado:
streamable-http - Host predeterminado:
127.0.0.1 - Puerto predeterminado:
8003 - La lista de comandos permitidos predeterminada se construye a partir de un pequeño conjunto de comandos relativamente seguros
Casos de uso típicos
- Inspeccionar el estado del repositorio y del sistema de archivos
- Leer archivos fuente y registros
- Escribir pequeños archivos generados o cambios de configuración
- Realizar sustituciones de texto revisables con respaldos automáticos
- Aplicar parches pequeños
- Obtener documentación o datos de la web
- Ejecutar un conjunto limitado de diagnósticos relativamente seguros
Este servidor se usa mejor cuando un agente de IA necesita acceso local controlado sin que se le den comandos de sistema sin restricciones.