node-red-mcp
by ziv-daniel
README.md
# š MCP Node-RED Server
[](https://opensource.org/licenses/MIT)
[](https://nodejs.org/)
[](https://www.typescriptlang.org/)
[](https://github.com/ziv-daniel/node-red-mcp/actions)
> A modern, production-ready Model Context Protocol (MCP) server for Node-RED
> integration.
## š Features
### š§ 20 MCP Tools
Full CRUD for flows, context variables, modules, and diagnostics ā plus semantic
search and real-time error detection.
### š Prompts Library
Built-in prompt templates: `debug_flow`, `explain_automation`, `audit_security`,
`document_flow`.
### š¦ MCP Resources
Browse Node-RED state as structured resources: `nodered://flows`,
`nodered://subflows`, `nodered://nodes`, `nodered://context/global`,
`flow://<id>`, `system://runtime`.
### š Semantic Search
Embeddings-based search across flows and nodes via `semantic_search_flows`.
Finds by meaning, not just keywords.
### š§ Elicitation
The server asks clarifying questions mid-call when required parameters are
missing (MCP SDK 1.24+ elicitation).
### šØ Real-time Error Detection
`get_node_errors` connects to Node-RED's WebSocket `/comms` endpoint to detect
nodes in error/warning state in real time.
## š Table of Contents
- [Quick Start](#-quick-start)
- [Available Tools](#-available-mcp-tools)
- [Read-Only Mode](#-read-only-mode)
- [Resources](#-mcp-resources)
- [Prompts](#-mcp-prompts)
- [Connecting](#-connecting-to-the-server)
- [Environment Variables](#-environment-variables)
## ā” Quick Start
### Prerequisites
- **Node.js** 22+ (LTS recommended)
- **Yarn** 4.x (automatically managed via Corepack)
- **Docker** (optional, for containerized setup)
### Native Installation
```bash
git clone https://github.com/ziv-daniel/node-red-mcp.git
cd node-red-mcp
yarn install
yarn build
```
### Docker
```bash
docker run -e NODERED_URL=http://your-nodered:1880 \
-e NODERED_USERNAME=admin \
-e NODERED_PASSWORD=password \
-p 3000:3000 \
ghcr.io/ziv-daniel/node-red-mcp:latest
```
## š§ Available MCP Tools
### Flow Management
| Tool | Description | Key Parameters |
| ----------------------- | ---------------------------------- | ------------------------------------------------ |
| `get_flows` | List flows (summary or full) | `includeDetails?`, `types?`, `limit?`, `offset?` |
| `get_flow` | Get a specific flow | `flowId` |
| `create_flow` | Create a new flow | `flowData`, `validate?` |
| `update_flow` | Update an existing flow | `flowId`, `flowData`, `validate?` |
| `enable_flow` | Enable a flow | `flowId` |
| `disable_flow` | Disable a flow | `flowId` |
| `delete_flow` | Delete a flow (dry-run by default) | `flowId`, `dryRun?`, `confirm?` |
| `validate_flow` | Validate flow structure | `flowId` |
| `search_flows` | Search nodes by type/name/property | `type?`, `query?`, `flowId?` |
| `semantic_search_flows` | Embeddings-based semantic search | `query`, `scope?`, `topK?`, `refresh?` |
### Context Variables
| Tool | Description | Key Parameters |
| ---------------- | --------------------------- | ----------------------------------- |
| `get_context` | Read global or flow context | `key?`, `scope?`, `flowId?` |
| `set_context` | Write a context variable | `key`, `value`, `scope?`, `flowId?` |
| `delete_context` | Delete a context variable | `key`, `scope?`, `flowId?` |
### Modules
| Tool | Description | Key Parameters |
| ----------------------- | ----------------------- | ------------------------------ |
| `search_modules` | Search Node-RED palette | `query`, `category?`, `limit?` |
| `install_module` | Install a module | `moduleName`, `version?` |
| `get_installed_modules` | List installed modules | ā |
### Diagnostics
| Tool | Description | Key Parameters |
| ------------------ | ----------------------------------------------- | -------------------------------- |
| `get_node_errors` | Detect nodes in error/warning state (WebSocket) | `includeWarnings?`, `timeoutMs?` |
| `get_flow_state` | Get flow runtime state (started/stopped) | ā |
| `get_settings` | Get Node-RED runtime settings | ā |
| `get_runtime_info` | Get Node-RED version and system info | ā |
## š Read-Only Mode
Set `MCP_READ_ONLY=true` to structurally prevent any mutation of your Node-RED
flows ā useful when exposing this server to remote AI agents where an accidental
or unintended write to a live/production instance is a real risk.
When enabled, write tools (`create_flow`, `update_flow`, `delete_flow`,
`enable_flow`, `disable_flow`, `set_context`, `delete_context`,
`install_module`) are removed from the tool list entirely ā clients never see
them as available capabilities ā and are also rejected if called directly by
name. All read, search, diagnostic, resource, and prompt capabilities remain
fully available. This pairs naturally with `delete_flow`'s existing `dryRun`
default for deployments that need read/write in the same session but still want
an extra layer of protection against accidental writes.
## š¦ MCP Resources
Access Node-RED state as browseable MCP resources:
| URI | Description |
| -------------------------- | ------------------------------- |
| `nodered://flows` | All tab flows (summary) |
| `nodered://subflows` | All subflows |
| `nodered://nodes` | Installed node modules |
| `nodered://context/global` | Global context variables |
| `flow://<id>` | Full detail for a specific flow |
| `system://runtime` | Node-RED runtime info |
## š MCP Prompts
Built-in prompt templates for common tasks:
| Prompt | Description |
| -------------------- | ------------------------------------------ |
| `debug_flow` | Diagnose errors in a specific flow |
| `explain_automation` | Explain what a flow does in plain language |
| `audit_security` | Security audit of flow configurations |
| `document_flow` | Generate documentation for a flow |
## š Connecting to the Server
### Transport Modes
| Mode | Env Var | Endpoint | Use Case |
| ------------------- | --------------------- | ------------ | ------------------------- |
| **Streamable HTTP** | `MCP_TRANSPORT=http` | `POST /mcp` | Production, remote agents |
| **Stdio** | `MCP_TRANSPORT=stdio` | stdin/stdout | Claude Desktop |
### Authentication
Set `MCP_USERNAME` and `MCP_PASSWORD` for HTTP Basic Auth on the `/mcp`
endpoint.
### Claude Desktop (stdio)
```json
{
"mcpServers": {
"nodered": {
"command": "node",
"args": ["path/to/node-red-mcp/dist/index.mjs"],
"env": {
"MCP_TRANSPORT": "stdio",
"NODERED_URL": "https://your-nodered-instance.com",
"NODERED_USERNAME": "admin",
"NODERED_PASSWORD": "password"
}
}
}
}
```
### Claude Code / Remote Agent (HTTP)
```bash
claude mcp add node-red \
--transport streamable-http \
--url https://<your-server>/mcp \
--header "Authorization: Basic <base64-credentials>"
```
## āļø Environment Variables
| Variable | Required | Default | Description |
| ----------------------------- | -------- | ------------------------- | --------------------------------------------------------------------------------------------------- |
| `NODERED_URL` | Yes | ā | URL of your Node-RED instance |
| `NODERED_USERNAME` | No | ā | Node-RED admin username |
| `NODERED_PASSWORD` | No | ā | Node-RED admin password |
| `MCP_TRANSPORT` | No | `http` | `http` or `stdio` |
| `MCP_USERNAME` | No | ā | MCP server auth username |
| `MCP_PASSWORD` | No | ā | MCP server auth password |
| `MCP_READ_ONLY` | No | `false` | Set `true` to hide write tools and reject write calls ā see [Read-Only Mode](#-read-only-mode) |
| `HOST` | No | `0.0.0.0` | Bind address |
| `PORT` | No | `3000` | Listen port |
| `LOG_LEVEL` | No | `info` | `debug`, `info`, `warn`, `error` |
| `NODERED_REJECT_UNAUTHORIZED` | No | `true` | Set `false` to allow self-signed TLS |
| `TRUST_PROXY` | No | `false` | Reverse proxy hops to trust ā see [Running Behind a Reverse Proxy](#running-behind-a-reverse-proxy) |
| `EMBEDDING_MODEL` | No | `Xenova/all-MiniLM-L6-v2` | Model for semantic search |
### Running Behind a Reverse Proxy
Express ignores `X-Forwarded-For` unless you tell it which proxies to trust.
Left unset behind a proxy, every client resolves to the proxy's own address and
shares a single rate-limit bucket. `TRUST_PROXY` sets Express's `trust proxy`:
| Value | Meaning |
| --------------------------- | ----------------------------------------------------------------------- |
| unset, empty, or `false` | Don't trust `X-Forwarded-For`; use the socket address (default) |
| `1`, `2`, ⦠| **Recommended.** Number of proxy hops in front of this server |
| `loopback` | Trust `127.0.0.1/8`, `::1/128` ā also `linklocal` and `uniquelocal` |
| `10.0.0.0/8`, `192.168.1.5` | Trust specific addresses or CIDR ranges |
| `loopback,10.0.0.0/8` | Comma-separated ā any combination of the above |
| `true` | Trust every hop. Works, but **not recommended** ā see the warning below |
Use the hop count wherever you can: `TRUST_PROXY=1` for a single Traefik, nginx
or Caddy in front, `TRUST_PROXY=2` for something like Traefik in front of
Pomerium. Count the proxies that actually append to `X-Forwarded-For`.
`TRUST_PROXY=true` is accepted, but the server logs a warning on startup and
express-rate-limit reports it as `ERR_ERL_PERMISSIVE_TRUST_PROXY`. Trusting
every hop means any client can spoof its address ā and so its rate-limit bucket
ā just by sending its own `X-Forwarded-For` header. Prefer a hop count or an
explicit trust list.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessUnresponsive