Skip to main content
Glama

Visual MCP

Un servidor del Protocolo de Contexto de Modelo (MCP) que proporciona a un LLM una capa visual estructurada: describe lo que existe y recibe a cambio un diagrama SVG limpio y preciso — en lugar de arte ASCII.


¿Qué es Visual MCP?

Pídele a cualquier LLM que "dibuje la arquitectura" y obtienes esto:

+----------+      +---------+      +------------+
|  React   |----->| NestJS  |----->| PostgreSQL |
+----------+      +---------+      +------------+
                       |
                       +-----> Redis?

Los caracteres de dibujo de recuadros son un mal medio para la información espacial. La alineación se rompe, las flechas no llegan, nada se puede editar después, y el modelo consume razonamiento contando caracteres.

La solución obvia — "dejar que el modelo escriba SVG" — es peor. Entonces tiene que calcular viewBoxes, datos de trayectoria, polígonos de punta de flecha, líneas base de texto e intersecciones de bordes, todo a mano, todo sin retroalimentación, y todo de nuevo desde cero en cuanto el usuario pide un pequeño cambio.

Visual MCP elimina la geometría del trabajo del modelo. El modelo trabaja con un grafo de escena:

{
  "title": "Service architecture",
  "elements": [
    { "id": "frontend", "type": "node",     "label": "React" },
    { "id": "backend",  "type": "node",     "label": "NestJS" },
    { "id": "db",       "type": "database", "label": "PostgreSQL" },
    { "id": "cache",    "type": "database", "label": "Redis" },

    { "id": "c1", "type": "connection", "from": "frontend", "to": "backend" },
    { "id": "c2", "type": "connection", "from": "backend",  "to": "db" },
    { "id": "c3", "type": "connection", "from": "backend",  "to": "cache" }
  ]
}

Nota lo que no está: sin coordenadas, sin tamaños, sin puntos finales de línea, sin puntas de flecha, sin SVG. El servidor lo calcula todo — tamaños de los nodos a partir de las etiquetas, posiciones a partir del grafo de conexiones, bordes que encuentran los límites, marcadores de punta de flecha, ajuste de texto, y un viewBox que no puede recortar.

Y como la escena es un grafo con identificadores estables, el siguiente turno de la conversación es una edición de una línea en lugar de un redibujado:

"Pon Redis encima del backend y PostgreSQL debajo de él." → update_element × 2, todo lo demás intacto.

"Ahora pon toda la infraestructura dentro de una caja llamada AWS." → group_elements, y nada se mueve.


Related MCP server: Mermaid MCP Server

Arquitectura

ChatGPT
   │  tool call: render_diagram / update_element / …
   ▼
MCP server            src/mcp/         (transport, tools, error shaping)
   │
   ▼
Scene graph           src/scene/       (Zod schemas, validation, store, mutations)
   │
   ├─▶ layout         src/layout/      (sizes and positions for elements with no coordinates)
   ├─▶ semantic       src/semantic/    (node/connection/axis/… ▸ primitives)
   │
   ▼
SvgNode tree          src/renderer/    (closed, allow-listed representation of an SVG document)
   │
   ├─▶ toSvgString()  ─────────────────▶  SVG returned by the MCP tools
   └─▶ <SceneRenderer> ────────────────▶  React, for the interactive UI

Cinco ideas lo sostienen

1. El grafo de escena es el artefacto, SVG es solo un formato de salida. Todo lo que el modelo envía se valida en una Scene y se almacena. El renderizado es una función pura de esa escena, por lo que el mismo diagrama se puede volver a renderizar más tarde con un tema diferente, o con un backend diferente, sin que el modelo intervenga.

2. Los elementos semánticos se compilan en primitivas. database se convierte en un trazado, una elipse y dos bloques de texto. connection se convierte en un trazado con un marcador. El renderizador solo ve las diez primitivas — lo que lo mantiene pequeño, y significa que añadir neuron, decisionTree o functionPlot más tarde es un archivo de expansión en src/semantic/, sin cambiar la unión del esquema, el motor de diseño o el renderizador.

