Node-RED Object Action MCP
by sammachin
README.md
# node-red-object-action-mcp
Expose your Node-RED flows as **MCP (Model Context Protocol) servers**. Declare an
*object* (e.g. `office lights`) with free-text *actions* (`turn on`, `turn off`, …) and
*readable values* (`status`, `brightness`), and an AI agent speaking MCP can call them as
tools — driving your flow and reading values back out of it.
The server speaks JSON-RPC 2.0 over the **Streamable HTTP** transport (MCP protocol
`2025-06-18`) and is mounted on Node-RED's own runtime HTTP server, so no extra port or
process is needed.
## Nodes
| Node | Palette label | Purpose |
|------|---------------|---------|
| `object-action-mcp-endpoint` | *(config)* | Mounts an MCP server at a path (e.g. `/mcp`). Multiple endpoints can coexist. |
| `object-action-mcp-object` | **object** | One object + N free-text actions. Each action is a tool and an output; a call fires a `msg` from that output. |
| `object-action-mcp-read` | **object read** | One object + N readable values. Each value is a tool and an output; a call emits a `msg` whose value is returned by a response node. |
| `object-action-mcp-response` | **mcp response** | Returns `msg.payload` to the waiting MCP tool call. |
## How it works
```
┌─────────────────────────────┐
MCP client ──HTTP POST /mcp──▶ │ object-action-mcp-endpoint │
(agent) ◀──JSON-RPC result └─────────────────────────────┘
│ tools/call ▲
▼ │ resolve
┌──────────────┐ ┌───────────┐ ┌──────────────┐
│ object/read │──msg─▶│ your flow │──msg─▶│ mcp response │
└──────────────┘ └───────────┘ └──────────────┘
```
- **Actions** (object node) can be configured **per action** to either:
- return an **instant ack** (fire-and-forget — the configured ack text is returned at once), or
- **wait for a response** node (the call is held open until a response node returns a result).
- **Reads** (object read node) always wait for a response node to supply the value.
- **Parameters:** actions and reads can declare typed parameters (`string` / `number` /
`boolean`, optional/required). They become the tool's MCP `inputSchema`, and the call
arguments arrive on `msg.payload`.
The emitted `msg` carries `object`, `action`/`read`, `tool`, and an opaque `_oamcp`
correlation handle. **Pass `_oamcp` through unchanged** so the response node can match the
value back to the right call. The response node returns `msg.payload` (a string is sent as
text; an object is also returned as `structuredContent`); set `msg.isError = true` to return
it as a tool error.
## Install
From your Node-RED user directory (`~/.node-red`):
```bash
npm install node-red-object-action-mcp
```
or, for local development, install from a checkout:
```bash
cd ~/.node-red
npm install /path/to/node-red-object-action-mcp
```
Restart Node-RED. The nodes appear under the **mcp** palette category.
## Quick start
1. Drag an **object** node onto a flow, add an **endpoint** config (path `/mcp`), set the
object to `office lights`, and add actions `turn on` and `turn off` (instant ack).
2. Wire each action output to a debug (or your device logic).
3. Drag an **object read** node on the same endpoint, object `office lights`, value
`status`; wire it through a function that sets `msg.payload` into an **mcp response** node.
4. Deploy.
An importable version of this flow is in [`examples/office-lights.json`](examples/office-lights.json).
### Try it with curl
```bash
# initialize
curl -s http://localhost:1880/mcp \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}'
# list tools
curl -s http://localhost:1880/mcp \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
# call an action
curl -s http://localhost:1880/mcp \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"office_lights_turn_on","arguments":{}}}'
# read a value
curl -s http://localhost:1880/mcp \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"office_lights_status","arguments":{}}}'
```
### Try it with the MCP Inspector
```bash
npx @modelcontextprotocol/inspector
```
Choose the **Streamable HTTP** transport and connect to `http://localhost:1880/mcp`.
## Tool names
Tool names are derived from the object and action/value names, lowercased with non
`[a-z0-9_-]` characters replaced by `_` (e.g. `office lights` + `turn on` →
`office_lights_turn_on`). Duplicate names on one endpoint are rejected (the later node shows a
red status and a warning in the log).
## Authentication
Each endpoint can optionally require a **bearer token** (set *Auth = Bearer token* on the
config node). Clients then send `Authorization: Bearer <token>`. You can also rely on
Node-RED's own `httpNodeAuth`/`httpNodeMiddleware` settings for the whole HTTP server.
> **Note:** MCP endpoints are served on Node-RED's runtime HTTP server. Expose them only on
> trusted networks, or put them behind TLS and the bearer token (or a reverse proxy).
## Notes & limitations
- Implements the tools surface only (`initialize`, `tools/list`, `tools/call`, `ping`). No
resources, prompts, or server-initiated streaming; `GET` returns `405` by design.
- Sessions are lenient: an `Mcp-Session-Id` is issued on `initialize` but not required on
later requests, so the server works statelessly.
- JSON-RPC batching is intentionally unsupported (it was removed in MCP `2025-06-18`).
- Zero runtime dependencies.
## Development
```bash
npm install
npm test
```
## License
MIT © Sam Machin
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessSyncing