editor-mcp

by danielpodrazka
Verified

local-only server

The server can only run on the client’s local machine because it depends on local resources.

Integrations

  • Uses Babel for JavaScript and React JSX syntax validation before committing code changes, ensuring JavaScript/React code maintains proper syntax.

  • Provides syntax checking for JavaScript files (.js) to maintain code integrity when editing JavaScript code.

  • Requires Node.js to perform JavaScript/JSX syntax validation through Babel when editing these file types.

Editor MCP

Un servidor editor de texto basado en Python, desarrollado con FastMCP, que proporciona potentes herramientas para la gestión de archivos. Este servidor permite leer, editar y gestionar archivos de texto mediante una API estandarizada con un enfoque único de varios pasos que mejora significativamente la precisión y la fiabilidad de la edición de código para LLM y asistentes de IA.

Características

  • Selección de archivo : establece un archivo con el que trabajar usando rutas absolutas
  • Operaciones de lectura :
    • Leer archivos completos con números de línea usando skim
    • Leer rangos de líneas específicos con números de línea prefijados usando read
    • Busque texto específico dentro de archivos usando find_line
    • Busque y extraiga definiciones de funciones en archivos Python y JavaScript/JSX usando find_function
  • Operaciones de edición :
    • Proceso de edición en dos pasos con vista previa de diferencias
    • Seleccionar y sobrescribir texto con verificación de identidad
    • Flujo de trabajo de edición limpio con seleccionar → sobrescribir → confirmar/cancelar patrón
    • Comprobación de sintaxis para archivos Python (.py) y JavaScript/React (.js, .jsx)
    • Crear nuevos archivos con contenido
  • Gestión de archivos :
    • Crear nuevos archivos con la inicialización adecuada
    • Eliminar archivos del sistema de archivos
    • Listar el contenido del directorio con listdir
  • Soporte de pruebas :
    • Ejecutar pruebas de Python con run_tests
    • Establecer rutas de Python para una resolución adecuada del módulo
  • Características de seguridad :
    • Verificación de Content ID para evitar conflictos
    • Límites de conteo de líneas para evitar el agotamiento de recursos
    • Comprobación de sintaxis para mantener la integridad del código
    • Rutas protegidas para restringir el acceso a archivos confidenciales

Riesgos de seguridad

El editor-mcp incluye potentes capacidades que vienen con ciertas consideraciones de seguridad:

  • Riesgo de jailbreak : El editor-mcp podría sufrir jailbreak al leer un archivo con instrucciones maliciosas. El contenido malicioso en los archivos editados podría contener instrucciones que manipulen el asistente de IA.
  • Ejecución de código arbitrario : si la ejecución de pruebas está habilitada, existe el riesgo de ejecución de código arbitrario a través de archivos de prueba manipulados o código Python malicioso.
  • Exposición de datos : el acceso a las operaciones del sistema de archivos podría exponer información confidencial si no se configuran las protecciones de ruta adecuadas.

Para mitigar estos riesgos:

  1. Utilice la variable de entorno PROTECTED_PATHS para restringir el acceso a archivos y directorios confidenciales.
  2. Deshabilite las capacidades de ejecución de pruebas en entornos de producción a menos que sea absolutamente necesario.
  3. Revise cuidadosamente los archivos antes de abrirlos, especialmente si provienen de fuentes no confiables.
  4. Considere ejecutar el editor en un entorno aislado con permisos limitados.

Ventajas clave para los LLM

El diseño único de este editor de texto resuelve problemas críticos que normalmente afectan la edición de código LLM:

  • Previene la pérdida de contexto : Los enfoques tradicionales suelen provocar que los LLM pierdan la visión general del código base tras unas pocas modificaciones. Esta implementación mantiene el contexto a través del proceso de varios pasos.
  • Evita reescrituras que consumen muchos recursos : los LLM suelen reemplazar archivos completos cuando se confunden, lo cual resulta costoso, lento e ineficiente. Este editor permite realizar ediciones selectivas.
  • Proporciona retroalimentación visual : el sistema de vista previa de diferencias permite que el LLM realmente vea y verifique los cambios antes de confirmarlos, lo que reduce drásticamente los errores.
  • Implementa la comprobación de sintaxis : la validación automática para Python y JavaScript/React garantiza que no se confirme el código roto.
  • Mejora el razonamiento de edición : el enfoque de múltiples pasos le da al LLM tiempo para razonar entre pasos, lo que reduce la producción aleatoria de tokens.