3. Un pipeline de geometría, dos backends. La salida real del renderizador es un árbol SvgNode, no una cadena. serialize() lo convierte en marcado para las herramientas MCP; <SceneRenderer> lo mapea a elementos React para la interfaz de usuario. No hay una segunda implementación que pueda desviarse, y no hay dangerouslySetInnerHTML en ningún lugar del proyecto.

4. Los errores están escritos para un modelo, no para un archivo de registro.

{
  "success": false,
  "error": {
    "code": "ELEMENT_NOT_FOUND",
    "message": "Connection 'c1' points to 'router-2' (to), which does not exist in the scene.",
    "path": "c1.to",
    "hint": "Existing elements you can connect: pc, switch, router-1, server."
  }
}

Un código para bifurcar, una frase que nombra el problema, y una pista que contiene la respuesta. Nunca un rastreo de pila.

5. Cada mutación es atómica. Una edición rechazada deja la escena almacenada byte por byte como estaba. Sin eso, una mala llamada corrompería el diagrama para el resto de la conversación.

Desviaciones del diseño originalmente esbozado

  • src/layout/ es su propio módulo, separado de src/semantic/. El posicionamiento y la expansión de significado a forma son problemas diferentes, y la división es lo que permite intercambiar Dagre o ELK más tarde con un cambio en un solo archivo (src/layout/flow.ts) — su interfaz FlowItem in / centres out es deliberadamente la forma que exponen esas bibliotecas.

  • SvgNode se sitúa entre el renderizador y su salida (idea 3 anterior), que es lo que permite que la vista React exista sin un segundo renderizador y sin inyección insegura de HTML.

  • src/mcp/widget.ts es un visor vanilla sin dependencias, separado de la aplicación React en src/ui/. El recurso de iframe de ChatGPT debe ser una única cadena HTML autocontenida sin paso de compilación que podría estar desactualizada o faltante en tiempo de ejecución; la aplicación React es el playground local. Comparten el mismo comportamiento (zoom/pan/ajustar/copiar/exportar) y la misma lista de permitidos.

  • El ajuste automático está activado por defecto, por lo que width/height actúan como sugerencias en lugar de un lienzo fijo. Esto elimina el modo de fallo más común: un modelo eligiendo un lienzo demasiado pequeño y recortando su propio diagrama.


Instalación

git clone <this repo>
cd visual-mcp
npm install

Requiere Node 20+ (desarrollado en Node 22/26).


Desarrollo

npm run dev:http      # MCP server over Streamable HTTP on http://localhost:3333/mcp
npm run dev:stdio     # MCP server over stdio (Claude Desktop, MCP Inspector, tunnels)
npm run dev:ui        # React playground on http://localhost:5180
npm test              # 128 tests
npm run typecheck
npm run build         # server → dist/
npm run build:ui      # playground → dist-ui/
npm run examples      # render the reference scenes → examples/out/index.html

Comprobación rápida extremo a extremo contra un servidor en ejecución:

npm run dev:http &
npx tsx scripts/smoke-mcp.ts

Reproduce toda la conversación objetivo: construir un diagrama sin coordenadas, inspeccionarlo, mover dos nodos, envolver todo en una caja — y verifica el resultado en cada paso.


Herramientas MCP disponibles

Herramienta

Qué hace

Cuándo el modelo debe usarla

render_diagram

Construye y renderiza una escena completa en una llamada, devuelve un sceneId.

Cualquier solicitud de dibujar, visualizar, diagramar, ilustrar o explicar visualmente. El punto de entrada por defecto.

render_scene

Vuelve a renderizar una escena almacenada.

Después de un lote de ediciones, para mostrar el resultado.

get_scene

Devuelve la escena más la caja calculada de cada elemento.

Antes de editar — especialmente para cambios relativos ("un poco a la derecha").

add_element

