Secure Agent Workspace

Un espacio de trabajo aislado y agéntico que proporciona un sistema de archivos seguro, bash y ejecución de Python impulsada por uv.

Documentación

🛡️ Servidor MCP de Agent Workspace

CI License: MIT Python 3.14+

Un servidor unificado del Protocolo de Contexto de Modelos (MCP) que proporciona un espacio de trabajo altamente seguro y contenerizado para Modelos de Lenguaje de Gran Escala (LLMs). Actúa como un "patio de juegos agéntico" aislado donde los agentes pueden codificar, probar y depurar de forma autónoma sin arriesgar la máquina host.


✨ Características

  • 🏗️ Ciclo de vida completo del proyecto: Inicializa proyectos con uv init, gestiona dependencias con uv add y ejecuta mediante uv run.
  • 🐚 Acceso seguro a Bash: Ejecuta comandos de shell con tiempos de espera obligatorios y flujos de salida combinados.
  • 🚀 Salida optimizada en tokens: Integra RTK (Rust Token Killer) para filtrar y comprimir automáticamente las salidas de run_bash (como ls, git y ejecutores de pruebas), ahorrando 60-90% de los tokens de contexto del LLM.
  • 📂 Sistema de archivos robusto: Operaciones protegidas contra ataques de traversal de rutas para leer, escribir y buscar en el espacio de trabajo.
  • 🛡️ Seguridad multicapa: Ejecución sin root, capacidades eliminadas, límites de recursos y sistema de archivos raíz de solo lectura.
  • Edición de precisión: search_and_replace avanzado con coincidencia difusa de espacios en blanco, preservación de indentación, soporte de ejecución en seco y validación de sintaxis para Python, JSON, JSONL, TOML y YAML.
  • 📊 Observabilidad en tiempo real: Registro directo en la interfaz del cliente MCP y registros de auditoría rotativos persistentes.

🏗️ Arquitectura

flowchart TD
    Client["MCP Client (Claude / Cursor)"] -- "stdio (JSON-RPC)" --> FastMCP["FastMCP Server"]

    subgraph Sandbox ["Docker Sandbox Container (mcpuser)"]
        direction TB
        
        FastMCP -. "Intercepts accidental prints" .-> StdioGuard["StdoutRedirector"]
        FastMCP -. "Application Logs" .-> Logger["Dual Logger (stderr & .mcp/server.log)"]
        
        FastMCP -- "Tool Calls" --> SecurityGuard["Security & Path Validator"]
        
        subgraph Toolset ["Tool Modules"]
            direction TB
            SecurityGuard --> FSTools["Filesystem (read, write, list, search)"]
            SecurityGuard --> EditTools["Editing (search_and_replace)"]
            SecurityGuard --> ExecTools["Execution (run_bash)"]
        end

        EditTools -- "AST Verification" --> Validator["Syntax Validations (Python, JSON, JSONL, TOML, YAML)"]
        ExecTools -- "Process Group (Timeout=60s)" --> Shell["/bin/sh Subprocess"]
        Shell -- "Package Mgt & Checks" --> UV["uv Environment / Ruff"]
        
        FSTools -- "Secure I/O" --> Workspace["/workspace Directory"]
        EditTools -- "Atomic Writes" --> Workspace
        Shell -- "Executes within" --> Workspace
    end

    Workspace <--"Volume Mount"--> HostFS["User Host Filesystem"]

📦 Inicio rápido

1. Extraer o construir la imagen Docker

# Pull from GHCR
docker pull ghcr.io/hrrodan/agent-workspace-mcp:latest

# OR: Build locally with your host's UID/GID for optimal permissions
docker build --build-arg UID=$(id -u) --build-arg GID=$(id -g) -t agent-workspace-mcp .

2. Uso programático (SDK de OpenAI Agents)

Aquí hay un código de inicio rápido que muestra cómo usar el espacio de trabajo contenerizado programáticamente con el SDK estándar de openai-agents:

import asyncio
from agents import Agent, Runner
from agents.mcp import MCPServerStdio