Gestión de recursos

El editor implementa varias medidas de seguridad para garantizar la estabilidad del sistema y evitar el agotamiento de los recursos:

  • Máximo de líneas de edición : de forma predeterminada, el editor aplica un límite de 50 líneas para cualquier operación de edición individual.

Instalación

Este MCP fue desarrollado y probado con Claude Desktop. Puedes descargar Claude Desktop en cualquier plataforma. Para Linux, puedes usar un script de instalación no oficial (que usa el archivo oficial). Repositorio recomendado: https://github.com/emsi/claude-desktop/tree/main

Una vez que tenga instalado Claude Desktop, siga las instrucciones a continuación para instalar este MCP específico:

Fácil instalación con UVX (recomendado)

La forma más sencilla de instalar el Editor MCP es utilizando el script de instalación proporcionado:

# Clone the repository git clone https://github.com/danielpodrazka/editor-mcp.git cd editor-mcp # Run the installation script chmod +x install.sh ./install.sh

Este script hará lo siguiente:

  1. Compruebe si UVX está instalado e instálelo si es necesario
  2. Instalar el Editor MCP en modo de desarrollo
  3. Haga que el comando editor-mcp esté disponible en su PATH

Instalación manual

Uso de UVX

# Install directly from GitHub uvx install git+https://github.com/danielpodrazka/mcp-text-editor.git # Or install from a local clone git clone https://github.com/danielpodrazka/mcp-text-editor.git cd mcp-text-editor uvx install -e .

Usando pip tradicional

pip install git+https://github.com/danielpodrazka/mcp-text-editor.git # Or from a local clone git clone https://github.com/danielpodrazka/mcp-text-editor.git cd mcp-text-editor pip install -e .

Uso de requisitos (heredado)

Instalar desde el archivo de bloqueo:

uv pip install -r uv.lock

Generar un archivo de requisitos bloqueado:

uv pip compile requirements.in -o uv.lock

Uso

Iniciando el servidor

Después de la instalación, puede iniciar el servidor Editor MCP utilizando uno de estos métodos:

# Using the installed script editor-mcp # Or using the Python module python -m text_editor.server

Configuración de MCP

Puede agregar el Editor MCP a su archivo de configuración MCP:

{ "mcpServers": { "text-editor": { "command": "editor-mcp", "env": { "MAX_SELECT_LINES": "100", "ENABLE_JS_SYNTAX_CHECK": "0", "FAIL_ON_PYTHON_SYNTAX_ERROR": "1", "FAIL_ON_JS_SYNTAX_ERROR": "0", "PROTECTED_PATHS": "*.env,.env*,config*.json,*secret*,/etc/passwd,/home/user/.ssh/id_rsa" } } } }

Configuración de variables de entorno

El editor MCP admite varias variables de entorno para personalizar su comportamiento:

  • MAX_SELECT_LINES : "100": número máximo de líneas que se pueden editar en una sola operación (el valor predeterminado es 50)
  • ENABLE_JS_SYNTAX_CHECK : "0" - Habilita o deshabilita la verificación de sintaxis de JavaScript y JSX (el valor predeterminado es "1" - habilitado)
  • FAIL_ON_PYTHON_SYNTAX_ERROR : "1": cuando está habilitado, los errores de sintaxis de Python cancelarán automáticamente la operación de sobrescritura (el valor predeterminado es habilitado)
  • FAIL_ON_JS_SYNTAX_ERROR : "0": cuando está habilitado, los errores de sintaxis de JavaScript/JSX cancelarán automáticamente la operación de sobrescritura (el valor predeterminado está deshabilitado).
  • PROTECTED_PATHS : Lista separada por comas de patrones de archivos o rutas a los que no se puede acceder, que admite comodines (por ejemplo, " .env,.env ,/etc/passwd")

Ejemplo de configuración de MCP al compilar desde la fuente