Añade un elemento, opcionalmente dentro de un grupo.

"Añadir un balanceador de carga", "dibujar una flecha de A a B".

update_element

Cambia solo los campos dados; null borra uno.

Cada solicitud de "cambia eso". Nunca redibujar para esto.

remove_element

Elimina un elemento, eliminando en cascada sus conexiones y etiquetas.

"Eliminar la caché".

group_elements

Envuelve elementos de nivel superior en una caja etiquetada, sin mover nada.

"Poner todo esto dentro de AWS", "agrupar estos en una VPC".

create_scene

Crea un lienzo vacío.

Solo cuando se ensambla un diagrama grande de forma incremental.

clear_scene

Vacía una escena, manteniendo su lienzo/tema/título.

"Desecha eso, empecemos de nuevo".

list_examples

Devuelve escenas de ejemplo funcionales y el catálogo de tipos.

Cuando no se está seguro de cómo expresar algo — copiar y adaptar.

Cada descripción de herramienta indica qué hace, cuándo usarla, cuándo no, y qué significa cada propiedad, porque otro modelo lee estas y decide por sí mismo. Las herramientas de solo lectura llevan readOnlyHint: true y las destructivas destructiveHint: true, que los anfitriones usan para decidir qué necesita confirmación.


Esquema de la escena

interface Scene {
  id?: string;
  title?: string;
  subtitle?: string;
  width?: number;          // hint; autoFit grows the canvas so nothing is clipped
  height?: number;
  autoFit?: boolean;       // default true
  background?: string;
  theme?: "dark" | "light" | "blueprint" | "paper";
  themeOverrides?: Partial<Theme>;
  layout?: "auto" | "layered" | "horizontal" | "vertical" | "grid" | "manual";
  direction?: "right" | "down" | "left" | "up";
  gap?: number;
  padding?: number;
  legend?: boolean;
  elements: VisualElement[];
}

Cada elemento tiene id y type. Los ids son estables y son como funciona la edición conversacional.

Primitivas — lo que el renderizador puede dibujar

circle · ellipse · rectangle · line · arrow · text · polygon · polyline · path · group

Elementos semánticos — lo que el modelo debería usar realmente

Tipo

Propósito

node

Caja etiquetada. Diez formas (rounded, circle, diamond, hexagon, cylinder, cloud, stack, screen, pill, rect). Se autoajusta a partir de la etiqueta; se posiciona a partir de las conexiones.

connection

Enlace por id: { from: "a", to: "b" }. Encuentra ambos bordes, añade la punta de flecha, se mantiene correcto cuando cualquiera de los extremos se mueve. Enrutamiento: straight, curved, orthogonal.

group

Contenedor etiquetado con su propio diseño. Límites como "AWS", "VLAN 10".

axis

Un sistema de coordenadas y un marco de datos.

point / scatter / cluster / plotLine

Marcadores y líneas en coordenadas de datos cuando se les da frame: "<axis id>". cluster genera un conjunto de puntos determinista y con semilla.

label

Leyenda que se puede adjuntar a otro elemento por id y lo sigue.

server database router switch computer cloud

Preajustes de dominio — un node con la forma y el glifo correctos ya seleccionados.

Diseño

layout: "auto" (el valor por defecto) construye un flujo en capas a partir del grafo de conexiones cuando hay alguna, de lo contrario una fila. Los elementos con x/y explícitos nunca se mueven, por lo que el modelo puede mover un nodo sin perturbar el resto. direction controla en qué dirección crece el flujo.

Marcos de datos

Un axis declara un mapeo de unidades de datos a píxeles; cualquier cosa con frame: "<axis id>" se coloca en coordenadas de datos, con y creciendo hacia arriba como debería:

{ "id": "plot",  "type": "axis",    "x": 90, "y": 70, "width": 620, "height": 420,
  "xRange": [0, 10], "yRange": [0, 10], "xLabel": "Feature 1", "yLabel": "Feature 2" },
{ "id": "class-a", "type": "cluster", "frame": "plot", "x": 3.4, "y": 6.6,
  "count": 40, "spread": 0.8, "label": "Class A", "hull": true, "seed": 7 }

