@gmag11/nodered-mcp-server 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +162 -0
  3. package/index.js +133 -0
  4. package/package.json +58 -0
  5. package/resources/skills/nodered-flow-builder/SKILL.md +659 -0
  6. package/resources/skills/nodered-flow-layout/SKILL.md +395 -0
  7. package/resources/skills/nodered-flowfuse-dashboard/SKILL.md +941 -0
  8. package/resources/skills/nodered-fundamentals/SKILL.md +323 -0
  9. package/resources/skills/nodered-jsonata/SKILL.md +1039 -0
  10. package/resources/skills/nodered-mustache/SKILL.md +588 -0
  11. package/resources/skills/nodered-node-reference/SKILL.md +1020 -0
  12. package/resources/skills/nodered-node-reference/examples/common.json +113 -0
  13. package/resources/skills/nodered-node-reference/examples/network.json +107 -0
  14. package/resources/skills/nodered-node-reference/examples/parser.json +147 -0
  15. package/resources/skills/nodered-node-reference/examples/sequence.json +141 -0
  16. package/resources/skills/nodered-node-reference/examples/storage.json +104 -0
  17. package/resources/skills/nodered-patterns/SKILL.md +414 -0
  18. package/resources/skills/nodered-patterns/examples/error-handler.json +72 -0
  19. package/resources/skills/nodered-patterns/examples/http-endpoint.json +42 -0
  20. package/resources/skills/nodered-patterns/examples/mqtt-subscriber.json +47 -0
  21. package/resources/skills/nodered-patterns/examples/timer-flow.json +50 -0
  22. package/resources/skills/nodered-subflows/SKILL.md +261 -0
  23. package/resources/skills/nodered-uibuilder/SKILL.md +500 -0
  24. package/src/auth/api-key-verifier.js +36 -0
  25. package/src/auth/composite-verifier.js +59 -0
  26. package/src/auth/config.js +106 -0
  27. package/src/auth/oauth-clients-store.js +107 -0
  28. package/src/auth/oauth-provider.js +149 -0
  29. package/src/auth/oauth-token-store.js +312 -0
  30. package/src/nodered/auth.js +158 -0
  31. package/src/nodered/client.js +199 -0
  32. package/src/nodered/comms-client.js +500 -0
  33. package/src/renderer/colors.js +161 -0
  34. package/src/renderer/geometry.js +115 -0
  35. package/src/renderer/html-builder.js +571 -0
  36. package/src/renderer/index.js +51 -0
  37. package/src/renderer/ir-builder.js +161 -0
  38. package/src/renderer/layout.js +126 -0
  39. package/src/renderer/mermaid-builder.js +109 -0
  40. package/src/renderer/svg-builder.js +228 -0
  41. package/src/schemas/responses.js +283 -0
  42. package/src/server.js +844 -0
  43. package/src/skills/loader.js +84 -0
  44. package/src/staging-store.js +258 -0
  45. package/src/tools/add-nodes-to-group.js +216 -0
  46. package/src/tools/connect-nodes.js +115 -0
  47. package/src/tools/constants.js +45 -0
  48. package/src/tools/create-flow.js +87 -0
  49. package/src/tools/create-node.js +126 -0
  50. package/src/tools/create-subflow-instance.js +123 -0
  51. package/src/tools/create-subflow.js +101 -0
  52. package/src/tools/delete-context.js +60 -0
  53. package/src/tools/delete-flow.js +81 -0
  54. package/src/tools/delete-group.js +116 -0
  55. package/src/tools/delete-node.js +73 -0
  56. package/src/tools/delete-subflow.js +103 -0
  57. package/src/tools/deploy.js +94 -0
  58. package/src/tools/disconnect-nodes.js +158 -0
  59. package/src/tools/export-flow.js +161 -0
  60. package/src/tools/export-subflow.js +78 -0
  61. package/src/tools/flow-utils.js +376 -0
  62. package/src/tools/get-config-nodes.js +86 -0
  63. package/src/tools/get-context.js +76 -0
  64. package/src/tools/get-flow-diagram.js +99 -0
  65. package/src/tools/get-flow-nodes.js +116 -0
  66. package/src/tools/get-flows.js +74 -0
  67. package/src/tools/get-node-detail.js +77 -0
  68. package/src/tools/get-node-type-detail.js +92 -0
  69. package/src/tools/get-palette-nodes.js +63 -0
  70. package/src/tools/get-staging-status.js +34 -0
  71. package/src/tools/get-subflow-detail.js +110 -0
  72. package/src/tools/get-subflows.js +105 -0
  73. package/src/tools/import-flow.js +310 -0
  74. package/src/tools/inject-message.js +117 -0
  75. package/src/tools/install-node.js +31 -0
  76. package/src/tools/read-debug-messages.js +155 -0
  77. package/src/tools/refresh-staging.js +62 -0
  78. package/src/tools/remove-nodes-from-group.js +162 -0
  79. package/src/tools/render-staging.js +69 -0
  80. package/src/tools/response-utils.js +42 -0
  81. package/src/tools/search-nodes.js +134 -0
  82. package/src/tools/uninstall-node.js +31 -0
  83. package/src/tools/update-flow.js +95 -0
  84. package/src/tools/update-group.js +77 -0
  85. package/src/tools/update-node.js +132 -0
  86. package/src/tools/update-subflow.js +84 -0
  87. package/src/transport/http.js +252 -0
  88. package/src/transport/stdio.js +16 -0
  89. package/src/transport/ws-server.js +223 -0
