Skip to main content
Glama

nodered-mcp

MCP-сервер, который читает, запрашивает и редактирует flows.json Node-RED.

License CI Python

О проекте

Node-RED хранит все потоки, узлы, соединения и группы в одном большом JSON-файле. Редактирование вручную — или с помощью jq и sed — приводит к оборванным соединениям, группам, чьи рамки больше не покрывают собственные узлы, и новым узлам, наложенным поверх существующих.

Этот сервер предоставляет этот файл MCP-клиенту как небольшой набор инструментов, которые понимают формат. Он различает узел потока и конфигурационный узел, может проследить путь соединения и воспроизводит собственную геометрию редактора Node-RED, так что нарисованная им рамка группы совпадает с рамкой, которую нарисовал бы редактор.

Это порт пары flows_util.py / layout_util.py, использовавшейся для скриптовой правки Node-RED в репозитории домашней автоматизации, обобщённый так, что путь к файлу, имя контейнера и команда перезапуска настраиваются.

Related MCP server: nr-mcp

Возможности

  • Запросы — вкладки, группы, осиротевшие узлы, подпотоки, используемые сущности Home Assistant и трассировка соединений по потоку.

  • Редактирование — создание, обновление, удаление, переименование и дублирование узлов; соединение и разъединение; создание, заполнение и изменение стилей групп; импорт и экспорт наборов узлов.

  • Размещение — занимайте пустое полотно перед созданием узлов вместо угадывания координат, проверяйте полотно на пересечения и исправляйте наложения.

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

  • Две защиты, которые базовым скриптам не требовались: проверка компоновки, отказывающая в записи при новых пересечениях, и проверка устаревания, отказывающая перезаписывать flows.json, развёрнутый кем-то из браузера.

Требования

  • Python 3.11+

  • flows.json в локальной файловой системе

  • Docker в PATH — только для инструмента deploy, который копирует файл в контейнер и перезапускает его

Установка

git clone https://github.com/ljmerza/nodered-mcp
cd nodered-mcp
uv sync

Использование

Путь к flows.json — единственный обязательный параметр. Разумного значения по умолчанию нет, поэтому сервер отказывается запускаться без него.

uv run nodered-mcp --flows-path /path/to/nodered/data/flows.json

Регистрация в MCP-клиенте

{
  "mcpServers": {
    "nodered": {
      "type": "stdio",
      "command": "uv",
      "args": ["run", "--directory", "/path/to/nodered-mcp", "nodered-mcp"],
      "env": {
        "NODERED_FLOWS_PATH": "/path/to/nodered/data/flows.json"
      }
    }
  }
}

Полный пример см. в .mcp.json.example.

Конфигурация

Каждый параметр определяется по приоритету: флаг CLI > переменная окружения > значение по умолчанию.

Флаг

Переменная окружения

По умолчанию

Назначение

--flows-path

NODERED_FLOWS_PATH

(обязательно)

Путь к flows.json на хосте

--container

NODERED_CONTAINER

nodered

Имя контейнера, используемое deploy

--container-flows-path

NODERED_CONTAINER_FLOWS_PATH

/data/flows.json

Путь к flows.json внутри контейнера

--restart-cmd

NODERED_RESTART_CMD

docker restart <container>

Команда перезапуска; {container} подставляется

--transport

NODERED_MCP_TRANSPORT

stdio

stdio, http или sse

--host / --port

NODERED_MCP_HOST / NODERED_MCP_PORT

127.0.0.1 / 8080

Адрес привязки для http и sse

Если Node-RED управляется не обычным Docker, укажите --restart-cmd:

NODERED_RESTART_CMD="docker compose restart {container}"

Инструменты

Семь инструментов, каждый диспетчеризуется по аргументу op.

Инструмент

Операции

nodered_query

summary, tabs, groups, tab, group, search, ungrouped, orphans, subflows, styles, entities, inspect, connections, trace

nodered_find_nodes

Структурированный поиск по вкладке, типу или подстроке имени

nodered_get_node

Сырой JSON одного узла плюс контекст соединений

nodered_edit

create_node, update_node, delete_node, rename_node, duplicate_node, wire, unwire, import_nodes, export_group

nodered_group

create, add, move_node, rename, set_style, normalize_styles, refit, shift, bounds

nodered_layout

check, free_region, occupied, fix

nodered_session

status, save, deploy, reload

Типичная сборка

nodered_query(op="tabs")                                   -> tab ids
nodered_layout(op="free_region", tab_id=TAB, w=800, h=200) -> {"x": 100, "y": 3240}
nodered_edit(op="create_node", tab_id=TAB, node_type="inject",
             name="tick", x=100, y=3240)                   -> node id
nodered_edit(op="create_node", tab_id=TAB, node_type="switch",
             name="gate", x=300, y=3240)                   -> node id