Temas

Cuatro temas integrados (dark, light, blueprint, paper), cada uno con una paleta completa más una pila de fuentes que no requiere fuentes externas. Los elementos se refieren a tokens — primary, surface, muted, danger — en lugar de colores fijos, por lo que todo un diagrama se reestiliza sin tocar su geometría. themeOverrides cambia cualquier token.


Ejecución local

Como biblioteca, sin MCP en absoluto

import { renderScene } from "visual-mcp";

const svg = renderScene({
  title: "Request flow",
  elements: [
    { id: "client", type: "computer", label: "Client" },
    { id: "api", type: "server", label: "API" },
    { id: "c", type: "connection", from: "client", to: "api", label: "HTTPS" },
  ],
});

Como servidor HTTP

npm run dev:http

Ruta

POST /mcp

Endpoint MCP HTTP Streamable

GET /health

verificación de salud

GET /scenes

escenas almacenadas

GET /scenes/:id.svg

una escena renderizada

GET /viewer?svg=/scenes/:id.svg

el visor interactivo, independiente

El servidor es sin estado: cada solicitud obtiene su propio McpServer y transporte, y el almacén de escenas es el único estado compartido. Eso es lo que lo hace seguro detrás de un balanceador de carga o en una plataforma serverless, donde dos turnos de una conversación pueden no llegar al mismo proceso.

Como servidor stdio (MCP Inspector, Claude Desktop, Cursor)

npx @modelcontextprotocol/inspector npx tsx src/mcp/stdio.ts
{
  "mcpServers": {
    "visual-mcp": {
      "command": "node",
      "args": ["/absolute/path/to/visual-mcp/dist/mcp/stdio.js"]
    }
  }
}

Conexión a ChatGPT

ChatGPT se conecta a servidores MCP remotos a través de HTTP Streamable en un endpoint HTTPS público, por lo que el servidor debe ser accesible desde internet. Dos formas:

A. Prueba rápida con un túnel

npm run dev:http                  # http://localhost:3333/mcp
npx localtunnel --port 3333       # or: ngrok http 3333, or cloudflared tunnel

B. Desplegar con Docker en un VPS

docker-compose.yml ejecuta dos contenedores: el servidor MCP en el puerto 4000 (no publicado en internet) y Caddy, que termina TLS al frente y renueva el certificado automáticamente.

Este VPS ya tiene otros servicios en los puertos 80 y 443, por lo tanto:

Puerto

Motivo

HTTPS / Endpoint MCP

500

443 está ocupado

Desafío ACME HTTP-01

90

80 está ocupado

Servidor MCP

4000

solo interno, nunca publicado

El problema: Let's Encrypt siempre se conecta al puerto 80 para HTTP-01 — eso está fijado por RFC 8555 y no se puede configurar — y TLS-ALPN también está fijado al 443. Caddy puede escuchar en el 90, pero algo debe llevar la solicitud hasta allí. Así que lo que ya posea el puerto 80 debe reenviar la ruta del desafío a Caddy.

1. Elige un nombre de host público. ChatGPT requiere HTTPS, y una IP desnuda no puede tener un certificado. Sin un dominio propio, usa sslip.io — resuelve <ip>.sslip.io a esa IP sin registro, y Let's Encrypt emite certificados para ello:

curl -4 ifconfig.me            # on the VPS -> e.g. 203.0.113.45
# hostname becomes: 203.0.113.45.sslip.io

2. Reenvía el desafío ACME desde el servidor del puerto 80. Identifícalo primero:

sudo ss -lptn 'sport = :80'

nginx — dentro del bloque server { listen 80; }:

location /.well-known/acme-challenge/ {
    proxy_pass http://127.0.0.1:90;
    proxy_set_header Host $host;
}