{ "mcpServers": { "text-editor": { "command": "/home/daniel/pp/venvs/editor-mcp/bin/python", "args": ["/home/daniel/pp/editor-mcp/src/text_editor/server.py"], "env": { "MAX_SELECT_LINES": "100", "ENABLE_JS_SYNTAX_CHECK": "0", "FAIL_ON_PYTHON_SYNTAX_ERROR": "1", "FAIL_ON_JS_SYNTAX_ERROR": "0", "PROTECTED_PATHS": "*.env,.env*,config*.json,*secret*,/etc/passwd,/home/user/.ssh/id_rsa" } } } }

Herramientas disponibles

El editor MCP proporciona 13 herramientas potentes para la manipulación, edición y prueba de archivos:

1. set_file

Establece el archivo actual con el que trabajar.

Parámetros :

  • filepath (str): Ruta absoluta al archivo

Devoluciones :

  • Mensaje de confirmación con la ruta del archivo

2. skim

Lee el texto completo del archivo actual. Cada línea tiene como prefijo su número.

Devoluciones :

  • Diccionario que contiene líneas con sus números de línea, número total de líneas y la configuración máxima de líneas de edición

Ejemplo de salida :

{ "lines": [ [1, "def hello():"], [2, " print(\"Hello, world!\")"], [3, ""], [4, "hello()"] ], "total_lines": 4, "max_select_lines": 50 }

3. read

Lee el texto del archivo actual desde la línea inicial hasta la línea final.

Parámetros :

  • start (int): Número de línea de inicio (indexación basada en 1)
  • end (int): Número de línea final (indexación basada en 1)

Devoluciones :

  • Diccionario que contiene líneas con sus números de línea como claves, junto con información de la línea de inicio y final

Ejemplo de salida :

{ "lines": [ [1, "def hello():"], [2, " print(\"Hello, world!\")"], [3, ""], [4, "hello()"] ], "start_line": 1, "end_line": 4 }

4. select

Seleccione un rango de líneas del archivo actual para la posterior operación de sobrescritura.

Parámetros :

  • start (int): Número de línea de inicio (basado en 1)
  • end (int): Número de línea final (basado en 1)

Devoluciones :

  • Diccionario que contiene las líneas seleccionadas, el rango de líneas y la identificación para verificación

Nota :

  • Esta herramienta valida la selección contra max_select_lines
  • Los detalles de selección se almacenan para su uso en la herramienta de sobrescritura.
  • Esto debe usarse antes de llamar a la herramienta de sobrescritura

5. overwrite

Prepárese para sobrescribir un rango de líneas en el archivo actual con texto nuevo.

Parámetros :

  • new_lines (lista): Lista de nuevas líneas para sobrescribir el rango seleccionado

Devoluciones :

  • Vista previa de diferencias que muestra los cambios propuestos

Nota :

  • Este es el primer paso de un proceso de dos pasos:
    1. Primera llamada a overwrite() para generar una vista previa de la diferencia
    2. Luego llame a confirm() para aplicar o cancel() para descartar los cambios pendientes.
  • Esta herramienta permite reemplazar las líneas previamente seleccionadas con contenido nuevo
  • El número de nuevas líneas puede diferir de la selección original.
  • Para los archivos Python (extensión .py), la verificación de sintaxis se realiza antes de escribir
  • Para los archivos JavaScript/React (extensiones .js, .jsx), la verificación de sintaxis es opcional y se puede deshabilitar mediante la variable de entorno ENABLE_JS_SYNTAX_CHECK

6. confirm

Aplicar los cambios pendientes de la operación de sobrescritura.

Devoluciones :

  • Resultado de la operación con estado y mensaje

Nota :

  • Esta es una de las dos acciones posibles en el segundo paso del proceso de edición.
  • La selección se elimina tras la aplicación exitosa de los cambios.

7. cancel

Descartar los cambios pendientes de la operación de sobrescritura.

Devoluciones :

  • Resultado de la operación con estado y mensaje

Nota :

  • Esta es una de las dos acciones posibles en el segundo paso del proceso de edición.
  • La selección permanece intacta cuando se cancelan los cambios.

8. delete_file

Eliminar el archivo configurado actualmente.

Devoluciones :

  • Resultado de la operación con estado y mensaje

9. new_file

Crea un nuevo archivo.

Parámetros :

  • absolute_file_path (str): Ruta del nuevo archivo

Devoluciones :

  • Resultado de la operación con estado e id del contenido si aplica

Nota :

  • Esta herramienta fallará si el archivo actual existe y no está vacío

10. find_line

Busque líneas que coincidan con el texto proporcionado en el archivo actual.

Parámetros :

  • search_text (str): Texto a buscar en el archivo

Devoluciones :

  • Diccionario que contiene líneas coincidentes con sus números de línea y coincidencias totales

Ejemplo de salida :

{ "status": "success", "matches": [ [2, " print(\"Hello, world!\")"] ], "total_matches": 1 }

Nota :

  • Devuelve un error si no se establece ninguna ruta de archivo
  • Busca coincidencias de texto exactas dentro de cada línea
  • El id se puede utilizar para operaciones de edición posteriores

11. find_function

Busque una definición de función o método en el archivo Python o JavaScript/JSX actual.

Parámetros :

  • function_name (str): Nombre de la función o método a buscar

Devoluciones :

  • Diccionario que contiene las líneas de función con sus números de línea, línea_de_inicio y línea_de_finalización

Ejemplo de salida :

{ "status": "success", "lines": [ [10, "def hello():"], [11, " print(\"Hello, world!\")"], [12, " return True"] ], "start_line": 10, "end_line": 12 }

Nota :

  • Para los archivos Python, esta herramienta utiliza el AST de Python y tokeniza los módulos para identificar con precisión los límites de las funciones, incluidos los decoradores y las cadenas de documentación.
  • Para archivos JavaScript/JSX, esta herramienta utiliza una combinación de enfoques:
    • Método principal: análisis de Babel AST cuando esté disponible (requiere paquetes Node.js y Babel)
    • Método de respaldo: coincidencia de patrones de expresiones regulares para declaraciones de funciones cuando Babel no está disponible
  • Admite varios tipos de funciones de JavaScript, incluidas funciones estándar, funciones asíncronas, funciones de flecha y ganchos de React.
  • Devuelve un error si no se establece ninguna ruta de archivo o si no se encuentra la función

12. listdir

Enumera el contenido de un directorio.

Parámetros :

  • dirpath (str): Ruta al directorio a listar

Devoluciones :

  • Diccionario que contiene la lista de nombres de archivos y la ruta consultada

13. run_tests y set_python_path

Herramientas para ejecutar pruebas de Python con pytest y configurar el entorno de Python.

  • Establezca en "0", "falso" o "no" para deshabilitar la comprobación de sintaxis de JavaScript
  • Útil si no tienes instalado Babel y las dependencias relacionadas
  • FAIL_ON_PYTHON_SYNTAX_ERROR : Controla si los errores de sintaxis de Python cancelan automáticamente la operación de sobrescritura (valor predeterminado: 1)
    • Cuando está habilitado, los errores de sintaxis en los archivos Python harán que la acción de sobrescritura se cancele automáticamente.
    • Las líneas permanecerán seleccionadas para que puedas corregir el error y volver a intentarlo.
  • FAIL_ON_JS_SYNTAX_ERROR : Controla si los errores de sintaxis de JavaScript/JSX cancelan automáticamente la operación de sobrescritura (valor predeterminado: 0)
    • Cuando está habilitado, los errores de sintaxis en archivos JavaScript/JSX harán que la acción de sobrescritura se cancele automáticamente.
    • Las líneas permanecerán seleccionadas para que puedas corregir el error y volver a intentarlo.
  • DUCKDB_USAGE_STATS : Controla si las estadísticas de uso se recopilan en una base de datos DuckDB (valor predeterminado: 0)
    • Establezca en "1", "verdadero" o "sí" para habilitar la recopilación de estadísticas de uso de la herramienta.
    • Cuando está habilitado, registra información sobre cada llamada de herramienta, incluidas las marcas de tiempo y los argumentos.
  • STATS_DB_PATH : Ruta donde se almacenará la base de datos DuckDB para estadísticas (predeterminado: "text_editor_stats.duckdb")
    • Solo se utiliza cuando DUCKDB_USAGE_STATS está habilitado
  • PROTECTED_PATHS : Lista separada por comas de patrones de archivos o rutas absolutas a las que se les negará el acceso
    • Ejemplo: *.env,.env*,config*.json,*secret*,/etc/passwd,/home/user/credentials.txt
    • Admite rutas de archivos exactas y patrones glob flexibles con comodines en cualquier posición:
      • *.env : coincide con archivos que terminan en .env, como .env , dev.env , prod.env
      • .env* - coincide con archivos que comienzan con .env, como .env , .env.local , .env.production
      • *secret* - coincide con cualquier archivo que contenga 'secreto' en el nombre
    • Proporciona protección contra la exposición accidental de archivos de configuración y credenciales confidenciales.
    • Las líneas permanecerán seleccionadas para que puedas corregir el error y volver a intentarlo.