@@ -0,0 +1,323 @@
1
+ ---
2
+ name: nodered-fundamentals
3
+ description: >-
4
+ Core vocabulary of Node-RED: nodes, flows (tabs), wires, messages, context, config nodes,
5
+ design principles, and basic error handling concepts.
6
+ tools:
7
+ - get-flows
8
+ - get-flow-nodes
9
+ - get-flow-diagram
10
+ - get-config-nodes
11
+ - get-node-detail
12
+ - get-palette-nodes
13
+ - get-node-type-detail
14
+ - create-flow
15
+ - update-flow
16
+ - delete-flow
17
+ - create-node
18
+ - update-node
19
+ - delete-node
20
+ - connect-nodes
21
+ - disconnect-nodes
22
+ - get-context
23
+ - delete-context
24
+ - inject-message
25
+ - search-nodes
26
+ - export-flow
27
+ - import-flow
28
+ - read-debug-messages
29
+ - install-node
30
+ - uninstall-node
31
+ - refresh-staging
32
+ - deploy
33
+ - get-staging-status
34
+ ---
35
+
36
+ # Node-RED Fundamentals
37
+
38
+ Core vocabulary, design principles, and basic error handling for working with Node-RED via the MCP tools. Read this BEFORE building any flows.
39
+
40
+ ---
41
+
42
+ ## What is Node-RED
43
+
44
+ Node-RED is a **flow-based, event-driven visual programming platform**. You wire together "nodes" on a canvas to process messages. Each message flows through a chain of nodes, each node performing a specific operation (transform, filter, route, store, etc.).
45
+
46
+ - **Event-driven**: Nodes wake up when a message arrives — there is no polling.
47
+ - **JSON-native**: Messages are JavaScript objects with a `payload` property.
48
+ - **Browser-based editor**: The UI runs in a browser, but the runtime and flows execute server-side.
49
+ - **Admin API**: The MCP tools communicate with Node-RED through its REST/WebSocket Admin API. All changes to flows (create, update, delete, deploy) go through this API.
50
+
51
+ ---
52
+
53
+ ## Node
54
+
55
+ A **node** is the fundamental building block. Each node has a type that determines what it does.
56
+
57
+ **Key fields on every node:**
58
+ | Field | Description |
59
+ |-------|-------------|
60
+ | `id` | Unique UUID (generated by the runtime or MCP tools) |
61
+ | `type` | Palette type (e.g., `"inject"`, `"function"`, `"debug"`, `"http in"`) |
62
+ | `name` | User-visible label (set via `name` property in create-node/update-node) |
63
+ | `z` | The flow (tab) ID this node belongs to |
64
+ | `x`, `y` | Canvas position (pixels, not meaningful for behavior) |
65
+ | `wires` | Array of output connections (see Wire section below) |
66
+
67
+ **MCP tools for nodes:**
68
+ - `create-node` — add a new node to a flow
69
+ - `update-node` — merge properties onto an existing node (never wires)
70
+ - `delete-node` — remove a node and clean up its wires
71
+ - `get-flow-nodes` — list nodes in a flow with their current state
72
+ - `get-node-detail` — get the full node object including large text fields (func code, template markup)
73
+ - `search-nodes` — find nodes across all flows by name, type, or property value
74
+
75
+ ---
76
+
77
+ ## Flow (Tab)
78
+
79
+ **"Flow" has two meanings in Node-RED — always disambiguate:**
80
+
81
+ 1. **Flow tab** (also called "flow" or "sheet"): A named tab in the editor that groups related nodes. Every node belongs to exactly one flow tab (its `z` field).
82
+ 2. **Message flow** (also called "wired flow"): The path messages take through connected nodes — inject → function → debug.
83
+
84
+ ---
85
+
86
+ ## Staging and Deploy
87
+
88
+ 🚨 **CRITICAL CONCEPT — Edits are NOT live until you deploy.**
89
+
90
+ The MCP tools use a **staging workspace** model, identical to the Node-RED editor:
91
+
92
+ - **All write operations stage locally**: `create-node`, `connect-nodes`, `update-node`, `delete-node`, etc. modify an in-memory copy of the flows. Nothing is sent to the Node-RED runtime until you explicitly deploy.
93
+ - **If you forget to deploy, your changes are LOST.** They only exist in staging memory.
94
+ - **All read operations read from staging**: `get-flows`, `get-flow-nodes`, `get-flow-diagram`, etc. return data from the staged copy, reflecting all pending changes.
95
+ - **Deploy pushes to runtime**: Call `deploy` to send all staged changes to Node-RED. Three deploy types:
96
+ - `"nodes"` (default) — restart only modified nodes (least disruptive)
97
+ - `"flows"` — restart only modified flow tabs
98
+ - `"full"` — restart everything
99
+ - **Check pending changes**: Use `get-staging-status` to see what's pending before deploying.
100
+ - **Staging guard**: `inject-message` refuses to inject if there are undeployed changes — deploy first, then test.
101
+ - **Batch then deploy**: Create several nodes + wire them, then call `deploy` once. Don't deploy after every single operation — batch your edits.
102
+
103
+ **Rule**: After ANY write operation, check the `staging.deployed` field in the response. If `false`, you have pending changes. Call `deploy` before testing with `inject-message`.
104
+
105
+ **Workflow**: Edit → Read (verify with diagram) → Deploy → Test (inject + debug)
106
+
107
+ In MCP contexts, "flow" typically means the tab. Use `flowId` to specify which tab to operate on.
108
+
109
+ **MCP tools for flows:**
110
+ - `get-flows` — list all tabs/subflows with their node counts and types
111
+ - `create-flow` — create a new empty tab
112
+ - `update-flow` — change tab label, disabled state, info, or env vars
113
+ - `delete-flow` — remove a tab and all its nodes
114
+ - `export-flow` — export a tab's JSON for backup or migration
115
+ - `import-flow` — import flow JSON into the instance
116
+
117
+ ---
118
+
119
+ ## Wire
120
+
121
+ A **wire** connects one node's output port to another node's input. Wires are stored in the `wires` array on the source node.
122
+
123
+ **`wires` array structure:**
124
+ ```json
125
+ "wires": [["targetNodeId1", "targetNodeId2"], []]
126
+ ```
127
+ - Index 0 → output port 0's wire targets
128
+ - Index 1 → output port 1's wire targets (empty if unused)
129
+ - Index 2 → output port 2's wire targets (empty if unused)
130
+
131
+ **Ports are 0-indexed.** The first output port is index 0.
132
+
133
+ **MCP tools for wires:**
134
+ - `connect-nodes` — add a wire from one node to another (single or batch)
135
+ - `disconnect-nodes` — remove a wire (single, clear-port, or batch)
136
+ - **Never set `wires` in `update-node` properties** — wiring is managed exclusively through connect-nodes/disconnect-nodes
137
+
138
+ ---
139
+
140
+ ## Message
141
+
142
+ A **message** (often called `msg`) is the JavaScript object that flows between nodes. Every message has at minimum:
143
+
144
+ | Property | Description |
145
+ |----------|-------------|
146
+ | `payload` | The primary data — can be any type (string, number, object, Buffer) |
147
+ | `topic` | Optional routing/metadata string |
148
+ | `_msgid` | Auto-generated unique message identifier |
149
+ | *(custom)* | Nodes can attach any additional properties (e.g., `msg.headers`, `msg.statusCode`) |
150
+
151
+ **MCP tools:**
152
+ - `inject-message` — trigger an inject node (starts a message through the flow)
153
+ - `read-debug-messages` — read output from debug nodes (requires comms WebSocket)
154
+
155
+ ---
156
+
157
+ ## Context
158
+
159
+ **Context** is Node-RED's key-value storage system with three scopes:
160
+
161
+ | Scope | Lifetime | Access |
162
+ |-------|----------|--------|
163
+ | **Node** | Tied to a single node | `context.get(key)` / `context.set(key, val)` in function nodes |
164
+ | **Flow** | All nodes in one flow tab | `flow.get(key)` / `flow.set(key, val)` in function nodes |
165
+ | **Global** | Entire Node-RED instance | `global.get(key)` / `global.set(key, val)` in function nodes |
166
+
167
+ **⚠️ IMPORTANT: The Admin API does NOT support writing context values.** The MCP tools can only **read** (`get-context`) and **delete** (`delete-context`) context. To write context, you must use a function node with `context.set()`, `flow.set()`, or `global.set()`.
168
+
169
+ **MCP tools:**
170
+ - `get-context` — read a context variable from any scope
171
+ - `delete-context` — delete a context variable from any scope
172
+
173
+ **Warning:** Default in-memory context is lost when Node-RED restarts. For persistence, users must configure file-based context storage (not controllable via MCP).
174
+
175
+ ---
176
+
177
+ ## Config Node
178
+
179
+ A **config node** (configuration node) is a shared resource node that holds reusable settings. Unlike regular nodes, config nodes are not wired into a flow — they are referenced by regular nodes via a property (e.g., an MQTT node references an `mqtt-broker` config node).
180
+
181
+ **Key characteristics:**
182
+ - `z` field is `""` (global, available to all flows) or a specific `flowId` (scoped to one tab)
183
+ - Not visible on the flow canvas by default (shown in a separate config node sidebar)
184
+ - Created automatically when you set a config-type property on a regular node via `create-node` or `update-node`
185
+
186
+ **⚠️ CREDENTIAL PRIVACY — critical to understand:**
187
+ Node-RED **never** exposes real credential **values** (passwords, API keys, tokens, certificates) through its REST API. When you call `get-flow-nodes` or `get-config-nodes`:
188
+ - The `credentials` field (e.g., `{ username: "xxx", password: "yyy" }`) will be **absent** — never included.
189
+ - **A missing `credentials` field does NOT mean the node has no credentials configured.** It means the values are hidden for security.
190
+
191
+ **How to work with credentials despite this limitation:**
192
+ - **To see credential metadata** (field names and which password-type fields are set): Use `get-node-detail` on a config node. It returns a `_credentials` field like `{ user: "test67", has_password: true }`. Password values are NEVER shown — only `has_<field>: true/false`.
193
+ - **To update credentials**: Use `update-node` with a `credentials` object. You only need to send the fields you want to change — unspecified credential fields are preserved. Example: `properties: { credentials: { password: "newpass" } }` changes only the password.
194
+ - **To set credentials on a new config node**: Use `create-node` with `credentials` inside `properties`. Example: `properties: { broker: "localhost", port: 1883, credentials: { user: "test67", password: "mypass" } }`.
195
+ - **The tools auto-detect credential fields** and nest them correctly — even if you send them at the top level, they will be moved to the `credentials` sub-object.
196
+
197
+ **MCP tools:**
198
+ - `get-config-nodes` — list all config nodes, filter by type (credentials hidden)
199
+ - `get-node-detail` — get full details of a specific config node (credentials hidden)
200
+
201
+ ---
202
+
203
+ ## Subflow
204
+
205
+ A **subflow** is a reusable group of nodes packaged as a single node. You define inputs/outputs as "subflow instance properties" and reuse the subflow like any palette node. Subflows appear in `get-flows` with `type: "subflow"`.
206
+
207
+ **Note:** Full subflow creation/editing is not yet supported via MCP tools. You can view existing subflows with `get-flows` and `get-flow-nodes`, but creating or modifying subflow internals requires the Node-RED editor.
208
+
209
+ ---
210
+
211
+ ## Palette
212
+
213
+ The **palette** is the registry of all installed node types. Each type has a module, version, category, and configurable properties.
214
+
215
+ **MCP tools:**
216
+ - `get-palette-nodes` — list all available node types (paginated, alphabetical)
217
+ - `get-node-type-detail` — get detailed info about a specific type including its configurable parameters
218
+ - `install-node` — install a new node module from npm (may require Node-RED restart)
219
+ - `uninstall-node` — remove a node module (⚠️ destroys all nodes of that type)
220
+
221
+ ---
222
+
223
+ ## Design Principles
224
+
225
+ ### Tab Organization
226
+ - **One tab per domain/concern** — don't put unrelated logic in one tab. Separate HTTP APIs, MQTT ingestion, data processing, and dashboard into distinct tabs.
227
+ - **Descriptive labels** — use `create-flow` or `update-flow` to set meaningful labels like `"Weather API Ingest"` not `"Flow 1"`.
228
+ - **info field** — use the `info` property on flows to document purpose, inputs/outputs, and dependencies. This is visible in the editor and helps anyone (including future you) understand the flow.
229
+
230
+ ### Node Naming
231
+ - **Always set a descriptive `name`** on every node you create. Use `create-node`'s `properties.name` or `update-node`.
232
+ - **Anti-pattern**: leaving nodes with default names (e.g., `"function 3"`, `"debug 2"`). These are meaningless in `get-flow-nodes` output.
233
+ - **Audit**: use `search-nodes` to find unnamed nodes: search for `"name":""`.
234
+
235
+ ### Documentation
236
+ - **Flow-level**: set the `info` property on flow tabs via `create-flow` or `update-flow`.
237
+ - **Node-level**: use **Comment nodes** (`type: "comment"`) to annotate sections of a flow. They display as text labels on the canvas.
238
+ - **Export**: use `export-flow` to share a documented flow as JSON for review.
239
+
240
+ ---
241
+
242
+ ## Error Handling Basics
243
+
244
+ Node-RED provides a **Catch node** (`type: "catch"`) for error handling. It catches errors thrown by nodes on the same flow tab.
245
+
246
+ **Catch node scope:**
247
+ - By default, a catch node catches errors from **all nodes on the same tab**.
248
+ - You can scope it to specific nodes by setting the `scope` property to an array of node IDs.
249
+
250
+ **Error object structure:**
251
+ ```javascript
252
+ {
253
+ message: "Error description",
254
+ source: { id: "nodeId", type: "nodeType", name: "nodeName", count: 1 },
255
+ error: <original error object>
256
+ }
257
+ ```
258
+
259
+ **Best practices:**
260
+ - Place a catch node on every tab, even if just wired to a debug node — otherwise errors are silently swallowed.
261
+ - In function nodes, use `node.error("message", msg)` to throw catchable errors.
262
+ - Use `read-debug-messages` to observe caught errors during development.
263
+
264
+ ---
265
+
266
+ ## Link Nodes
267
+
268
+ **Link nodes** enable message passing across flow tabs without using global context or subflows.
269
+
270
+ | Type | Purpose |
271
+ |------|---------|
272
+ | `link in` | Receives messages from link out/call nodes (any tab) |
273
+ | `link out` | Sends messages to all link in nodes with matching link name |
274
+ | `link call` | Sends a message and **waits for a response** (request-reply pattern) |
275
+
276
+ **Key behaviors:**
277
+ - Link nodes connect by **name**, not by wires. All link in/out nodes with the same name form a virtual bus.
278
+ - `link call` is the only built-in way to do synchronous request-reply across tabs.
279
+ - Link nodes are an alternative to subflows for cross-tab reuse.
280
+
281
+ **MCP tools:** Standard `create-node`, `update-node`, `delete-node`, `connect-nodes` apply to link nodes as well.
282
+
283
+ ---
284
+
285
+ ## Environment Variables
286
+
287
+ Flows can define **environment variables** scoped to a single tab.
288
+
289
+ **How to set them:**
290
+ - Via MCP: use `create-flow` or `update-flow` with the `env` array:
291
+ ```json
292
+ "env": [
293
+ { "name": "API_KEY", "value": "sk-xxx", "type": "str" },
294
+ { "name": "TIMEOUT", "value": "30", "type": "num" },
295
+ { "name": "DEBUG", "value": "true", "type": "bool" }
296
+ ]
297
+ ```
298
+ - Types: `"str"`, `"num"`, `"bool"` (controls how the value is parsed)
299
+
300
+ **How to use them:**
301
+ - In function nodes: `const apiKey = env.get("API_KEY");`
302
+ - In template nodes: `{{env.API_KEY}}`
303
+ - In any node property that supports env-var substitution: `${API_KEY}`
304
+
305
+ ---
306
+
307
+ ## Message-Flow Diagram
308
+
309
+ A simple inject → function → debug flow:
310
+
311
+ ```
312
+ ┌──────────┐ msg ┌──────────────┐ msg ┌──────────┐
313
+ │ inject │──────────▶│ function │──────────▶│ debug │
314
+ │ (start) │ │ msg.payload │ │ (output) │
315
+ └──────────┘ │ = x * 2 │ └──────────┘
316
+ └──────────────┘
317
+
318
+ 1. inject node triggers → sends msg { payload: <timestamp> }
319
+ 2. function node receives msg → sets msg.payload = msg.payload * 2
320
+ 3. debug node receives msg → prints to debug sidebar (read via read-debug-messages)
321
+ ```
322
+
323
+ Each node processes the message and passes it to the next node in the chain. This is the fundamental pattern: **trigger → transform → output**.