Apache — dentro del <VirtualHost *:80>:

ProxyPreserveHost On
ProxyPass        /.well-known/acme-challenge/ http://127.0.0.1:90/.well-known/acme-challenge/
ProxyPassReverse /.well-known/acme-challenge/ http://127.0.0.1:90/.well-known/acme-challenge/

Caddy — dentro del bloque del sitio que sirve el puerto 80:

handle /.well-known/acme-challenge/* {
    reverse_proxy 127.0.0.1:90
}

Usa un proxy real, no una redirección 301: Let's Encrypt sigue redirecciones solo a los puertos 80 y 443, por lo que una redirección a :90 fallaría.

3. Configura e inicia:

cp .env.example .env
# MCP_DOMAIN=203.0.113.45.sslip.io
docker compose up -d --build

Si el servidor del puerto 80 se ejecuta dentro de su propio contenedor en lugar de en el host, 127.0.0.1:90 no es accesible desde él — establece MCP_HTTP_BIND=0.0.0.0 en .env y apunta el proxy a la IP interna del VPS (o coloca ambos contenedores en una misma red de Docker).

4. Verifica (la primera solicitud puede tardar unos segundos mientras se emite el certificado):

curl https://$MCP_DOMAIN:500/health       # {"status":"ok",...}
docker compose logs caddy | grep -i "certificate obtained"

La URL MCP es entonces https://<MCP_DOMAIN>:500/mcp, y es permanente: restart: unless-stopped sobrevive a reinicios, y los certificados viven en el volumen caddy_data, por lo que las renovaciones persisten a través de docker compose down/up. Solo docker compose down -v los elimina. Mantén el reenvío del desafío activo — las renovaciones cada ~60 días lo necesitan tanto como la primera emisión.

PUBLIC_URL y ALLOWED_HOSTS se derivan de MCP_DOMAIN y MCP_HTTPS_PORT mediante Compose. Ambos deben llevar el puerto: PUBLIC_URL porque los enlaces svgUrl apuntarían al 443 de lo contrario, y ALLOWED_HOSTS porque el SDK compara el encabezado Host sin procesar — que lee <domain>:500 en un puerto no estándar — como una cadena exacta.

Si no puedes tocar el servidor del puerto 80, HTTP-01 no está disponible en absoluto. Las opciones son un desafío DNS-01 (necesita un dominio real en un proveedor de DNS compatible — sslip.io no tiene API), o un Cloudflare Tunnel, que no necesita puertos de entrada.

Sin Compose

docker build -t visual-mcp .
docker run -d --name visual-mcp --restart unless-stopped -p 127.0.0.1:4000:4000 \
  -e PUBLIC_URL=https://your-host -e ALLOWED_HOSTS=your-host visual-mcp

Luego apunta cualquier proxy inverso a http://127.0.0.1:4000. El contenedor se ejecuta como el usuario no root node, incluye un HEALTHCHECK /health y solo lleva dependencias de producción. Las plataformas gestionadas (Fly.io, Railway, Render, Cloud Run) también funcionan — inyectan su propio PORT, que el servidor respeta.

Luego, en ChatGPT

  1. Activa el modo desarrollador. Está disponible en ChatGPT Business, Enterprise y Edu en la web. Un administrador lo activa en Configuración del espacio de trabajo → Permisos y roles → Datos conectados → Modo desarrollador / Crear conectores MCP personalizados.

  2. Configuración → Conectores → Crear / Avanzado → Modo desarrollador → Añadir conector personalizado.

  3. Rellena:

    • Nombre: Visual MCP

    • URL del servidor MCP: https://<tu-host>/mcp

    • Autenticación: Sin autenticación (este servidor se envía sin autenticación — ver Seguridad)

  4. Guarda. ChatGPT llama a tools/list inmediatamente; deberías ver los diez herramientas listadas.

  5. En un nuevo chat, activa el conector y pide un diagrama.

El servidor también registra un recurso MCP Apps UI (ui://visual-mcp/scene.html, text/html;profile=mcp-app), adjunto a las herramientas de renderizado a través de _meta.ui.resourceUri y el alias de ChatGPT _meta["openai/outputTemplate"]. Donde sea compatible, el diagrama aparece en un marco interactivo con zoom, desplazamiento, ajuste, copia y exportación; en otros lugares, las herramientas aún devuelven el SVG en structuredContent, por lo que el servidor degrada con elegancia.


Ejemplos

npm run examples renderiza los cinco en examples/out/index.html, y list_examples los sirve al modelo.

1. Red — examples/out/network.svg

Preajustes de dominio y diseño automático de izquierda a derecha. computer → switch → router → server, con subtítulos de VLAN en los enlaces. Sin coordenadas en ninguna parte de la escena fuente.

2. LDA — examples/out/lda.svg

Un marco de datos axis, dos clusters sembrados con contornos suaves, un límite de decisión discontinuo y la dirección LDA — todo en coordenadas de datos, ambas líneas recortadas al gráfico.

3. Regresión — examples/out/regression.svg

Eje, una serie scatter y un plotLine ajustado con extend: true, en el tema claro.

4. Arquitectura de software — examples/out/architecture.svg

React → REST API → { Redis, PostgreSQL }, con los dos almacenes dentro de un group etiquetado ("Capa de datos") al que las conexiones se dirigen.

5. Árbol binario — examples/out/tree.svg

Siete nodos circulares y seis conexiones; el diseño en capas que fluye down produce el árbol.

Indicaciones para probar en ChatGPT

Draw the architecture where React talks to NestJS, NestJS uses PostgreSQL and also queries Redis.
Now put Redis above the backend and the database below it.
Now put all the infrastructure inside a box called AWS.
Make PostgreSQL bigger and give it a purple border.

Explain Linear Discriminant Analysis visually.
Show me graphically how linear regression works.
Draw a network where a PC in VLAN 20 reaches a server in VLAN 10 through a switch and a router.
Draw a balanced binary tree with 7 nodes.
Explain the TCP three-way handshake as a diagram.
Diagram merge sort on [5, 2, 9, 1].

Seguridad

El modelo de amenazas es simple: todo lo que el servidor renderiza se originó en un modelo de lenguaje, y esa salida puede contener texto que el usuario pegó de otro lugar. Por lo tanto, nada derivado del modelo se trata nunca como código.

  • Esquema cerrado. Solo se analizan los veinticuatro tipos de elementos conocidos. Los colores deben coincidir con una gramática de hex/rgb/hsl/keyword/token — url(javascript:…) se rechaza en la validación. Los datos de ruta deben coincidir con comandos y números de ruta SVG, nada más.

  • Lista blanca de salida. El renderizador solo puede emitir etiquetas y atributos de dos listas explícitas en src/renderer/svgNode.ts. No hay on*, no hay href, no hay style, no hay class, no hay <foreignObject>, no hay <script> — el modelo no puede expresarlos, y el serializador los descartaría de todos modos.

  • Escapado. El contenido de texto y los valores de atributos se escapan en XML a la salida.

  • Sin dangerouslySetInnerHTML, sin eval, sin new Function en ningún lugar del proyecto. La vista React construye elementos a partir del árbol SvgNode; el widget de ChatGPT analiza el SVG y lo reconstruye nodo por nodo contra las mismas listas blancas, por lo que incluso un servidor comprometido no puede introducir scripts en ese marco.

  • Entrada acotada. Los recuentos de elementos, longitudes de cadenas, recuentos de puntos, longitud de ruta y escenas almacenadas están todos limitados; las escenas se eliminan las más antiguas primero.

  • Sin trazas de pila para el modelo. Cada manejador está envuelto; cualquier cosa inesperada se convierte en INTERNAL_ERROR con un mensaje corto.

Las pruebas en tests/security.test.tsx afirman cada uno de estos.

No incluido, por diseño: autenticación. El servidor no expone secretos ni toca ningún sistema externo, pero una implementación pública es un almacén de escenas público. Ponlo detrás de la autenticación de tu plataforma, o añade OAuth a través de los ayudantes de autenticación del SDK, antes de exponerlo a nadie más que a ti mismo. Establece ALLOWED_HOSTS para activar la protección contra el rebote de DNS cuando sea accesible desde un navegador.


Limitaciones actuales

  • Las métricas de texto se estiman, no se miden — no hay un motor de fuentes en el servidor. Los anchos están dentro de unos pocos por ciento para las pilas sans-serif incluidas, lo que es suficiente para cuadros y ajuste de línea, pero una fuente inusual o mucho CJK se ajustarán ligeramente sueltos.

  • El motor de diseño es intencionalmente pequeño. Capas de ruta más larga con centrado de rango. No tiene minimización de cruces ni resolución de superposición, por lo que un gráfico denso (aproximadamente 25+ nodos con muchos enlaces cruzados) producirá cruces que un motor real evitaría. La interfaz tiene forma de Dagre precisamente por esta razón.

  • Los diseños de árbol no están centrados en los hijos; un padre se sienta en el centro de su rango, no sobre el punto medio de sus hijos.

  • El esquema JSON de render_diagram tiene aproximadamente 50 KB (~12k tokens) porque enseña todo el vocabulario de elementos. Las otras nueve herramientas suman ~5 KB. Eso es una compensación deliberada: el modelo obtiene documentación por campo y rara vez necesita un viaje de ida y vuelta de reparación.

  • Dentro de un grupo con diseño automático, las coordenadas x/y explícitas de los hijos se ignoran — el diseño gana. Usa layout: "manual" en el grupo para posicionar a los hijos tú mismo.

  • El almacenamiento está en memoria. Las escenas no sobreviven a un reinicio, y con múltiples réplicas una escena vive en la instancia que la creó. La interfaz SceneStore existe para que esta sea una clase a reemplazar.

  • Salida estática. Sin animación, sin 3D, sin analizador de expresiones matemáticas todavía — ver más abajo.


Hoja de ruta

Próximo

  • SceneStore persistente (SQLite primero) — la interfaz ya está en su lugar.

  • Deshacer/rehacer. Cada mutación ya se registra como una SceneMutation; esto es cuestión de almacenar la inversa.

  • Dagre o ELK detrás de src/layout/flow.ts para gráficos densos, con el motor pequeño como predeterminado.

  • Diseño de árbol centrado en los hijos.

Matemáticas — el marco de datos axis es la base; cada uno de estos es un expansor en src/semantic/, sin cambio en el renderizador: functionPlot ({ "expression": "x^2", "domain": [-5, 5] }), vector, matrix, plane, distribution, projection, decisionBoundary y regressionLine como alias nombrados de plotLine.

Vocabulario de diagramasneuron, neuralNetwork, decisionTree, sequenceDiagram, stateMachine, gantt, swimlane.

Animación{ "animation": { "type": "flow", "duration": 1200 } } en una conexión, emitido como SVG SMIL o CSS para que siga siendo declarativo y no necesite tiempo de ejecución. Paquetes moviéndose a lo largo de un enlace, una solicitud viajando a través de una tubería, un algoritmo avanzando a través de una estructura.

Otros renderizadores — la tubería de resolución ya termina en un árbol agnóstico del backend. Una Scene con kind: "3d" y { "type": "sphere", "position": [0, 1, 0] } seleccionaría un backend Three.js en lugar del SVG; un backend Canvas serviría gráficos de dispersión muy grandes. Sin cambio en la capa MCP.


Licencia

MIT

Install Server
F
license - not found
A
quality
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • A comprehensive Model Context Protocol (MCP) server that enables AI assistants to interact with yo…

  • A Model Context Protocol server for Wix AI tools

  • MCP (Model Context Protocol) server for Appwrite

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/daniel69zz/visual_draw_mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server