@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,261 @@
1
+ ---
2
+ name: nodered-subflows
3
+ description: >-
4
+ Comprehensive guide for working with Node-RED subflows via MCP tools.
5
+ Covers subflow vocabulary, discovery, creation from scratch, instantiation,
6
+ editing, export/import, deletion, common patterns, and limitations.
7
+ tools:
8
+ - get-subflows
9
+ - get-subflow-detail
10
+ - create-subflow
11
+ - update-subflow
12
+ - delete-subflow
13
+ - create-subflow-instance
14
+ - export-subflow
15
+ - import-flow
16
+ ---
17
+
18
+ # Node-RED Subflows
19
+
20
+ Comprehensive guide for creating, managing, and using Node-RED subflows via MCP tools.
21
+
22
+ > **⚠️ Staging reminder:** All subflow operations (create, update, delete, instantiate) stage changes locally. Call `deploy()` after making changes to push them to the Node-RED runtime. Use `get-staging-status` to check what's pending.
23
+
24
+ > **Prerequisites:** Read `nodered-fundamentals` first for core vocabulary and `nodered-flow-builder` for basic flow construction patterns. See `nodered-flow-layout` for positioning rules when placing subflow instances on the canvas.
25
+
26
+ ---
27
+
28
+ ## Subflow Vocabulary
29
+
30
+ A subflow is a **reusable, encapsulated flow** that can be instantiated multiple times across different flow tabs. It has three layers in the Node-RED JSON:
31
+
32
+ ```
33
+ ┌──────────────────────────────────────────────────────────────────┐
34
+ │ SUBFLOW MODEL │
35
+ ├──────────────────────────────────────────────────────────────────┤
36
+ │ │
37
+ │ 1. DEFINITION (type: "subflow") │
38
+ │ - id, name, info (markdown description) │
39
+ │ - in → input port definitions (where messages enter) │
40
+ │ - out → output port definitions (where messages exit) │
41
+ │ - category, color, icon → palette metadata │
42
+ │ │
43
+ │ 2. INTERNAL NODES (z = subflowId) │
44
+ │ - Regular nodes placed inside the subflow canvas │
45
+ │ - Wired together to form the internal logic │
46
+ │ - Managed with the same tools as flow tab nodes │
47
+ │ │
48
+ │ 3. INSTANCES (type: "subflow:<subflowId>") │
49
+ │ - Placed in flow tabs (z = tabId) │
50
+ │ - Each has its own name, env vars, and wire connections │
51
+ │ - Output wires auto-size to match definition's out ports │
52
+ │ │
53
+ └──────────────────────────────────────────────────────────────────┘
54
+ ```
55
+
56
+ ### Key properties
57
+
58
+ | Concept | Field | Example |
59
+ |---------|-------|---------|
60
+ | Subflow ID | `id` | `"7b6d939fa36f99ef"` |
61
+ | Instance type | `type` | `"subflow:7b6d939fa36f99ef"` |
62
+ | Internal parent | `z` | `z = "7b6d939fa36f99ef"` |
63
+ | Instance location | `z` | `z = "c9a401de7611c87e"` (tab ID) |
64
+ | Input ports | `in` | Array of `{ x, y, wires: [{ id, port }] }` |
65
+ | Output ports | `out` | Array of `{ x, y, wires: [{ id, port }] }` |
66
+ | Instance env vars | `env` | Array of `{ name, value, type }` |
67
+
68
+ ---
69
+
70
+ ## Workflow A — Discover Available Subflows
71
+
72
+ ### Step 1: List all subflows
73
+ ```
74
+ get-subflows()
75
+ ```
76
+ Returns enriched summary of each subflow: name, description, input/output counts, internal node types, instance count and locations.
77
+
78
+ ### Step 2: Inspect a subflow deeply
79
+ ```
80
+ get-subflow-detail(subflowId: "<subflowId>")
81
+ ```
82
+ Returns the full definition, all internal nodes (with sanitized configs), all instances and their locations, and a Mermaid diagram of the internal flow. **Always call this before instantiating or modifying a subflow** to understand what it does.
83
+
84
+ ---
85
+
86
+ ## Workflow B — Create a Subflow from Scratch
87
+
88
+ Follow these steps in exact order:
89
+
90
+ ### Step 1: Create the subflow definition (empty container)
91
+ ```
92
+ create-subflow(name: "My Subflow", info: "Processes incoming data and routes by type")
93
+ ```
94
+ Save the returned `subflowId` — you'll use it as `flowId` for internal nodes.
95
+
96
+ ### Step 2: Populate internal nodes
97
+ ```
98
+ create-node(type: "mqtt in", flowId: "<subflowId>", properties: { topic: "test/#", broker: "<brokerId>" }, x: 100, y: 100)
99
+ create-node(type: "switch", flowId: "<subflowId>", properties: { property: "topic", outputs: 3 }, x: 300, y: 100)
100
+ create-node(type: "debug", flowId: "<subflowId>", properties: { complete: "payload" }, x: 500, y: 100)
101
+ ```
102
+ Use `<subflowId>` as `flowId` — the same `create-node` tool works for subflow internals.
103
+
104
+ ### Step 3: Wire internal nodes
105
+ ```
106
+ connect-nodes(fromNodeId: "<mqttId>", outputPort: 0, toNodeId: "<switchId>")
107
+ connect-nodes(fromNodeId: "<switchId>", outputPort: 0, toNodeId: "<debugId>")
108
+ ```
109
+
110
+ ### Step 4: Define input/output ports
111
+ ```
112
+ update-subflow(subflowId: "<subflowId>", updates: {
113
+ out: [
114
+ { x: 600, y: 100, wires: [{ id: "<switchId>", port: 0 }] },
115
+ { x: 600, y: 180, wires: [{ id: "<switchId>", port: 1 }] },
116
+ { x: 600, y: 260, wires: [{ id: "<switchId>", port: 2 }] }
117
+ ]
118
+ })
119
+ ```
120
+ **Important:** Port wires must reference internal node IDs. The `x`/`y` values are the port position on the subflow's input/output bar in the UI.
121
+
122
+ ### Step 5: Verify
123
+ ```
124
+ get-subflow-detail(subflowId: "<subflowId>")
125
+ ```
126
+ Check the Mermaid diagram shows correct internal wiring.
127
+
128
+ ---
129
+
130
+ ## Workflow C — Instantiate a Subflow in a Flow Tab
131
+
132
+ ### Basic instantiation
133
+ ```
134
+ create-subflow-instance(
135
+ subflowId: "<subflowId>",
136
+ flowId: "<tabId>"
137
+ )
138
+ ```
139
+ The tool auto-sizes output wires to match the subflow's output port count. Returns `nodeId`.
140
+
141
+ ### With environment variables
142
+ ```
143
+ create-subflow-instance(
144
+ subflowId: "<subflowId>",
145
+ flowId: "<tabId>",
146
+ name: "Sensor Processor",
147
+ env: [
148
+ { name: "THRESHOLD", value: "42", type: "num" },
149
+ { name: "API_URL", value: "https://example.com", type: "str" }
150
+ ]
151
+ )
152
+ ```
153
+ Environment variables are passed to internal nodes. Inside a function node, access them with `env.get("THRESHOLD")`.
154
+
155
+ ### Wire the instance outputs
156
+ ```
157
+ connect-nodes(fromNodeId: "<instanceId>", outputPort: 0, toNodeId: "<target1Id>")
158
+ connect-nodes(fromNodeId: "<instanceId>", outputPort: 1, toNodeId: "<target2Id>")
159
+ ```
160
+ Each output port corresponds to one entry in the subflow's `out` array (0-indexed).
161
+
162
+ ---
163
+
164
+ ## Workflow D — Editing Subflows
165
+
166
+ ### Editing metadata or ports
167
+ ```
168
+ update-subflow(subflowId: "<subflowId>", updates: {
169
+ name: "New Name",
170
+ info: "Updated description",
171
+ out: [ ... new port definitions ... ]
172
+ })
173
+ ```
174
+ Only allowed fields are updated: `name`, `info`, `category`, `color`, `icon`, `in`, `out`. All other fields are preserved.
175
+
176
+ ### Editing internal nodes
177
+ Use the standard tools with `flowId` set to the subflow ID:
178
+ ```
179
+ update-node(nodeId: "<internalNodeId>", properties: { ... })
180
+ connect-nodes(fromNodeId: "<a>", toNodeId: "<b>")
181
+ disconnect-nodes(fromNodeId: "<a>", toNodeId: "<b>")
182
+ create-node(type: "function", flowId: "<subflowId>", ...)
183
+ delete-node(nodeId: "<internalNodeId>")
184
+ ```
185
+
186
+ ### Editing an instance
187
+ Instances are just nodes — use standard tools:
188
+ ```
189
+ update-node(nodeId: "<instanceId>", properties: { name: "New Name", env: [...] })
190
+ ```
191
+
192
+ ---
193
+
194
+ ## Workflow E — Exporting and Importing
195
+
196
+ ### Export a subflow
197
+ ```
198
+ export-subflow(subflowId: "<subflowId>")
199
+ ```
200
+ Returns a JSON string containing the subflow definition, all internal nodes, and any referenced config nodes (e.g., mqtt-broker). Instances are NOT included — they belong to their parent flow tabs.
201
+
202
+ ### Import (duplicate or restore)
203
+ ```
204
+ import-flow(flowJson: "<exportedJson>", conflictStrategy: "regenerate")
205
+ ```
206
+ Use `"regenerate"` to create a safe duplicate with new IDs. Use `"overwrite"` to replace an existing subflow by ID.
207
+
208
+ ---
209
+
210
+ ## Workflow F — Deleting a Subflow
211
+
212
+ ### Cascade delete (default, safest)
213
+ ```
214
+ delete-subflow(subflowId: "<subflowId>")
215
+ ```
216
+ Removes: the subflow definition + all internal nodes + all instances. The `previousState` response enables undo via `import-flow`.
217
+
218
+ ### Delete definition only, keep instances
219
+ ```
220
+ delete-subflow(subflowId: "<subflowId>", deleteInstances: false)
221
+ ```
222
+ ⚠️ **Dangerous**: instances become orphan nodes of type `subflow:<deletedId>`. They will appear as "unknown" in the Node-RED UI. Only use this when migrating instances to a new subflow.
223
+
224
+ ### Recover from deletion
225
+ ```
226
+ import-flow(flowJson: JSON.stringify(previousState.definition, ...previousState.internalNodes, ...previousState.instances), conflictStrategy: "regenerate")
227
+ ```
228
+
229
+ ---
230
+
231
+ ## Common Patterns
232
+
233
+ ### Parametrized subflow pattern
234
+ Create a subflow with env variables for configuration:
235
+ 1. Define the subflow with a function node reading `env.get("PARAM")`
236
+ 2. Instantiate with different `env` values per instance
237
+ 3. Each instance behaves differently based on its env vars
238
+
239
+ ### Subflow as data pipeline
240
+ ```
241
+ [tab: Main Flow]
242
+ [mqtt in] → [subflow instance: Transform] → [debug]
243
+
244
+ [tab: Analytics] │
245
+ [http in] → [subflow instance: Transform] → [http response]
246
+ ```
247
+ Same subflow, different contexts.
248
+
249
+ ### When to use subflows vs link nodes vs tabs
250
+ - **Subflow**: Reusable logic with configurable parameters (env vars)
251
+ - **Link nodes**: Cross-tab message passing without duplication
252
+ - **Separate tabs**: Organizational separation, not functional reuse
253
+
254
+ ---
255
+
256
+ ## Limitations
257
+
258
+ - **No nested subflows**: Node-RED's UI does not support placing a subflow instance inside another subflow. While technically possible in JSON, the UI will not render it correctly.
259
+ - **UI refresh required**: Subflow changes made via MCP tools may not be immediately visible in the Node-RED editor. The user may need to refresh the browser.
260
+ - **Port wiring**: Input/output port `wires` in the subflow definition must reference internal node IDs. Invalid references will cause a deploy error.
261
+ - **Config node sharing**: Config nodes (mqtt-broker, etc.) referenced by subflow internal nodes are included in `export-subflow` but shared across instances at runtime.