Skip to main content
Glama

Visual MCP

Сервер Model Context Protocol, который предоставляет LLM структурированный визуальный слой: он описывает что существует и получает чистую, точную SVG-диаграмму — вместо ASCII-арта.


What is Visual MCP?

Попросите любую LLM "нарисовать архитектуру" и вы получите это:

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

Символы рисования рамок — плохой носитель для пространственной информации. Выравнивание ломается, стрелки не доходят, ничего нельзя отредактировать впоследствии, и модель тратит рассуждения на подсчёт символов.

Очевидное исправление — "пусть модель пишет SVG" — ещё хуже. Тогда ей приходится вычислять viewBox, данные путей, полигоны наконечников стрелок, базовые линии текста и пересечения границ, всё вручную, без обратной связи, и всё заново с нуля, как только пользователь просит одно небольшое изменение.

Visual MCP убирает геометрию из задачи модели. Модель работает с графом сцены:

{
  "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" }
  ]
}

Обратите внимание, чего нет: нет координат, нет размеров, нет конечных точек линий, нет наконечников стрелок, нет SVG. Сервер вычисляет всё это — размеры узлов по меткам, позиции по графу соединений, рёбра, которые встречаются с границами, маркеры наконечников стрелок, перенос текста и viewBox, который не может обрезать.

И поскольку сцена — это граф со стабильными идентификаторами, следующий виток разговора — это правка в одну строку, а не перерисовка:

"Помести Redis над бэкендом, а PostgreSQL под ним." → update_element × 2, всё остальное нетронуто.

"Теперь помести всю инфраструктуру в коробку под названием AWS." → group_elements, и ничего не двигается.


Related MCP server: Mermaid MCP Server

Architecture

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

Five ideas hold this together

1. Граф сцены — это артефакт, SVG — только формат вывода. Всё, что отправляет модель, проверяется и сохраняется как Scene. Рендеринг — это чистая функция этой сцены, поэтому одна и та же диаграмма может быть позже перерендерена в другой теме или другим бэкендом без участия модели.

2. Семантические элементы компилируются в примитивы. database становится путём, эллипсом и двумя текстовыми блоками. connection становится путём с маркером. Рендерер видит только десять примитивов — это сохраняет его компактным и означает, что добавление neuron, decisionTree или functionPlot позже — это один файл расширения в src/semantic/, без изменений в объединении схемы, механизме компоновки или рендерере.

3. Один конвейер геометрии, два бэкенда. Реальный вывод рендерера — это дерево SvgNode, а не строка. serialize() превращает его в разметку для инструментов MCP; <SceneRenderer> отображает его в элементы React для UI. Нет второй реализации, которая могла бы разойтись, и нет dangerouslySetInnerHTML нигде в проекте.

4. Ошибки написаны для модели, а не для файла журнала.

{
  "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."
  }
}

Код для ветвления, предложение, которое называет проблему, и подсказка, содержащая ответ. Никогда не стек вызовов.

5. Каждая мутация атомарна. Отклонённое редактирование оставляет сохранённую сцену побайтово такой, какой она была. Без этого один неудачный вызов испортил бы диаграмму на весь остаток разговора.

Deviations from the originally sketched layout

  • src/layout/ — это собственный модуль, отдельный от src/semantic/. Позиционирование и расширение смысла в форму — разные задачи, и разделение позволяет заменить Dagre или ELK позже изменением одного файла (src/layout/flow.ts) — его интерфейс FlowItem in / centres out намеренно имеет форму, которую предоставляют эти библиотеки.

  • SvgNode находится между рендерером и его выводом (идея 3 выше), что позволяет React-представлению существовать без второго рендерера и без небезопасной вставки HTML.

  • src/mcp/widget.ts — это независимый ванильный просмотрщик без зависимостей, отдельный от React-приложения в src/ui/. Ресурс iframe для ChatGPT должен быть одной самодостаточной HTML-строкой без этапа сборки, который мог бы устареть или отсутствовать во время выполнения; React-приложение — это локальная игровая площадка. Они разделяют одно и то же поведение (масштабирование/панорамирование/подгонка/копирование/экспорт) и один и тот же список разрешённого.

  • Автоподгонка включена по умолчанию, поэтому width/height действуют как подсказки, а не как жёсткий холст. Это устраняет наиболее распространённый режим отказа — модель выбирает слишком маленький холст и обрезает собственную диаграмму.


