22-tool MCP server for Node-RED flow management with Pydantic models, incremental flow patching, layout linting, and flexible auth (token, basic, OAuth2). 137 tests, full ruff compliance. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
8.4 KiB
nodered-mcp
A Python MCP server for Node-RED flow management, built on FastMCP and Pydantic.
Gives language models full read/write access to a Node-RED instance through the Admin HTTP API, with structured Pydantic responses, incremental flow patching, layout linting, and flexible authentication (token, basic, OAuth2).
Compared to node-red-mcp-server
This project was inspired by karavaev-evgeniy/node-red-mcp-server (TypeScript/npm). Key differences:
| node-red-mcp-server (TS) | nodered-mcp (Python) | |
|---|---|---|
| Runtime | Node.js / npm | Python 3.11+ / uv |
| Framework | Custom MCP SDK | FastMCP |
| Responses | Raw JSON strings | Typed Pydantic models |
| Auth | Token only | Token, Basic, OAuth2 |
| Deployment types | full only |
full, nodes, flows, reload |
| Flow mutations | Replace entire flow | patch_flow with granular ops (add/remove/update/rewire) |
| Layout checks | None | lint_flow detects overlaps, spacing, wire crossings |
| Auto-lint | N/A | update_flow and patch_flow append warnings automatically |
| Tool count | 19 | 22 |
Installation
Requires Python 3.11+ and uv:
git clone <repo-url> && cd nodered-mcp
uv sync
Quick Start
# Minimal — token auth (default)
export NODE_RED_URL=http://localhost:1880
export NODE_RED_TOKEN=your-api-token
uv run nodered-mcp
Configuration
All configuration is via environment variables with the NODE_RED_ prefix.
| Variable | Default | Description |
|---|---|---|
NODE_RED_URL |
http://localhost:1880 |
Node-RED instance URL |
NODE_RED_TOKEN |
"" |
Bearer token (for token auth method) |
NODE_RED_API_VERSION |
v1 |
API version header |
NODE_RED_AUTH_METHOD |
token |
Auth method: token, basic, or oauth |
NODE_RED_AUTH_USERNAME |
"" |
Username for basic or oauth auth |
NODE_RED_AUTH_PASSWORD |
"" |
Password/app password for basic or oauth auth |
NODE_RED_OAUTH_TOKEN_URL |
"" |
OAuth2 token endpoint URL |
NODE_RED_OAUTH_CLIENT_ID |
"" |
OAuth2 client ID |
Authentication
Token (default)
Static bearer token sent with every request. This is the simplest method and matches how node-red-mcp-server works:
NODE_RED_URL=http://localhost:1880
NODE_RED_TOKEN=your-api-token
Basic Auth
HTTP Basic authentication, useful when Node-RED sits behind a forward auth proxy.
NODE_RED_AUTH_METHOD=basic
NODE_RED_AUTH_USERNAME=admin
NODE_RED_AUTH_PASSWORD=your-password
Basic Auth with Authentik
A common setup is Node-RED behind Authentik as a forward auth proxy. Authentik intercepts requests, validates credentials, and sets session cookies before forwarding to Node-RED.
-
Create an Authentik application for your Node-RED instance using the Forward Auth (single application) provider.
-
Configure your reverse proxy (Traefik, nginx, Caddy) to use Authentik's forward auth endpoint. For example, with Traefik:
# docker-compose.yml (Traefik labels on the Node-RED service) labels: - "traefik.http.routers.nodered.middlewares=authentik@docker" -
Create an Authentik service account (or use an existing user) and generate an app password under the user's token settings. This avoids MFA prompts that would block API access.
-
Configure nodered-mcp:
NODE_RED_URL=https://nodered.yourdomain.com NODE_RED_AUTH_METHOD=basic NODE_RED_AUTH_USERNAME=service-account NODE_RED_AUTH_PASSWORD=the-app-password-from-authentik
The basic auth credentials are sent to Authentik's proxy, which validates them and sets cookies. Subsequent requests use the session cookie, so Node-RED itself doesn't need auth enabled.
OAuth2 Client Credentials
Fetches a short-lived JWT via OAuth2 client credentials grant. The token is cached and auto-refreshed with a 30-second expiry buffer. On a 401 response, the server retries once with a fresh token.
NODE_RED_AUTH_METHOD=oauth
NODE_RED_AUTH_USERNAME=service-account
NODE_RED_AUTH_PASSWORD=service-password
NODE_RED_OAUTH_TOKEN_URL=https://auth.example.com/application/o/token/
NODE_RED_OAUTH_CLIENT_ID=your-client-id
MCP Client Configuration
Claude Desktop
{
"mcpServers": {
"nodered": {
"command": "uv",
"args": ["--directory", "/path/to/nodered-mcp", "run", "nodered-mcp"],
"env": {
"NODE_RED_URL": "http://localhost:1880",
"NODE_RED_TOKEN": "your-token"
}
}
}
}
Claude Code
{
"mcpServers": {
"nodered": {
"command": "uv",
"args": ["--directory", "/path/to/nodered-mcp", "run", "nodered-mcp"],
"env": {
"NODE_RED_URL": "http://localhost:1880",
"NODE_RED_TOKEN": "your-token"
}
}
}
}
Tools
Flow Tools (12)
| Tool | Description |
|---|---|
get_flows |
Get all flows with summary statistics |
update_flows |
Replace all flows with deployment type control (full/nodes/flows/reload) |
get_flow |
Get a single flow by ID |
update_flow |
Update a single flow (auto-lints after save) |
list_tabs |
List all flow tabs (workspaces) |
create_flow |
Create a new flow tab |
delete_flow |
Delete a flow tab |
get_flows_state |
Get runtime state (started/stopped) |
set_flows_state |
Start or stop the flow runtime |
get_flows_formatted |
Get flows grouped by tabs/nodes/subflows with statistics |
visualize_flows |
Markdown-formatted per-tab structural overview |
patch_flow |
Incremental operations: add_nodes, remove_nodes, update_node, rewire, set_label, set_info, set_disabled (auto-lints after save) |
Node Tools (6)
| Tool | Description |
|---|---|
inject |
Trigger an inject node |
get_nodes |
List installed node modules |
get_node_info |
Detailed info about a node module |
toggle_node_module |
Enable or disable a node module |
find_nodes_by_type |
Find all nodes of a given type |
search_nodes |
Search nodes by name or any property |
Layout Tools (1)
| Tool | Description |
|---|---|
lint_flow |
Check a flow for node overlaps, insufficient spacing, and wire-through-node crossings. Optionally scoped to specific node IDs. |
Settings Tools (2)
| Tool | Description |
|---|---|
get_settings |
Get Node-RED runtime settings |
get_diagnostics |
Get runtime diagnostics (Node.js version, OS, modules) |
Utility Tools (1)
| Tool | Description |
|---|---|
api_help |
Node-RED Admin API endpoint reference |
Architecture
src/nodered_mcp/
├── server.py # FastMCP server, config, client init
├── config.py # Pydantic Settings (env vars)
├── client.py # Async httpx wrapper with auth
├── models/
│ ├── base.py # BaseApiModel with from_api()
│ ├── flow.py # Node, FlowTab, Flow, FlowState
│ ├── node.py # NodeModule, NodeSet
│ ├── responses.py # FlowList, FlowSummary, Settings, etc.
│ └── layout.py # LayoutIssue, LayoutReport
└── tools/
├── flows.py # Flow CRUD + patch + auto-lint
├── nodes.py # Node management + search
├── layout.py # Layout lint checks
├── settings.py # Settings + diagnostics
└── utility.py # API help reference
The layer diagram is simple:
MCP Tools (thin async functions, return Pydantic models)
↓
NodeRedClient (async httpx, returns raw dicts)
↓
Node-RED Admin HTTP API
Development
make all # format + lint + test
make check # lint + test (no format)
make test # uv run pytest tests/ -v
make lint # uv run ruff check src/ tests/
make format # uv run ruff format src/ tests/
Run a single test file:
uv run pytest tests/tools/test_layout.py -v
Run with coverage:
uv run pytest tests/ -v --cov=src/nodered_mcp --cov-report=term-missing
Always use uv run — never bare python or pytest.
See conventions.md for detailed code patterns (model layering, tool conventions, client architecture).
License
MIT