Desarrollo

Prerrequisitos

El editor-mcp requiere:

  • Python 3.7+
  • Paquete FastMCP
  • negro (para comprobaciones de formato de código Python)
  • Babel (para comprobaciones de sintaxis de JavaScript/JSX si se trabaja con esos archivos)

Instalar dependencias de desarrollo:

# Using pip pip install pytest pytest-asyncio pytest-cov # Using uv uv pip install pytest pytest-asyncio pytest-cov

Para validar la sintaxis de JavaScript/JSX, necesita Node.js y Babel. El editor de texto usa npx babel para comprobar la sintaxis de JS/JSX al editar estos tipos de archivos:

# Required for JavaScript/JSX syntax checking npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/preset-react # You can also install these globally if you prefer # npm install -g @babel/core @babel/cli @babel/preset-env @babel/preset-react

El editor requiere:

  • @babel/core y @babel/cli : paquetes básicos de Babel para la comprobación de sintaxis
  • @babel/preset-env - Para archivos JavaScript estándar (.js)
  • @babel/preset-react - Para archivos React JSX (.jsx)

Ejecución de pruebas

# Run tests pytest -v # Run tests with coverage pytest -v --cov=text_editor

Estructura de la prueba

El conjunto de pruebas cubre:

  1. herramienta set_file
    • Configuración de archivos válidos
    • Configuración de archivos inexistentes
  2. herramienta de lectura
    • Validación del estado del archivo
    • Leyendo archivos completos
    • Lectura de rangos de líneas específicos
    • Casos extremos como archivos vacíos
    • Manejo de rango no válido
  3. herramienta de selección
    • Validación de rango de línea
    • Validación de selección contra max_select_lines
    • Almacenamiento de selección para operaciones posteriores
  4. herramienta de sobrescritura
    • Verificación de contenido seleccionado mediante identificación
    • Validación de reemplazo de contenido
    • Comprobación de sintaxis para archivos Python y JavaScript/React
    • Generación de vista previa de diferencias para cambios
  5. confirmar y cancelar herramientas
    • Aplicar o cancelar cambios pendientes
    • Proceso de verificación de dos pasos
  6. herramienta de eliminación de archivos
    • Validación de eliminación de archivos
  7. herramienta new_file
    • Validación de creación de archivos
    • Manejo de archivos existentes
  8. herramienta find_line
    • Encontrar coincidencias de texto en archivos
    • Manejo de términos de búsqueda específicos
    • Manejo de errores para archivos inexistentes
    • Manejo de casos sin coincidencias
    • Manejo de archivos existentes

Cómo funciona

El enfoque de edición de varios pasos

A diferencia de los métodos tradicionales de edición de código, donde los LLM simplemente buscan líneas para editar y realizan reemplazos (lo que a menudo genera confusión después de varias ediciones), este editor implementa un flujo de trabajo estructurado de varios pasos que mejora drásticamente la precisión de la edición:

  1. set_file - Primero, el LLM establece qué archivo quiere editar
  2. Skim - El LLM lee todo el archivo para obtener una descripción general completa
  3. leer - El LLM examina secciones específicas relevantes para la tarea, con líneas que se muestran junto a los números para un mejor contexto
  4. seleccionar - Cuando esté listo para editar, el LLM selecciona líneas específicas (limitadas a un número configurable, predeterminado 50)
  5. sobrescribir : LLM propone contenido de reemplazo, lo que da como resultado una vista previa de estilo git diff que muestra exactamente qué cambiará
  6. Confirmar/Cancelar : después de revisar la vista previa, el LLM puede aplicar o descartar los cambios.

Este flujo de trabajo estructurado obliga al LLM a analizar cuidadosamente cada edición y evita errores comunes, como sobrescribir archivos completos accidentalmente. Al ver vistas previas de los cambios antes de confirmarlos, el LLM puede verificar que las ediciones sean correctas.

Sistema de verificación de identidad