Installation

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

Требуется Node 20+ (разработано на Node 22/26).


Development

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

Быстрая сквозная проверка на работающем сервере:

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

Он воспроизводит весь целевой разговор — построить диаграмму без координат, проверить её, переместить два узла, обернуть всё в коробку — и проверяет результат на каждом шаге.


Available MCP tools

Инструмент

Что делает

Когда модель должна к нему обратиться

render_diagram

Строит и рендерит всю сцену за один вызов, возвращает sceneId.

Любой запрос нарисовать, визуализировать, изобразить в виде диаграммы, проиллюстрировать или объяснить визуально. Точка входа по умолчанию.

render_scene

Перерендеривает сохранённую сцену.

После пакета правок, чтобы показать результат.

get_scene

Возвращает сцену плюс вычисленный прямоугольник каждого элемента.

Перед редактированием — особенно для относительных изменений ("немного правее").

add_element

Добавляет один элемент, опционально внутри группы.

"Добавить балансировщик нагрузки", "нарисовать стрелку от A к B".

update_element

Изменяет только указанные поля; null очищает одно.

Каждый запрос "изменить это". Никогда не перерисовывать для этого.

remove_element

Удаляет элемент, каскадно удаляя его соединения и метки.

"Удалить кеш".

group_elements

Оборачивает элементы верхнего уровня в помеченную коробку, ничего не перемещая.

"Помести всё это внутрь AWS", "сгруппируй это в VPC".

create_scene

Создаёт пустой холст.

Только при сборке большой диаграммы по частям.

clear_scene

Очищает сцену, сохраняя её холст/тему/заголовок.

"Выбрось это, давай начнём заново".

list_examples

Возвращает рабочие примеры сцен и каталог типов.

Когда не уверены, как что-то выразить — скопируйте и адаптируйте.

Каждое описание инструмента сообщает, что он делает, когда его использовать, когда не использовать, и что означает каждое свойство, потому что другая модель читает это и принимает решение самостоятельно. Инструменты только для чтения имеют readOnlyHint: true, а разрушительные — destructiveHint: true, которые хосты используют для решения, что требует подтверждения.


Scene schema

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[];
}

Каждый элемент имеет id и type. Идентификаторы стабильны и именно так работает диалоговое редактирование.

Primitives — what the renderer can draw

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

Semantic elements — what the model should actually use

Тип

Назначение

node

Помеченная коробка. Десять форм (rounded, circle, diamond, hexagon, cylinder, cloud, stack, screen, pill, rect). Размер определяется по метке; позиция определяется по соединениям.

connection

Ссылка по id: { from: "a", to: "b" }. Находит обе границы, добавляет наконечник стрелки, остаётся корректным при перемещении любого конца. Маршрутизация: straight, curved, orthogonal.

group

Помеченный контейнер с собственной компоновкой. Границы, такие как "AWS", "VLAN 10".

axis

Система координат и фрейм данных.

point / scatter / cluster / plotLine

Маркеры и линии в данных координатах при указании frame: "<axis id>". cluster генерирует детерминированное, посеянное облако точек.

label

Подпись, которая может быть прикреплена к другому элементу по id и следует за ним.

server database router switch computer cloud

Доменные предустановки — node с уже выбранной правильной формой и глифом.

Layout

layout: "auto" (по умолчанию) строит многослойный поток из графа соединений, если они есть, в противном случае — строку. Элементы с явными x/y никогда не перемещаются, поэтому модель может подтолкнуть один узел, не нарушая остальные. direction управляет направлением роста потока.

Data frames

axis объявляет отображение из единиц данных в пиксели; всё с frame: "<axis id>" размещается в координатах данных, при этом y растёт вверх, как и должно:

{ "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 }

Themes

Четыре встроенные темы (dark, light, blueprint, paper), каждая с полной палитрой и стеком шрифтов, который не требует внешних шрифтов. Элементы ссылаются на токены — primary, surface, muted, danger — а не на жёстко заданные цвета, поэтому вся диаграмма меняет стиль без изменения геометрии. themeOverrides изменяет любой токен.


Running locally

As a library, with no MCP at all

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" },
  ],
});

As an HTTP server

npm run dev:http

Route

POST /mcp

Конечная точка MCP Streamable HTTP

GET /health

проверка работоспособности

GET /scenes

сохранённые сцены

GET /scenes/:id.svg

отрендеренная сцена

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

интерактивный просмотрщик, автономный

Сервер не имеет состояния: каждый запрос получает свой собственный McpServer и транспорт, и хранилище сцен — единственное общее состояние. Именно это делает его безопасным за балансировщиком нагрузки или на бессерверной платформе, где два витка одного разговора могут не достичь одного и того же процесса.

As a stdio server (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"]
    }
  }
}

Connecting to ChatGPT

ChatGPT подключается к удалённым MCP-серверам через Streamable HTTP на публичной HTTPS-конечной точке, поэтому сервер должен быть доступен из интернета. Два способа:

A. Quick test with a tunnel

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

B. Deploy with Docker on a VPS

docker-compose.yml запускает два контейнера: MCP-сервер на порту 4000 (не опубликован в интернет) и Caddy, который терминирует TLS перед ним и автоматически обновляет сертификат.

На этом VPS уже работают другие сервисы на портах 80 и 443, поэтому:

Порт

Причина

HTTPS / MCP endpoint

500

443 занят

ACME HTTP-01 challenge

90

80 занят

MCP-сервер

4000

только внутренний, никогда не публикуется

Загвоздка: Let's Encrypt всегда подключается к порту 80 для HTTP-01 — это фиксировано RFC 8555 и не настраивается; TLS-ALPN также фиксирован на 443. Caddy может слушать на 90, но кто-то должен перенаправить запрос туда. Поэтому тот, кто уже владеет портом 80, должен перенаправлять путь challenge на Caddy.

1. Выберите публичное имя хоста. ChatGPT требует HTTPS, а голый IP не может иметь сертификат. Если у вас нет своего домена, используйте sslip.io — он разрешает <ip>.sslip.io в этот IP без регистрации, и Let's Encrypt выдаёт для него сертификаты:

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

2. Перенаправьте ACME challenge с сервера на порту 80. Определите его сначала:

sudo ss -lptn 'sport = :80'

nginx — внутри блока server { listen 80; }:

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

Apache — внутри <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 — внутри блока сайта, обслуживающего порт 80:

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

Используйте настоящий прокси, а не редирект 301: Let's Encrypt следует редиректам только на порты 80 и 443, поэтому редирект на :90 не сработает.

3. Настройте и запустите:

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

Если сервер на порту 80 работает внутри своего контейнера, а не на хосте, 127.0.0.1:90 из него недоступен — установите MCP_HTTP_BIND=0.0.0.0 в .env и укажите прокси на внутренний IP VPS (или поместите оба контейнера в одну сеть Docker).

4. Проверьте (первый запрос может занять несколько секунд, пока выпускается сертификат):

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

URL MCP будет https://<MCP_DOMAIN>:500/mcp, и он постоянен: restart: unless-stopped переживает перезагрузки, а сертификаты живут в томе caddy_data, поэтому обновления сохраняются между docker compose down/up. Только docker compose down -v удаляет их. Оставьте перенаправление challenge на месте — обновления каждые ~60 дней нуждаются в нём так же, как и первичная выдача.

PUBLIC_URL и ALLOWED_HOSTS выводятся из MCP_DOMAIN и MCP_HTTPS_PORT с помощью Compose. Оба должны содержать порт: PUBLIC_URL — потому что иначе ссылки svgUrl указывали бы на 443, а ALLOWED_HOSTS — потому что SDK сравнивает сырой заголовок Host (который на нестандартном порту выглядит как <domain>:500) как точную строку.