async def main():
    # 1. Configure the MCP Server to run via Docker
    server = MCPServerStdio(
        name="Sandboxed Workspace",
        params={
            "command": "docker",
            "args": [
                "run", "-i", "--rm", "--init",
                # "--network", "none", # Network Isolation (optional) - see below
                "--memory=2g", "--cpus=2.0",
                "--pids-limit=256",
                "--cap-drop=ALL", "--security-opt=no-new-privileges:true",
                "--read-only",
                "--tmpfs", "/tmp:size=64m",
                "--tmpfs", "/home/mcpuser/.cache:size=512m",
                "--user", "1000:1000", # Replace with your host UID:GID
                "-v", "/path/to/your/projects:/workspace",
                "ghcr.io/hrrodan/agent-workspace-mcp:latest",
            ],
        },
        client_session_timeout_seconds=60.0,
    )

    # 2. Attach server to the Agent and load the skill instructions (optional)
    with open("skills/agent-workspace-mcp/SKILL.md", "r") as f:
        skill_instructions = f.read()

    agent = Agent(
        name="WorkspaceAgent",
        instructions=f"You are a coding agent with access to a secure workspace.\n\n{skill_instructions}",
        mcp_servers=[server],
    )

    # 3. Execute a workflow
    async with server:
        result = await Runner.run(
            agent, 
            "Create a python script in the workspace to print the first 10 Fibonacci numbers, then run it."
        )
        print(f"Agent's Final Output:\n{result.final_output}")

if __name__ == "__main__":
    asyncio.run(main())

3. Uso con clientes MCP (Claude / Cursor)

Agrega la siguiente configuración a tu claude_desktop_config.json o a la configuración de Cursor.

{
  "mcpServers": {
    "agent-workspace-mcp": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm", "--init",
        // "--network", "none", // Network Isolation (optional) - see below
        "--memory=2g", "--cpus=2.0",
        "--pids-limit=256",
        "--cap-drop=ALL", "--security-opt=no-new-privileges:true",
        "--read-only",
        "--tmpfs", "/tmp:size=64m",
        "--tmpfs", "/home/mcpuser/.cache:size=512m",
        "--user", "1000:1000",
        "-v", "/path/to/your/projects:/workspace",
        "ghcr.io/hrrodan/agent-workspace-mcp:latest"
      ]
    }
  }
}

[!IMPORTANT] Usuarios de Linux: Reemplaza 1000:1000 con tu UID:GID real (ejecuta id -u y id -g). Claude Desktop no expande variables de entorno. Manejo de señales: La bandera --init es esencial para el reenvío adecuado de señales y la recolección de procesos zombis.


🛠️ Referencia de herramientas

HerramientaDescripción
read_fileLee archivos de texto con offset y limit opcionales (predeterminado: 100 líneas).
write_fileCrea archivos con validación de sintaxis y un límite de tamaño de 5MB. Se niega a sobrescribir archivos existentes por defecto (create_only=True).
list_directoryLista contenidos con prefijos de [F]archivo y [D]directorio.
search_workspaceEncuentra archivos por patrón glob con soporte para exclude_patterns.
run_bashEjecuta comandos de shell en /workspace con un tiempo de espera de 60s. Optimizado automáticamente mediante RTK para reducir el uso de tokens.
search_and_replaceHerramienta de edición múltiple con coincidencia difusa de espacios en blanco, preservación de indentación, modo de ejecución en seco y validación de sintaxis (Python, JSON, JSONL, TOML, YAML).

⚙️ Configuración

El servidor admite las siguientes variables de entorno (pasadas a través de Docker --env):

VariablePredeterminadoDescripción
COMMAND_TIMEOUT60Segundos predeterminados antes de que run_bash mate un proceso.
MAX_SEARCH_RESULTS50Resultados máximos devueltos por search_workspace.
MAX_READ_SIZE_BYTES1048576Tamaño máximo de archivo para read_file (1MB).
MAX_WRITE_SIZE_BYTES5242880Tamaño máximo de archivo para write_file (5MB).
LOG_LEVELINFONivel de registro de Python (DEBUG, INFO, etc.).

🛡️ Modelo de seguridad y arquitectura

Este servidor emplea una estrategia de defensa en profundidad, separando explícitamente los límites de seguridad estrictos de las características de experiencia del desarrollador y confiabilidad operativa.

🔒 Características de seguridad principales