El servidor utiliza FastMCP para ofrecer funciones de edición de texto mediante una API bien definida. El sistema de verificación de identidad garantiza la integridad de los datos verificando que el contenido no haya cambiado entre las operaciones de lectura y modificación.

El mecanismo de identificación utiliza SHA-256 para generar un identificador único del contenido del archivo o de los rangos de líneas seleccionados. Para operaciones específicas de línea, el ID incluye un prefijo que indica el rango de líneas (p. ej., "L10-15-[hash]"). Esto ayuda a garantizar que las modificaciones se apliquen al contenido esperado.

Detalles de implementación

La clase principal TextEditorServer :

  1. Se inicializa con una instancia de FastMCP llamada "editor de texto".
  2. Establece un límite max_select_lines configurable (predeterminado: 50) a partir de variables de entorno
  3. Mantiene la ruta del archivo actual como estado
  4. Registra trece herramientas principales a través de FastMCP:
    • set_file : valida y establece la ruta del archivo actual
    • skim : lee todo el contenido de un archivo y devuelve un diccionario de números de línea a texto de línea
    • read : lee líneas de un rango de líneas especificado y devuelve un diccionario estructurado del contenido de las líneas
    • select : selecciona líneas para la operación de sobrescritura posterior
    • overwrite : toma una lista de nuevas líneas y prepara una vista previa de diferencias para cambiar el contenido
    • confirm : aplica los cambios pendientes de la operación de sobrescritura
    • cancel : descarta los cambios pendientes de la operación de sobrescritura
    • delete_file : elimina el archivo actual
    • new_file : Crea un nuevo archivo
    • find_line : Encuentra líneas que contienen texto específico
    • find_function : busca definiciones de funciones o métodos en archivos Python y JavaScript/JSX
    • listdir : enumera el contenido de un directorio
    • run_tests y set_python_path : herramientas para ejecutar pruebas de Python

El servidor se ejecuta utilizando el transporte stdio de FastMCP de forma predeterminada, lo que facilita la integración con varios clientes.

Aviso del sistema para obtener mejores resultados

Para obtener resultados óptimos con los asistentes de IA, se recomienda utilizar el mensaje del sistema (consulte system_prompt.md ) que ayuda a guiar a la IA para realizar ediciones manejables y seguras.

Este mensaje del sistema ayuda al asistente de IA a:

  1. Realizar cambios incrementales : dividir las ediciones en partes más pequeñas
  2. Mantener la integridad del código : realizar cambios que mantengan el código funcional
  3. Trabajar dentro de los límites de recursos : evitar operaciones que puedan saturar el sistema
  4. Seguir un flujo de trabajo de verificación : realizar comprobaciones finales para detectar errores después de las ediciones

Al incorporar este aviso del sistema cuando trabaje con asistentes de IA, obtendrá un comportamiento de edición más confiable y evitará errores comunes en la edición de código automatizada.

Estadísticas de uso

El editor de texto MCP puede recopilar estadísticas de uso cuando está habilitado, lo que proporciona información sobre cómo se utilizan las herramientas de edición:

  • Recopilación de datos : las estadísticas se recopilan en una base de datos DuckDB cuando DUCKDB_USAGE_STATS está habilitado
  • Información rastreada : registra el nombre de la herramienta, los argumentos, la marca de tiempo, la ruta del archivo actual, la respuesta de la herramienta y las identificaciones de solicitud/cliente
  • Ubicación de almacenamiento : los datos se almacenan en un archivo DuckDB especificado por STATS_DB_PATH
  • Privacidad : todo se almacena localmente en su máquina.

Las estadísticas recopiladas pueden ayudar a comprender patrones de uso, identificar flujos de trabajo comunes y optimizar el editor para las operaciones más frecuentes.

Puede consultar la base de datos utilizando SQL estándar a través de cualquier cliente DuckDB para analizar patrones de uso.

Solución de problemas

Si encuentra problemas:

  1. Comprobar permisos de archivos
  2. Verifique que las rutas de los archivos sean absolutas
  3. Asegúrese de que el entorno utilice Python 3.7+

Inspiración

Inspirado en un proyecto similar: https://github.com/tumf/mcp-text-editor , que al principio bifurqué, sin embargo decidí reescribir todo el código base desde cero para que solo la idea general permaneciera igual.

ID: era56k0b3d