nodered-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@nodered-mcpCheck for orphaned nodes in my flows"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
nodered-mcp
An MCP server that reads, queries, and edits a Node-RED flows.json.
About
Node-RED stores every flow, node, wire, and group box in one large JSON file.
Editing it by hand — or with jq and sed — is how you end up with dangling
wires, groups whose boxes no longer cover their own nodes, and new nodes stacked
on top of existing ones.
This server exposes that file to an MCP client as a small set of tools that understand the format. It knows the difference between a flow node and a config node, it can trace a wire path, and it reproduces the Node-RED editor's own geometry so a group box it draws is the box the editor would have drawn.
It is a port of the flows_util.py / layout_util.py pair used to script
Node-RED changes in a home-automation repo, generalised so the file path,
container name, and restart command are all configuration.
Related MCP server: nr-mcp
Features
Query — tabs, groups, orphaned nodes, subflows, referenced Home Assistant entities, and wire traces through a flow.
Edit — create, update, delete, rename, and duplicate nodes; wire and unwire them; create, populate, and restyle groups; import and export node sets.
Place — claim empty canvas before creating nodes instead of guessing coordinates, lint the canvas for collisions, and repair overlaps.
Commit deliberately — edits accumulate in memory and reach disk only when you ask, so a multi-node build lands as one unit.
Two guards the underlying scripts never needed: a layout gate that refuses writes which introduce new collisions, and a staleness check that refuses to overwrite a
flows.jsonsomeone deployed from the browser.
Requirements
Python 3.11+
A
flows.jsonon the local filesystemDocker on
PATH— only for thedeploytool, which copies the file into a container and restarts it
Installation
git clone https://github.com/ljmerza/nodered-mcp
cd nodered-mcp
uv syncUsage
The flows.json path is the only required setting. There is no sensible
default, so the server refuses to start without one.
uv run nodered-mcp --flows-path /path/to/nodered/data/flows.jsonRegister with an MCP client
{
"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"
}
}
}
}See .mcp.json.example for a fuller example.
Configuration
Every setting resolves CLI flag > environment variable > default.
Flag | Environment variable | Default | Purpose |
|
| (required) | Path to |
|
|
| Container name used by |
|
|
| Path to |
|
|
| Restart command; |
|
|
|
|
|
|
| Bind address for |
If Node-RED is managed by something other than plain Docker, point
--restart-cmd at it:
NODERED_RESTART_CMD="docker compose restart {container}"Tools
Seven tools, each dispatching on an op argument.
Tool | Ops |
|
|
| Structured search by tab, type, or name substring |
| One node's raw JSON plus its wiring context |
|
|
|
|
|
|
|
|
A typical build
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")Nothing above touches flows.json until the final save.
How it protects the file
The layout gate
save and deploy lint the canvas before and after your edit, and refuse to
write if the edit introduces a new error-level finding:
Finding | Severity | Meaning |
| error | A group box landed on another group box |
| error | A group box no longer covers its own nodes |
| warning | A node sits inside a group box it isn't a member of |
| warning | Two nodes occupy the same space |
Problems that already existed on disk never block — only ones your edit created. When the gate fires, the fix is usually one of:
nodered_layout(op="free_region")to claim clear canvas, then place therenodered_group(op="refit", group_id=...)to resize a group around its nodesnodered_session(op="save", allow_overlap=true)if the overlap is deliberate
Group geometry is exact: the sizing rules are ported from the Node-RED editor, so a computed box matches what the editor draws. Node geometry is exact apart from label text width, which is approximated from Helvetica metrics — that is why node-level findings are only ever warnings.
The staleness check
Node-RED rewrites flows.json whenever someone presses Deploy in the browser.
The session records (mtime_ns, size) when it loads the file and re-checks
before every write. If the file changed underneath you, the commit is refused
rather than silently reverting that work. Either reload and redo your edits,
or pass force=true.
Nanoseconds rather than os.path.getmtime: a float epoch only resolves to about
a microsecond, so a write landing in the same tick as the load compares equal
and slips past the check.
Standalone use
Both engine modules work as libraries and CLIs, independent of 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,movefrom 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 boxesalone makes things worse: refitting grows some boxes so they swallow neighbouring non-member nodes. Runboxes,movetogether, and read the dry run before passing--apply.
Project layout
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 editorFlows composes the mixins, so the public API stays flat: f.summary(),
f.create_node(), f.free_region(), f.save().
Development
uv sync --group dev
uv run pytest # 49 tests
uv run ruff check .
uv run ruff format --check .Tests run against a synthetic fixture in tests/fixtures/, never a real flows
file. They cover configuration precedence, the read tools, in-memory-until-save
semantics, the layout gate both blocking and overridden, the staleness guard,
the deploy command sequence, and that no tool writes to stdout — a stray print
would corrupt MCP's stdio framing.
CI runs the same checks through
ljmerza/misc-actions.
Contributing
Issues and pull requests are welcome. Please keep ruff check, ruff format,
and pytest green.
Acknowledgments
Node-RED — the canvas geometry here is ported from its editor client, so group boxes match what the editor draws.
FastMCP — the MCP server framework.
License
MIT. See LICENSE.
This server cannot be installed
Maintenance
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
- AlicenseNot gradedqualityDmaintenanceEnables management of multiple N8N workflow automation instances through MCP. Supports listing, creating, updating, deleting, executing workflows and monitoring their executions across different N8N environments.63MIT
- AlicenseAqualityDmaintenanceLets AI assistants interact with Node-RED to read flows, search nodes, edit function code, deploy changes safely, and manage modules.131MIT
- AlicenseNot gradedqualityBmaintenanceExposes Node-RED flows as MCP tools for AI assistants, with OAuth protection and optional admin tools for flow management.2081ISC
- FlicenseNot gradedqualityBmaintenanceMinimal MCP server wrapping the Node-RED admin API, enabling flow management, node installation, and context retrieval via natural language.
Related MCP Connectors
Create, browse, remix, collaborate on, and run durable AI workflow nodes from MCP hosts.
MCP server for secureFlows: token-free URL builders and integration-linting tools for AI agents.
JSON tools MCP.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/ljmerza/nodered-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server