mcp-node-red 1.0.0 → 1.1.0
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.
- package/CHANGELOG.md +51 -1
- package/README.md +107 -232
- package/dist/client.d.ts +14 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +181 -4
- package/dist/client.js.map +1 -1
- package/dist/env.d.ts +2 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +13 -0
- package/dist/env.js.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/schemas.d.ts +286 -0
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +47 -0
- package/dist/schemas.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +232 -0
- package/dist/server.js.map +1 -1
- package/dist/tools/delete-context.d.ts +8 -0
- package/dist/tools/delete-context.d.ts.map +1 -0
- package/dist/tools/delete-context.js +26 -0
- package/dist/tools/delete-context.js.map +1 -0
- package/dist/tools/delete-flow.d.ts +8 -0
- package/dist/tools/delete-flow.d.ts.map +1 -0
- package/dist/tools/delete-flow.js +17 -0
- package/dist/tools/delete-flow.js.map +1 -0
- package/dist/tools/get-context.d.ts +8 -0
- package/dist/tools/get-context.d.ts.map +1 -0
- package/dist/tools/get-context.js +23 -0
- package/dist/tools/get-context.js.map +1 -0
- package/dist/tools/get-diagnostics.d.ts +8 -0
- package/dist/tools/get-diagnostics.d.ts.map +1 -0
- package/dist/tools/get-diagnostics.js +12 -0
- package/dist/tools/get-diagnostics.js.map +1 -0
- package/dist/tools/get-flow-state.d.ts +8 -0
- package/dist/tools/get-flow-state.d.ts.map +1 -0
- package/dist/tools/get-flow-state.js +12 -0
- package/dist/tools/get-flow-state.js.map +1 -0
- package/dist/tools/get-nodes.d.ts +8 -0
- package/dist/tools/get-nodes.d.ts.map +1 -0
- package/dist/tools/get-nodes.js +12 -0
- package/dist/tools/get-nodes.js.map +1 -0
- package/dist/tools/get-settings.d.ts +8 -0
- package/dist/tools/get-settings.d.ts.map +1 -0
- package/dist/tools/get-settings.js +12 -0
- package/dist/tools/get-settings.js.map +1 -0
- package/dist/tools/install-node.d.ts +8 -0
- package/dist/tools/install-node.d.ts.map +1 -0
- package/dist/tools/install-node.js +17 -0
- package/dist/tools/install-node.js.map +1 -0
- package/dist/tools/remove-node-module.d.ts +8 -0
- package/dist/tools/remove-node-module.d.ts.map +1 -0
- package/dist/tools/remove-node-module.js +17 -0
- package/dist/tools/remove-node-module.js.map +1 -0
- package/dist/tools/set-debug-state.d.ts +8 -0
- package/dist/tools/set-debug-state.d.ts.map +1 -0
- package/dist/tools/set-debug-state.js +18 -0
- package/dist/tools/set-debug-state.js.map +1 -0
- package/dist/tools/set-flow-state.d.ts +8 -0
- package/dist/tools/set-flow-state.d.ts.map +1 -0
- package/dist/tools/set-flow-state.js +17 -0
- package/dist/tools/set-flow-state.js.map +1 -0
- package/dist/tools/set-node-module-state.d.ts +8 -0
- package/dist/tools/set-node-module-state.d.ts.map +1 -0
- package/dist/tools/set-node-module-state.js +18 -0
- package/dist/tools/set-node-module-state.js.map +1 -0
- package/dist/tools/trigger-inject.d.ts +8 -0
- package/dist/tools/trigger-inject.d.ts.map +1 -0
- package/dist/tools/trigger-inject.js +17 -0
- package/dist/tools/trigger-inject.js.map +1 -0
- package/package.json +22 -5
- package/.github/workflows/ci.yml +0 -37
- package/.github/workflows/release.yml +0 -30
- package/.mcp.json.example +0 -11
- package/.releaserc.json +0 -17
- package/CLAUDE.md +0 -147
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"set-debug-state.js","sourceRoot":"","sources":["../../src/tools/set-debug-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE;CACrB,CAAC,CAAC;AAEH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAqB,EAAE,IAAa;IACtE,MAAM,MAAM,GAAG,uBAAuB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEnD,MAAM,MAAM,CAAC,iBAAiB,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAE9D,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;aAClF;SACF;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"set-flow-state.d.ts","sourceRoot":"","sources":["../../src/tools/set-flow-state.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAMlD,wBAAsB,YAAY,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO;;;;;GAWtE"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const SetFlowStateArgsSchema = z.object({
|
|
3
|
+
state: z.enum(['start', 'stop']),
|
|
4
|
+
});
|
|
5
|
+
export async function setFlowState(client, args) {
|
|
6
|
+
const parsed = SetFlowStateArgsSchema.parse(args);
|
|
7
|
+
const result = await client.setFlowState(parsed.state);
|
|
8
|
+
return {
|
|
9
|
+
content: [
|
|
10
|
+
{
|
|
11
|
+
type: 'text',
|
|
12
|
+
text: JSON.stringify(result, null, 2),
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=set-flow-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"set-flow-state.js","sourceRoot":"","sources":["../../src/tools/set-flow-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;CACjC,CAAC,CAAC;AAEH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAAqB,EAAE,IAAa;IACrE,MAAM,MAAM,GAAG,sBAAsB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvD,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;aACtC;SACF;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"set-node-module-state.d.ts","sourceRoot":"","sources":["../../src/tools/set-node-module-state.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAOlD,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO;;;;;GAW5E"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const SetNodeModuleStateArgsSchema = z.object({
|
|
3
|
+
module: z.string(),
|
|
4
|
+
enabled: z.boolean(),
|
|
5
|
+
});
|
|
6
|
+
export async function setNodeModuleState(client, args) {
|
|
7
|
+
const parsed = SetNodeModuleStateArgsSchema.parse(args);
|
|
8
|
+
const result = await client.setNodeModuleState(parsed.module, parsed.enabled);
|
|
9
|
+
return {
|
|
10
|
+
content: [
|
|
11
|
+
{
|
|
12
|
+
type: 'text',
|
|
13
|
+
text: JSON.stringify(result, null, 2),
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=set-node-module-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"set-node-module-state.js","sourceRoot":"","sources":["../../src/tools/set-node-module-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,4BAA4B,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE;CACrB,CAAC,CAAC;AAEH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAAqB,EAAE,IAAa;IAC3E,MAAM,MAAM,GAAG,4BAA4B,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAC9E,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;aACtC;SACF;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trigger-inject.d.ts","sourceRoot":"","sources":["../../src/tools/trigger-inject.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAMlD,wBAAsB,aAAa,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO;;;;;GAavE"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const TriggerInjectArgsSchema = z.object({
|
|
3
|
+
nodeId: z.string(),
|
|
4
|
+
});
|
|
5
|
+
export async function triggerInject(client, args) {
|
|
6
|
+
const parsed = TriggerInjectArgsSchema.parse(args);
|
|
7
|
+
await client.triggerInject(parsed.nodeId);
|
|
8
|
+
return {
|
|
9
|
+
content: [
|
|
10
|
+
{
|
|
11
|
+
type: 'text',
|
|
12
|
+
text: JSON.stringify({ nodeId: parsed.nodeId, triggered: true }, null, 2),
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=trigger-inject.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trigger-inject.js","sourceRoot":"","sources":["../../src/tools/trigger-inject.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;CACnB,CAAC,CAAC;AAEH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAqB,EAAE,IAAa;IACtE,MAAM,MAAM,GAAG,uBAAuB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEnD,MAAM,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAE1C,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;aAC1E;SACF;KACF,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-node-red",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "MCP server for Node-RED workflow management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
"test:coverage": "vitest run --coverage",
|
|
15
15
|
"lint": "biome check .",
|
|
16
16
|
"lint:fix": "biome check --write .",
|
|
17
|
-
"format": "biome format --write ."
|
|
17
|
+
"format": "biome format --write .",
|
|
18
|
+
"prepare": "husky"
|
|
18
19
|
},
|
|
19
20
|
"keywords": [
|
|
20
21
|
"mcp",
|
|
@@ -25,22 +26,38 @@
|
|
|
25
26
|
],
|
|
26
27
|
"author": "",
|
|
27
28
|
"license": "MIT",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "https://github.com/fx/mcp-node-red"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist",
|
|
35
|
+
"README.md",
|
|
36
|
+
"LICENSE",
|
|
37
|
+
"CHANGELOG.md"
|
|
38
|
+
],
|
|
28
39
|
"dependencies": {
|
|
29
40
|
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
41
|
+
"dotenv": "^17.3.1",
|
|
30
42
|
"undici": "^7.3.0",
|
|
31
43
|
"zod": "^3.24.1"
|
|
32
44
|
},
|
|
33
45
|
"devDependencies": {
|
|
34
46
|
"@biomejs/biome": "^1.9.4",
|
|
35
|
-
"@semantic-release/changelog": "^6.0.3",
|
|
36
|
-
"@semantic-release/git": "^10.0.1",
|
|
37
47
|
"@types/node": "^22.10.5",
|
|
38
48
|
"@vitest/coverage-v8": "^2.1.8",
|
|
39
|
-
"
|
|
49
|
+
"husky": "^9.1.7",
|
|
50
|
+
"lint-staged": "^16.2.3",
|
|
40
51
|
"typescript": "^5.7.2",
|
|
41
52
|
"vitest": "^2.1.8"
|
|
42
53
|
},
|
|
43
54
|
"engines": {
|
|
44
55
|
"node": ">=20"
|
|
56
|
+
},
|
|
57
|
+
"lint-staged": {
|
|
58
|
+
"*.{js,ts}": [
|
|
59
|
+
"biome format --write --files-ignore-unknown=true",
|
|
60
|
+
"biome check --write --no-errors-on-unmatched --files-ignore-unknown=true"
|
|
61
|
+
]
|
|
45
62
|
}
|
|
46
63
|
}
|
package/.github/workflows/ci.yml
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [main]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: [main]
|
|
8
|
-
|
|
9
|
-
jobs:
|
|
10
|
-
test:
|
|
11
|
-
runs-on: ubuntu-latest
|
|
12
|
-
strategy:
|
|
13
|
-
matrix:
|
|
14
|
-
node-version: [20, 22]
|
|
15
|
-
steps:
|
|
16
|
-
- uses: actions/checkout@v4
|
|
17
|
-
- name: Use Node.js ${{ matrix.node-version }}
|
|
18
|
-
uses: actions/setup-node@v4
|
|
19
|
-
with:
|
|
20
|
-
node-version: ${{ matrix.node-version }}
|
|
21
|
-
cache: 'npm'
|
|
22
|
-
- run: npm ci
|
|
23
|
-
- run: npm run build
|
|
24
|
-
- run: npm test
|
|
25
|
-
- run: npm run lint
|
|
26
|
-
|
|
27
|
-
coverage:
|
|
28
|
-
runs-on: ubuntu-latest
|
|
29
|
-
steps:
|
|
30
|
-
- uses: actions/checkout@v4
|
|
31
|
-
- uses: actions/setup-node@v4
|
|
32
|
-
with:
|
|
33
|
-
node-version: 22
|
|
34
|
-
cache: 'npm'
|
|
35
|
-
- run: npm ci
|
|
36
|
-
- run: npm run build
|
|
37
|
-
- run: npm run test:coverage
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
name: Release
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [main]
|
|
6
|
-
|
|
7
|
-
permissions:
|
|
8
|
-
contents: write
|
|
9
|
-
issues: write
|
|
10
|
-
pull-requests: write
|
|
11
|
-
id-token: write
|
|
12
|
-
|
|
13
|
-
jobs:
|
|
14
|
-
release:
|
|
15
|
-
runs-on: ubuntu-latest
|
|
16
|
-
steps:
|
|
17
|
-
- uses: actions/checkout@v4
|
|
18
|
-
with:
|
|
19
|
-
fetch-depth: 0
|
|
20
|
-
- uses: actions/setup-node@v4
|
|
21
|
-
with:
|
|
22
|
-
node-version: 22
|
|
23
|
-
- run: npm ci
|
|
24
|
-
- run: npm run build
|
|
25
|
-
- run: npm test
|
|
26
|
-
- run: npm run lint
|
|
27
|
-
- run: npx semantic-release
|
|
28
|
-
env:
|
|
29
|
-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
30
|
-
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/.mcp.json.example
DELETED
package/.releaserc.json
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"branches": ["main"],
|
|
3
|
-
"plugins": [
|
|
4
|
-
"@semantic-release/commit-analyzer",
|
|
5
|
-
"@semantic-release/release-notes-generator",
|
|
6
|
-
"@semantic-release/changelog",
|
|
7
|
-
"@semantic-release/npm",
|
|
8
|
-
"@semantic-release/github",
|
|
9
|
-
[
|
|
10
|
-
"@semantic-release/git",
|
|
11
|
-
{
|
|
12
|
-
"assets": ["package.json", "package-lock.json", "CHANGELOG.md"],
|
|
13
|
-
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
|
|
14
|
-
}
|
|
15
|
-
]
|
|
16
|
-
]
|
|
17
|
-
}
|
package/CLAUDE.md
DELETED
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
# CLAUDE.md
|
|
2
|
-
|
|
3
|
-
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
-
|
|
5
|
-
## Project Overview
|
|
6
|
-
|
|
7
|
-
MCP (Model Context Protocol) server that provides Node-RED workflow management capabilities via stdio transport. Exposes 4 tools for AI agents to interact with Node-RED Admin API v2: get flows, create flow, update flow, and validate flow.
|
|
8
|
-
|
|
9
|
-
## Commands
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
# Build (required after any code changes)
|
|
13
|
-
npm run build
|
|
14
|
-
|
|
15
|
-
# Development with auto-rebuild
|
|
16
|
-
npm run dev
|
|
17
|
-
|
|
18
|
-
# Run all tests
|
|
19
|
-
npm test
|
|
20
|
-
|
|
21
|
-
# Run tests with coverage
|
|
22
|
-
npm run test:coverage
|
|
23
|
-
|
|
24
|
-
# Run single test file
|
|
25
|
-
npx vitest tests/client.test.ts
|
|
26
|
-
|
|
27
|
-
# Lint
|
|
28
|
-
npm run lint
|
|
29
|
-
|
|
30
|
-
# Fix lint issues
|
|
31
|
-
npm run lint:fix
|
|
32
|
-
|
|
33
|
-
# Format code
|
|
34
|
-
npm run format
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## Architecture
|
|
38
|
-
|
|
39
|
-
### Core Components
|
|
40
|
-
|
|
41
|
-
**Server Layer** (`src/server.ts`):
|
|
42
|
-
- Creates MCP server using `@modelcontextprotocol/sdk`
|
|
43
|
-
- Reads config from env vars: `NODE_RED_URL` (required), `NODE_RED_TOKEN` (optional)
|
|
44
|
-
- Registers 4 MCP tools with schemas (get_flows, create_flow, update_flow, validate_flow)
|
|
45
|
-
- Routes tool calls to individual tool handlers
|
|
46
|
-
- Catches errors and returns MCP-formatted error responses
|
|
47
|
-
|
|
48
|
-
**HTTP Client** (`src/client.ts`):
|
|
49
|
-
- `NodeRedClient` class wraps Node-RED Admin API v2
|
|
50
|
-
- Handles two auth modes:
|
|
51
|
-
- Bearer token via `NODE_RED_TOKEN` env var
|
|
52
|
-
- Basic auth extracted from URL credentials (e.g., `http://user:pass@host:1880`)
|
|
53
|
-
- Always sets `Node-RED-API-Version: v2` header
|
|
54
|
-
- Uses `undici` for HTTP requests
|
|
55
|
-
|
|
56
|
-
**Tools** (`src/tools/*.ts`):
|
|
57
|
-
- Each tool is a standalone async function
|
|
58
|
-
- Takes `NodeRedClient` instance and tool arguments
|
|
59
|
-
- Returns MCP tool response format: `{ content: [{ type: 'text', text: '...' }] }`
|
|
60
|
-
- `create-flow.ts` uses POST /flow to create new flows
|
|
61
|
-
- `update-flow.ts` uses PUT /flow/:id to update individual flows safely
|
|
62
|
-
|
|
63
|
-
**Schemas** (`src/schemas.ts`):
|
|
64
|
-
- Zod schemas for validation
|
|
65
|
-
- `NodeRedItemSchema` is a union of flows (type: "tab") and nodes (other types)
|
|
66
|
-
- All items have `id` and `type`, flows also require `label`
|
|
67
|
-
- Node references to parent flows via `z` property
|
|
68
|
-
- `UpdateFlowRequestSchema` defines structure for PUT /flow/:id requests
|
|
69
|
-
|
|
70
|
-
### Key Design Decisions
|
|
71
|
-
|
|
72
|
-
**Stdio Transport**: Uses stdin/stdout for MCP communication, not HTTP. Server runs as child process.
|
|
73
|
-
|
|
74
|
-
**API v2 with Optimistic Locking**: Uses `rev` field in responses to prevent conflicts.
|
|
75
|
-
|
|
76
|
-
**Authentication Flexibility**: Supports both Bearer tokens (standalone Node-RED) and Basic auth (Home Assistant add-on).
|
|
77
|
-
|
|
78
|
-
**JSON String Parameters**: MCP tool parameters receive flows as JSON strings, not objects. Tools parse and validate them.
|
|
79
|
-
|
|
80
|
-
**Individual Flow Updates**: Uses PUT /flow/:id to update one flow at a time, preventing accidental destruction of other flows.
|
|
81
|
-
|
|
82
|
-
## Node-RED Admin API v2
|
|
83
|
-
|
|
84
|
-
**GET /flows**:
|
|
85
|
-
- Returns all flows: `{rev: "...", flows: [...]}`
|
|
86
|
-
|
|
87
|
-
**POST /flow**:
|
|
88
|
-
- Creates a new flow
|
|
89
|
-
- Request: `{id, label, nodes: [], configs: []}`
|
|
90
|
-
- Response: 200 or 204 with `{id: "..."}` in body
|
|
91
|
-
- Flow ID is optional - auto-generated if not provided
|
|
92
|
-
|
|
93
|
-
**PUT /flow/:id**:
|
|
94
|
-
- Updates a single flow by ID
|
|
95
|
-
- Request: `{id, label, nodes: [], configs: []}`
|
|
96
|
-
- Response: 204 with `{id: "..."}` in body
|
|
97
|
-
- Only affects the specified flow, all other flows remain untouched
|
|
98
|
-
|
|
99
|
-
## Testing
|
|
100
|
-
|
|
101
|
-
Tests use vitest with mocked `undici` requests. Each component has dedicated test file:
|
|
102
|
-
- `tests/client.test.ts` - HTTP client + auth modes
|
|
103
|
-
- `tests/tools.test.ts` - Tool handlers
|
|
104
|
-
- `tests/server.test.ts` - MCP server setup
|
|
105
|
-
|
|
106
|
-
## CRITICAL: Flow Update Safety
|
|
107
|
-
|
|
108
|
-
**Always use PUT /flow/:id for individual flow updates**
|
|
109
|
-
|
|
110
|
-
The MCP server uses `PUT /flow/:id` which:
|
|
111
|
-
- Updates ONLY the specified flow
|
|
112
|
-
- Leaves all other flows completely untouched
|
|
113
|
-
- No risk of destroying unrelated workflows
|
|
114
|
-
- Simpler and safer than POST /flows
|
|
115
|
-
|
|
116
|
-
**Flow update format**:
|
|
117
|
-
```json
|
|
118
|
-
{
|
|
119
|
-
"id": "flow-id",
|
|
120
|
-
"label": "Flow Name",
|
|
121
|
-
"nodes": [...],
|
|
122
|
-
"configs": [...]
|
|
123
|
-
}
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
## CRITICAL: ALWAYS Use MCP Tools
|
|
127
|
-
|
|
128
|
-
**NEVER bypass MCP tools to interact with Node-RED directly**
|
|
129
|
-
|
|
130
|
-
- NEVER use `curl` to call Node-RED API directly
|
|
131
|
-
- NEVER use Bash to make HTTP requests to Node-RED
|
|
132
|
-
- ALWAYS use the MCP tools: `get_flows`, `create_flow`, `update_flow`, `validate_flow`
|
|
133
|
-
|
|
134
|
-
The entire purpose of this MCP server is to provide safe, validated access to Node-RED through MCP tools. Bypassing them defeats the purpose and removes safety checks.
|
|
135
|
-
|
|
136
|
-
If MCP tools appear to fail:
|
|
137
|
-
1. Debug the MCP tool issue
|
|
138
|
-
2. Fix the tool implementation
|
|
139
|
-
3. Test the fix
|
|
140
|
-
4. NEVER work around it with direct API calls
|
|
141
|
-
|
|
142
|
-
## Configuration
|
|
143
|
-
|
|
144
|
-
Required env var: `NODE_RED_URL`
|
|
145
|
-
Optional env var: `NODE_RED_TOKEN`
|
|
146
|
-
|
|
147
|
-
For Home Assistant add-on deployments, embed credentials in URL: `http://username:password@host:1880`
|