Если вы не можете трогать сервер на порту 80, HTTP-01 вообще недоступен. Варианты: DNS-01 challenge (требуется реальный домен на поддерживаемом DNS-провайдере — у sslip.io нет API) или Cloudflare Tunnel, которому не нужны входящие порты вообще.

Без 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

Затем направьте любой обратный прокси на http://127.0.0.1:4000. Контейнер запускается от непривилегированного пользователя node, имеет HEALTHCHECK /health и содержит только production-зависимости. Управляемые платформы (Fly.io, Railway, Render, Cloud Run) тоже работают — они подставляют свой PORT, который сервер учитывает.

Затем, в ChatGPT

  1. Включите режим разработчика. Он доступен в ChatGPT Business, Enterprise и Edu в веб-версии. Администратор включает его в Workspace Settings → Permissions & Roles → Connected Data → Developer mode / Create custom MCP connectors.

  2. Settings → Connectors → Create / Advanced → Developer mode → Add custom connector.

  3. Заполните:

    • Name: Visual MCP

    • MCP server URL: https://<your-host>/mcp

    • Authentication: No authentication (этот сервер поставляется без аутентификации — см. Безопасность)

  4. Сохраните. ChatGPT сразу вызывает tools/list; вы должны увидеть перечисленные десять инструментов.

  5. В новом чате включите коннектор и попросите диаграмму.

Сервер также регистрирует UI-ресурс MCP Apps (ui://visual-mcp/scene.html, text/html;profile=mcp-app), прикреплённый к инструментам рендеринга через _meta.ui.resourceUri и псевдоним ChatGPT _meta["openai/outputTemplate"]. Там, где это поддерживается, диаграмма отображается в интерактивном фрейме с масштабированием, панорамированием, подгонкой, копированием и экспортом; в остальных случаях инструменты всё равно возвращают SVG в structuredContent, поэтому сервер корректно деградирует.


Примеры

npm run examples рендерит все пять в examples/out/index.html, а list_examples подаёт их модели.

1. Сеть — examples/out/network.svg

Доменные пресеты и автоматическая компоновка слева направо. computer → switch → router → server, с подписями VLAN на соединениях. Никаких координат в исходной сцене.

2. LDA — examples/out/lda.svg

Фрейм данных axis, два инициализированных cluster с мягкими оболочками, пунктирная граница решения и направление LDA — всё в координатах данных, обе линии обрезаны по графику.

3. Регрессия — examples/out/regression.svg

Ось, серия scatter и подобранный plotLine с extend: true, на светлой теме.

4. Архитектура ПО — examples/out/architecture.svg

React → REST API → { Redis, PostgreSQL }, два хранилища внутри помеченной group («Слой данных»), в которую ведут соединения.

5. Бинарное дерево — examples/out/tree.svg

Семь круглых узлов и шесть соединений; слоистая компоновка, направленная down, даёт дерево.

Промпты для 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].

Безопасность

Модель угроз проста: всё, что отображает сервер, поступило от языковой модели, и этот вывод может содержать текст, который пользователь вставил откуда-то ещё. Поэтому ничто, полученное от модели, никогда не рассматривается как код.

  • Закрытая схема. Распознаются только двадцать четыре известных типа элементов. Цвета должны соответствовать грамматике hex/rgb/hsl/keyword/token — url(javascript:…) отклоняется при валидации. Данные пути должны соответствовать командам и числам SVG path, ничего другого.

  • Белый список вывода. Рендерер может выдавать только теги и атрибуты из двух явных списков в src/renderer/svgNode.ts. Нет on*, нет href, нет style, нет class, нет <foreignObject>, нет <script> — модель не может их выразить, а сериализатор в любом случае их отбросит.

  • Экранирование. Текстовое содержимое и значения атрибутов экранируются на выходе как XML.

  • Нет dangerouslySetInnerHTML, нет eval, нет new Function нигде в проекте. React-представление строит элементы из дерева SvgNode; виджет ChatGPT парсит SVG и перестраивает его узел за узлом, используя те же белые списки, так что даже скомпрометированный сервер не сможет внедрить скрипт в этот фрейм.

  • Ограниченный ввод. Количество элементов, длины строк, количество точек, длина пути и хранимые сцены — всё имеет лимиты; сцены удаляются по принципу «самые старые».

  • Нет стек-трейсов модели. Каждый обработчик обёрнут; любое неожиданное событие превращается в INTERNAL_ERROR с кратким сообщением.

