Excalidraw mediante MCP
Decir "usa Excalidraw MCP" debería ser suficiente para obtener un diagrama complicado, dibujado en vivo y guardado donde corresponde. Esta habilidad es lo que hace que eso sea realidad.
Lo único que lo rompe todo
El formato de elementos de create_view es un esqueleto, no el esquema de disco. La
label de una forma es azúcar solo del esqueleto. El motor de renderizado del lienzo de Excalidraw no tiene rama de texto para rectángulo / elipse / rombo — el texto del contenedor se dibuja únicamente mediante
boundElements → containerId. Por lo tanto, pegar JSON de create_view en un archivo .excalidraw
produce cajas vacías, en silencio. Ese único hecho es por lo que existe scripts/excalidraw_build.py:
escribe una vez en el esqueleto, obtienes tanto el renderizado en vivo como un archivo correcto.
Segundo hecho: los diagramas hechos a mano no degradan gradualmente con el tamaño — fallan por irregularidad. Medido en una escena generada real, los elementos producidos por una fórmula de diseño repetitivo tuvieron una tasa de defectos del 0.00; los elementos únicos hechos a medida tuvieron 0.71. Por lo tanto, calcula las posiciones con una fórmula, y deja que el linter verifique el resultado.
Verificación previa en una máquina nueva
Instalar esta habilidad no instala el servidor MCP — mcp-deps es una declaración que
vskill check verifica, no un instalador. Si las herramientas mcp__excalidraw__* no están
disponibles, ejecuta esto primero — detecta y registra el servidor, en cualquier sistema operativo:
python3 scripts/ensure_mcp.py --install
Informa dónde se encontró el servidor, o ejecuta
claude mcp add --transport http --scope user excalidraw https://mcp.excalidraw.com
y vuelve a verificar. Código de salida 0 configurado, 1 faltante, 2 no se pudo registrar (no hay CLI de Claude en
PATH — imprime el comando para ejecutar manualmente). Claude Code necesita un reinicio después para
recoger un servidor recién añadido.
Ámbitos: --scope user (por defecto) cubre todos los proyectos de la máquina mediante ~/.claude.json;
--scope project escribe ./.mcp.json para que los compañeros de equipo lo obtengan al clonar; --scope local es
solo este proyecto. Un servidor registrado bajo un proyecto diferente cuenta como faltante —
Claude Code no lo cargará aquí, y el script lo indica.
Sin el MCP, todo excepto el renderizado en línea en vivo sigue funcionando.
excalidraw_build.py y excalidraw_lint.py son solo Python 3 con la biblioteca estándar — sin paquetes, sin
red. Construye archivos, límpialos, envíalos. excalidraw_render.py adicionalmente necesita
pip install playwright && playwright install chromium.
Windows
Usa py -3 y barras invertidas; python3 en Windows es un stub de Microsoft Store que abre
la Tienda en lugar de ejecutar nada.
py -3 scripts\ensure_mcp.py --install
py -3 scripts\excalidraw_build.py scene.json -o out.excalidraw
Todo lo demás es portátil: las rutas pasan por pathlib, la salida se escribe con UTF-8 explícito
y saltos de línea \n para que una ejecución en Windows no hornee CRLF en el JSON de la escena, y la
verificación previa resuelve claude.cmd / claude.exe además de claude. Si vskill i advierte
que los enlaces simbólicos no están disponibles, recurre a copiar — habilita el Modo Desarrollador para obtener
enlaces simbólicos de vuelta.
Flujo de trabajo
- Verificación previa (solo en máquina nueva): si las herramientas
mcp__excalidraw__*faltan,python3 scripts/ensure_mcp.py --install(py -3en Windows). - Escribe el esqueleto. Un array JSON, el mismo que recibe
create_view. Las posiciones provienen de una fórmula de diseño (consultareferences/layout-recipes.md), nunca de estimación visual. - Límpialo — sin conexión, sin dependencias, detecta desbordamiento/colisión/geometría:
python3 scripts/excalidraw_lint.py scene.json --camera--cameraimprime uncameraUpdatecorrectamente encuadrado 4:3 para pegar al principio. - Renderízalo en vivo con
mcp__excalidraw__create_view, los elementos se transmiten en orden z con movimientos de cámara (consultareferences/mcp-workflow.md). Conserva elcheckpointIddevuelto. - Guarda el archivo cuando el usuario quiera uno en disco:
python3 scripts/excalidraw_build.py scene.json -o out.excalidraw python3 scripts/excalidraw_build.py scene.json -o out --obsidian # → out.excalidraw.md python3 scripts/excalidraw_build.py scene.json -o out.excalidraw --dark - Míralo antes de declarar éxito en algo no trivial. Esto renderiza a través del
exportToSvgpropio de Excalidraw, por lo que el texto se mide con métricas de fuente reales:
Luego lee el PNG. Arregla lo que veas; vuelve a limpiar; vuelve a renderizar.python3 scripts/excalidraw_render.py out.excalidraw -o /tmp/preview.png
Los pasos 2 y 5 son el control de calidad. Omitirlos es como terminar con etiquetas fuera de sus cajas y flechas apuntando a la nada.
Hoja de trucos del esqueleto
{"type":"rectangle","id":"api","x":100,"y":80,"width":180,"height":80,
"roundness":{"type":3},"backgroundColor":"#a5d8ff","fillStyle":"solid",
"strokeColor":"#4a9eed","label":{"text":"API Gateway","fontSize":18}}
{"type":"arrow","id":"e1","from":"api","to":"db","label":{"text":"SQL"}} // enlace automático
{"type":"arrow","id":"e2","from":"api","to":"db","route":"ortho"} // en forma de L
{"type":"arrow","id":"e3","x":300,"y":150,"points":[[0,0],[120,0]]} // manual
{"type":"text","id":"ttl","center":400,"y":20,"text":"Título","fontSize":24} // centrado automático
{"type":"rectangle","id":"zone","x":40,"y":40,"width":700,"height":420,
"opacity":30,"zoneLabel":"Capa de datos"} // título, no etiqueta enlazada
Extensiones solo del constructor: from/to (anclajes de perímetro + enlace bidireccional),
route:"ortho", zoneLabel, center en texto, fixedWidth en una forma (ajuste de línea en lugar de
crecer). Todo lo demás se pasa sin cambios, por lo que el mismo array sigue funcionando
literalmente con create_view.
Nunca pongas una label enlazada en un rectángulo de zona de fondo — se centra en medio
de la zona y no se puede agarrar. Usa zoneLabel.
Elegir la salida
| Destino | Comando | Notas |
|---|---|---|
| Mostrar al usuario ahora | create_view | animado, guiado por cámara; devuelve checkpointId |
| Archivo en un repositorio | excalidraw_build.py -o x.excalidraw | se abre en excalidraw.com o en la extensión de VS Code |
| Bóveda de Obsidian | ... -o x --obsidian | .excalidraw.md, analizado por plugins, diffeable con git |
| Enlace compartible | mcp__excalidraw__export_to_excalidraw | sube a excalidraw.com — pregunta primero |
El MCP no tiene herramienta de archivos locales. export_to_excalidraw es una subida pública, así que trátala
como publicación: confirma con el usuario antes de llamarla.
Iteración
create_view devuelve un checkpointId. Para continuar desde él — incluyendo ediciones del usuario hechas en
pantalla completa — comienza el siguiente array con
{"type":"restoreCheckpoint","id":"<checkpointId>"} y agrega solo lo que es nuevo. Usa
{"type":"delete","ids":"a,b"} para eliminar elementos; nunca reutilices un id eliminado. Mantén el
archivo esqueleto en disco sincronizado, ya que ese archivo es lo que construye y limpia.
Referencias
references/file-format.md— el esquema de disco, verificado contra el código fuente original: códigos de fuente, texto enlazado, geometría de flechas, enlaces, lo que Excalidraw recalcula y lo que no al abrir. Léelo antes de editar manualmente cualquier archivo.excalidraw.references/mcp-workflow.md— coreografía de cámara, orden de transmisión, puntos de control, modo oscuro y los límites propios del MCP.references/layout-recipes.md— fórmulas para diseños de flujo, capas, carriles, secuencia, cuadrícula, radial y matriz, además de cómo mantener legible un diagrama de 60 elementos.references/obsidian.md— el envoltorio.excalidraw.md, reglas de block-ref y el problema de la escena comprimida.scripts/ensure_mcp.py— detecta y registra el servidor MCP de Excalidraw en cualquier sistema operativo.scripts/split_excalidraw_library.py— divide un.excalidrawlib(paquetes de iconos AWS/GCP/K8s de libraries.excalidraw.com) en JSON por icono más una tabla de búsqueda, para que los datos de iconos nunca entren en el contexto.
Límites que vale la pena declarar en voz alta
- Las estimaciones de ancho están calibradas por carácter, no medidas desde el binario de la fuente; el linter advierte dentro del 10% del desbordamiento. Cuando advierte sobre algo importante, renderízalo.
excalidraw_render.pynecesitaplaywrightmás acceso de red a esm.sh. Sin ellos, la limpieza sigue siendo totalmente sin conexión.- El linter no puede juzgar si un diagrama es bueno, solo si es correcto. La composición sigue siendo tu trabajo.
Registro de cambios
- 1.2.0 —
scripts/ensure_mcp.py: verificación previa multiplataforma que detecta el servidor MCP (incluyendo el mapa por proyecto de~/.claude.json) y lo registra cuando falta. Soporte para Windows: documentadopy -3, resolución declaude.cmd, UTF-8 explícito y saltos de línea\nen cada escritura. - 1.1.1 — el linter ya no aplica las reglas de ajuste de caja (R1/R2) a los contenedores de flechas; las etiquetas de flechas se colocan a lo largo de la trayectoria y están cubiertas por R10.
- 1.1.0 — movido al monorepo vskill en
skills/excalidraw-mcp/, coincidiendo conremotion-best-practicesy las otras habilidades dentro del repositorio. El repositorio independienteanton-abyzov/excalidraw-mcp-skillestá obsoleto. - 1.0.1 — documenta la configuración de MCP: instalar la habilidad no instala el servidor;
añadido el comando único
claude mcp addy lo que aún funciona sin él. - 1.0.0 — primera versión. Reemplaza la habilidad
excalidraw-diagram-generatorsolo de archivos, cuyas plantillas emitíantexten línea en las formas y, por lo tanto, se abrían como cajas vacías.