nodered_edit(op="wire", source_id=..., target_id=...)
nodered_group(op="create", name="My Flow", tab_id=TAB, node_ids=[...])
nodered_session(op="save")

Ничто из вышеперечисленного не касается flows.json до финального save.

Как сервер защищает файл

Проверка компоновки

save и deploy проверяют полотно до и после вашей правки и отказываются записывать, если правка вносит новую ошибку уровня error:

Находка

Уровень

Значение

group-overlap

error

Рамка группы попала на другую рамку группы

group-escape

error

Рамка группы больше не покрывает свои узлы

stray-in-group

warning

Узел находится внутри рамки группы, но не является её членом

node-overlap

warning

Два узла занимают одно и то же пространство

Проблемы, уже существовавшие на диске, никогда не блокируют — только те, что создала ваша правка. Когда проверка срабатывает, обычно помогает одно из:

  • nodered_layout(op="free_region") — занять свободное полотно, затем разместить там

  • nodered_group(op="refit", group_id=...) — изменить размер группы вокруг её узлов

  • nodered_session(op="save", allow_overlap=true) — если наложение намеренное

Геометрия групп точна: правила расчёта размеров перенесены из редактора Node-RED, поэтому вычисленная рамка совпадает с тем, что рисует редактор. Геометрия узлов точна, за исключением ширины текста метки, которая аппроксимируется по метрикам Helvetica — поэтому находки на уровне узлов всегда только предупреждения.

Проверка устаревания

Node-RED перезаписывает flows.json при каждом нажатии Deploy в браузере. Сессия записывает (mtime_ns, size) при загрузке файла и перепроверяет перед каждой записью. Если файл изменился под вами, фиксация отклоняется, а не молча откатывает вашу работу. Либо выполните reload и повторите правки, либо передайте force=true.

Наносекунды, а не os.path.getmtime: эпоха с плавающей точкой даёт точность примерно до микросекунды, поэтому запись, попавшая в тот же такт, что и загрузка, сравнивается как равная и проскальзывает мимо проверки.

Автономное использование

Оба модуля движка работают как библиотеки и CLI, независимо от MCP.

uv run python -m nodered_mcp.flows summary --flows-path /path/to/flows.json
uv run python -m nodered_mcp.layout --path /path/to/flows.json --fix boxes,move
from nodered_mcp.flows import Flows

f = Flows("/path/to/flows.json")
ox, oy = f.free_region(tab_id, w=1600, h=300)
f.create_node(tab_id, "inject", "tick", x=ox, y=oy)
f.save()

--fix boxes в одиночку делает хуже: пересчёт размеров увеличивает некоторые рамки, так что они поглощают соседние узлы, не входящие в группу. Запускайте boxes,move вместе и читайте пробный прогон перед --apply.

Структура проекта

src/nodered_mcp/
├── server.py       FastMCP server: the seven tools
├── session.py      in-memory session, stdout capture, staleness guard
├── config.py       CLI flags and environment resolution
├── flows.py        the Flows class, composed from the mixins below
├── constants.py    defaults, the group style, LayoutError
├── reports.py      ReadMixin      — summary, tab, group, search, trace
├── nodes.py        NodeEditMixin  — create/update/delete/wire nodes
├── groups.py       GroupMixin     — create and populate group boxes
├── placement.py    LayoutMixin    — claim free canvas, measure and refit boxes
├── transfer.py     TransferMixin  — import and export node sets
├── persist.py      PersistMixin   — save, deploy, and the layout gate
└── layout.py       canvas geometry and linter, ported from the NR editor

Flows объединяет миксины, поэтому публичный API остаётся плоским: f.summary(), f.create_node(), f.free_region(), f.save().

Разработка

uv sync --group dev
uv run pytest                    # 49 tests
uv run ruff check .
uv run ruff format --check .

Тесты запускаются на синтетическом фикстуре в tests/fixtures/, никогда на реальном файле flows. Они покрывают приоритет конфигурации, инструменты чтения, семантику «в памяти до сохранения», проверку компоновки (и блокировку, и переопределение), защиту от устаревания, последовательность команд deploy и то, что ни один инструмент не пишет в stdout — случайный print нарушил бы фрейминг stdio MCP.

CI запускает те же проверки через ljmerza/misc-actions.

Вклад

Приветствуются issues и pull request. Пожалуйста, поддерживайте ruff check, ruff format и pytest зелёными.

Благодарности

  • Node-RED — геометрия полотна здесь перенесена из его клиента редактора, поэтому рамки групп совпадают с тем, что рисует редактор.

  • FastMCP — фреймворк MCP-сервера.

Лицензия

MIT. См. LICENSE.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Minimal MCP server wrapping the Node-RED admin API, enabling flow management, node installation, and context retrieval via natural language.
    265 npm
    MIT