Тесты в tests/security.test.tsx проверяют каждое из этих утверждений.

Не включено по замыслу: аутентификация. Сервер не раскрывает секретов и не взаимодействует с внешними системами, но публичное развёртывание — это публичное хранилище сцен. Поместите его за аутентификацией вашей платформы или добавьте OAuth через хелперы аутентификации SDK, прежде чем открывать кому-либо, кроме себя. Установите ALLOWED_HOSTS, чтобы включить защиту от DNS-ребондинга, когда сервер доступен из браузера.


Текущие ограничения

  • Метрики текста оцениваются, а не измеряются — на сервере нет движка шрифтов. Ширины находятся в пределах нескольких процентов для встроенных стеков без засечек, что достаточно для блоков и переносов, но необычный шрифт или много китайских/японских символов дадут небольшую погрешность.

  • Движок компоновки намеренно мал. Слои на основе самого длинного пути с центрированием рангов. В нём нет минимизации пересечений и разрешения наложений, поэтому плотный граф (примерно 25+ узлов с множеством перекрёстных связей) даст пересечения, которых настоящий движок избежал бы. Интерфейс оформлен по образу Dagre именно по этой причине.

  • Древовидные раскладки не центрированы по дочерним элементам; родитель находится в центре своего ранга, а не над серединой своих детей.

  • JSON Schema для render_diagram имеет размер около 50 КБ (~12k токенов), потому что она обучает всю лексику элементов. Остальные девять инструментов в сумме составляют ~5 КБ. Это осознанный компромисс: модель получает документацию по каждому полю и редко нуждается в повторном вызове для исправления.

  • Внутри группы с автоматической раскладкой явные x/y дочерних элементов игнорируются — раскладка имеет приоритет. Используйте layout: "manual" для группы, чтобы позиционировать детей самостоятельно.

  • Хранилище находится в памяти. Сцены не переживают перезапуск, а при наличии нескольких реплик сцена живёт на том экземпляре, который её создал. Интерфейс SceneStore существует, чтобы это можно было заменить одним классом.

  • Статический вывод. Пока нет анимации, 3D, парсера математических выражений — см. ниже.


План развития

Ближайшее

  • Постоянное SceneStore (сначала SQLite) — интерфейс уже готов.

  • Отмена/повтор. Каждая мутация уже записывается как SceneMutation; осталось хранить обратное действие.

  • Dagre или ELK за src/layout/flow.ts для плотных графов, с маленьким движком по умолчанию.

  • Древовидная раскладка с центрированием по дочерним элементам.

Математика — фрейм данных axis является основой; каждая из этих функций — один расширитель в src/semantic/, без изменений в рендерере: functionPlot ({ "expression": "x^2", "domain": [-5, 5] }), vector, matrix, plane, distribution, projection, decisionBoundary и regressionLine как именованные псевдонимы plotLine.

Словарь диаграммneuron, neuralNetwork, decisionTree, sequenceDiagram, stateMachine, gantt, swimlane.

Анимация{ "animation": { "type": "flow", "duration": 1200 } } на соединении, выводимая как SVG SMIL или CSS, чтобы оставаться декларативной и не требовать рантайма. Пакеты, движущиеся по ссылке, запрос, проходящий через конвейер, алгоритм, шагающий по структуре.

Другие рендереры — конвейер разрешения уже заканчивается деревом, не привязанным к бэкенду. Сцена с kind: "3d" и { "type": "sphere", "position": [0, 1, 0] } выберет бэкенд Three.js вместо SVG; бэкенд Canvas будет обслуживать очень большие точечные графики. Никаких изменений в слое MCP.


Лицензия

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