Estas características están diseñadas para proteger el sistema host y aplicar límites de aislamiento estrictos.

  • Endurecimiento del kernel: Se eliminan todas las capacidades de Linux (--cap-drop=ALL), neutralizando los vectores de escalada de privilegios.
  • Código de servidor inmutable: El directorio /app que contiene el código fuente del servidor y su entorno virtual es propiedad de root y es de solo lectura para mcpuser. Esto evita que el servidor se modifique a sí mismo o sea manipulado mediante run_bash.
  • Bloqueo de privilegios: Aplica no-new-privileges:true para evitar que cualquier proceso obtenga derechos elevados.
  • Núcleo del sistema inmutable: El sistema de archivos raíz del contenedor está montado completamente en solo lectura, proporcionando una segunda capa de defensa contra la manipulación a nivel de sistema operativo.
  • Cuotas de recursos: Límites estrictos en CPU, memoria y PIDs mitigan intentos de denegación de servicio (DoS) como bombas fork y agotamiento del host.
  • Aplicación estricta de límites: Un validador de rutas robusto bloquea de manera integral todos los ataques de traversal de rutas fuera del /workspace designado.
  • Control de procesos y recursos: Tiempos de espera obligatorios (60s por defecto) y aislamiento estricto de grupos de procesos aseguran que los procesos descontrolados o maliciosos sean eliminados.
  • Protección contra sobrecarga de memoria: Límites estrictos en lecturas de archivos (1MB) y salidas de comandos (50KB) previenen el agotamiento de memoria.
  • Prevención de fugas de información: Los rastreos de pila internos y las rutas del sistema se suprimen y sanitizan de las salidas de las herramientas.

🛠️ Experiencia del desarrollador y conveniencia

Características enfocadas en integración fluida, usabilidad y reducción de fricción en flujos de trabajo agénticos.

  • Identidad no root alineada con el host: Se ejecuta como mcpuser con UID/GID personalizable en tiempo de compilación, eliminando conflictos tediosos de permisos de archivos en montajes de volúmenes del host.
  • Optimización automática de tokens: Los comandos de shell ejecutados mediante run_bash se reescriben transparentemente a través de RTK para proporcionar una salida ultracompacta y amigable para LLMs sin alterar el comportamiento subyacente del comando.
  • Exclusiones de búsqueda inteligentes: Los directorios de alto ruido o sensibles (.git, .venv) se ignoran automáticamente para mantener las ventanas de contexto limpias y relevantes.
  • Espacios de trabajo efímeros: Los contenedores son estrictamente efímeros (--rm), garantizando un estado limpio y predecible para cada nueva sesión sin fugas de estado entre conexiones.
  • Descubrimiento estandarizado: Cumple con la Especificación de Imágenes OCI para una integración estandarizada en el ecosistema de contenedores y una auditoría transparente.

⚙️ Mecanismos de confiabilidad y seguridad

Características que aseguran la integridad estructural del espacio de trabajo y proporcionan observabilidad.

  • Validación de sintaxis previa a la escritura: Tanto write_file como search_and_replace realizan validación de sintaxis en memoria para Python, JSON, JSONL, TOML y YAML antes de persistir cambios, evitando estados de código rotos.
  • Escritura a prueba de fallos: write_file bloquea sobrescrituras accidentales de archivos existentes por defecto y aplica un límite de tamaño de 5MB para prevenir la inundación del espacio de trabajo.
  • Operaciones de archivo atómicas: Las ediciones utilizan lógica de temp-y-mover para garantizar la integridad de los archivos y prevenir la corrupción, incluso durante interrupciones o fallos inesperados.
  • Observabilidad transparente: Todas las invocaciones de herramientas y cambios de estado se transmiten en tiempo real a la interfaz del cliente MCP para una supervisión inmediata del operador.

🌐 Aislamiento de red (opcional)

Por defecto, el contenedor tiene acceso completo a la red a través de la red bridge de Docker. Para un aislamiento máximo, puedes deshabilitar completamente la pila de red usando --network none:

docker run -i --rm --init \
  --network none \
  --memory=2g --cpus=2.0 --pids-limit=256 \
  --cap-drop=ALL --security-opt=no-new-privileges:true \
  --read-only \
  --tmpfs /tmp:size=64m \
  --tmpfs /home/mcpuser/.cache:size=512m \
  --user 1000:1000 \
  -v /path/to/your/projects:/workspace \
  ghcr.io/hrrodan/agent-workspace-mcp:latest

Esto crea un sandbox completamente aislado — solo la interfaz de loopback existe dentro del contenedor. Todas las conexiones salientes (curl, DNS, uv add, etc.) fallarán inmediatamente, eliminando por completo los riesgos de exfiltración de datos y movimiento lateral.

[!NOTE] Con --network none, el agente no puede instalar paquetes en tiempo de ejecución. Todas las dependencias deben estar preinstaladas en una imagen personalizada o pre-pobladas en el volumen del espacio de trabajo montado.


🤝 Contribuciones

  1. Instalar dependencias de desarrollo: uv sync
  2. Ejecutar linting: uv run ruff check .
  3. Ejecutar pruebas unitarias: uv run pytest tests/ --ignore=tests/integration/
  4. Ejecutar pruebas de integración: Establece OPENROUTER_API_KEY y ejecuta uv run pytest tests/integration/

© 2026 HrRodan. Licenciado bajo MIT.