[KongchangAI]
· 3 min read· 1,530 words

River AI in Practice: Building a Voice-Controlled ESP32 Agent with n8n + MCP

River AI in Practice: Building a Voice-Controlled ESP32 Agent with n8n + MCP

A student capstone using MCP + n8n + ESP32 to build a complete voice-controlled IoT AI Agent.

River AI is a university capstone project that chains voice recognition, n8n low-code workflows, the MCP protocol, and ESP32 hardware to build an AI Agent capable of reading sensor data and controlling six appliances by voice. A Flask-based server.py acts as the central state hub, while n8n hosts both an MCP Server workflow (exposing sensor-read and device-control tools) and an AI Agent workflow (powered by Google Gemini with memory). The system prompt explicitly requires the model to call tools before claiming completion, preventing hallucinated execution — and the deployment covers key pitfalls like workflow publishing, same-network requirements, and Chrome's localhost-only microphone policy.

A university student's capstone project that chains together a voice assistant, n8n workflows, the MCP protocol, and ESP32 hardware — enabling voice-driven sensor readings and control of six home appliances. This project, called River AI, offers a concrete, low-code AI Agent implementation worth dissecting.

Project Overview: A Voice-Driven IoT Agent

As demonstrated on YouTube by Nabila Rahmadiani, an Information Technology student at Universitas Lampung, River AI is an AI Agent that takes voice commands. It uses Speech to Text to receive instructions, reads temperature, humidity, and distance data collected by an ESP32, and can toggle six appliances — represented by six LEDs: a light, TV, refrigerator, air conditioner, washing machine, and radio.

The heart of the system is the MCP (Model Context Protocol). It turns n8n into a tool provider, allowing the AI Agent to call these tools on demand, then communicates with a Python backend running on a Linux virtual machine via HTTP requests to ultimately drive real hardware. This architecture cleanly decouples "LLM inference" from "hardware execution."

MCP (Model Context Protocol) is an open standard proposed by Anthropic in late 2024 to address the fragmentation problem in integrating large AI models with external tools and data sources. Its core idea is to decouple the "tool provider" (MCP Server) from the "tool consumer" (MCP Client/Agent): the Server declares what it can do and which interfaces it exposes; the Client (typically an AI Agent) discovers and calls these tools on demand, without writing custom adapter code for each integration. This design is analogous to the USB-C unified interface concept — as long as tools from different sources follow the same protocol, an Agent can use them directly. n8n has natively supported MCP nodes since version 1.x, allowing non-developers to build MCP-compliant tool services through a visual interface. This is precisely the technical foundation that enables River AI to control hardware in a low-code fashion.

Backend Architecture: server.py as the Data Hub

The project's server runs on a Linux virtual machine and starts two things: n8n inside Docker, and a small Flask service called server.py.

The River AI folder contains three key files. index.html is the dashboard for the six devices, with cards that light up or dim based on their state. reaver.service runs the service as a background daemon, controllable via systemctl commands. The real "data hub," however, is server.py.

server.py handles three responsibilities: storing the latest sensor values uploaded by the ESP32, storing the on/off state of the six devices, and receiving on/off commands. The author explains why this middleware layer is necessary — n8n, the ESP32, and the dashboard all share the same data, and server.py is where they converge. This design pattern is valuable for any IoT project requiring multi-client data synchronization: rather than having clients connect directly to each other, a single unified state store is far cleaner.

Data sensor dari ESP32

The dashboard shows all devices initially turned off, while the sensor API endpoint displays temperature, humidity, and distance data from the ESP32, with the ESP status showing as online.

Flask is an extremely lightweight web framework in the Python ecosystem, well-suited for quickly building small HTTP API services. In an IoT project like River AI, its role is that of a "state server" rather than a full backend — it simply maintains a few global variables (latest sensor values, device on/off states) and exposes read/write interfaces through GET/POST endpoints. This minimalist "in-memory state + HTTP interface" pattern is very common in prototype projects: the ESP32 periodically POSTs data, n8n reads via GET, and the dashboard polls for updates — all three are fully decoupled through HTTP with no direct connections. The trade-off is that state is lost on restart; if persistence is needed, a storage layer like SQLite or Redis would be required. For a capstone demo, however, this is more than sufficient.

n8n Dual-Workflow Design: Separating MCP Server and Client

The author designed two separate workflows in n8n, directly mirroring MCP's two-sided architecture.

MCP Server Workflow

The first workflow acts as the MCP Server, using three nodes. The core is the MCP Server Trigger node, which turns n8n into an MCP server that exposes an endpoint — any tool hanging beneath it becomes callable by an Agent.

Tool one is "Read Sensors," which uses an HTTP Request node to GET the sensor API on server.py and retrieve the latest temperature, humidity, and distance readings. Tool two is "Control Device," which POSTs to the control API with parameters for the device name and action (on or off). A key detail: the specific device and action values are filled in by the AI using a from AI expression, derived directly from what the user said.

Node AI agentnya

AI Agent Chat Workflow

The second workflow handles conversation. The entry point is a Webhook node that receives speech-to-text results from the web page, with CORS enabled so the browser can call it.

The brain of this workflow is the AI Agent node. The author's system prompt defines a persona — named River AI, created by Nabila, with instructions to keep responses concise and Markdown-free (since they'll be read aloud via text-to-speech), and crucially, to call tools before claiming an action is complete. That last constraint is important: it prevents the LLM from "hallucinating" that it executed an action it never actually performed.

The chat model is Google Gemini, paired with a Memory node that uses the Session ID passed from the web page as a key to maintain conversation context. An MCP Client node connects to the MCP Server workflow, making all tools available to the Agent. Finally, a Respond to Webhook node returns the reply to the web page as JSON (in a reply field).

Deployment Checklist: From Publishing Workflows to Flashing the ESP32

Once the workflows are built, several critical preparation steps remain. The author lays them out clearly.

Step one: publish both workflows, because production Webhook and MCP URLs only take effect after publishing — any change requires a re-publish. Step two: update the Webhook constant in the HTML file with the VM's IP and production URL, so the frontend knows where to send text.

配置必须保持一致

Step three: use the Arduino IDE to flash the program onto the ESP32, ensuring pin configuration, Wi-Fi credentials, and server address are all correct. The ESP32 must also be on the same network as the VM to communicate. Step four: start a local web server in Windows PowerShell using python -m http.server 8000, then open the page in Chrome via localhost — because Chrome only allows microphone access on localhost or over HTTPS. This browser microphone permission restriction is a pitfall many web-based voice projects stumble into.

On the hardware side, the ESP32 is connected to a DHT11 temperature and humidity sensor, an HC-SR04 ultrasonic distance sensor, and six LEDs. The ESP32 sends sensor data to the server every two seconds, and the server's response includes device states, which are used to turn the corresponding LEDs on or off.

The ESP32 is a low-cost microcontroller from Espressif with integrated Wi-Fi and Bluetooth, and is currently one of the most popular IoT development boards. The DHT11 is a common digital temperature and humidity sensor with ±2°C temperature accuracy and ±5% RH humidity accuracy — inexpensive but sufficient for teaching demonstrations. The HC-SR04 is an ultrasonic ranging module that measures distance by emitting a 40kHz sound wave and calculating the echo return time, with a range of roughly 2cm to 4m. The Arduino IDE supports programming the ESP32 via the official board package; before flashing, you need to select the correct board model and serial port in the Tools menu and hardcode the Wi-Fi SSID/password and server IP in the code. This means the firmware must be reflashed when the network environment changes — a limitation of such prototype projects that would need to be addressed for production use (e.g., using a provisioning mode or pulling parameters from a configuration server).

Live Demo: Voice Queries and Device Control

The demonstration validated the entire chain.

实机演示

When the author asked "what's the room temperature," River replied "31.2 degrees Celsius"; asking about humidity returned "65.8%"; asking about the nearest object's distance returned "6.9 centimeters" — sensor reading worked end-to-end. Device control was equally successful: saying "turn on the light" lit up the first LED; "turn on all devices" lit all six; "turn off all devices" extinguished them all. The frontend also features a personified design, with River portrayed as a magical character who appears during interactions.

Why This Project Is Worth Referencing

Setting aside its identity as a student capstone project, River AI demonstrates a fairly complete combination of "AI Agent + low-code + IoT." It uses MCP to standardize tool invocation, n8n to lower the orchestration barrier, a Flask middleware layer to handle multi-client data consistency, and system prompt constraints to bound the LLM's behavior. For developers looking to get started with AI Agent hardware control, this is a compact but fully-formed reference sample. The real engineering challenges rarely lie in the model itself — they lie in methodically connecting voice, protocol, hardware, and permissions into a working whole.

#River AI#n8n MCP#ESP32 AI Agent#voice controlled IoT#MCP protocol#n8n workflow#AI Agent IoT#low-code AI agent
Share:

Related articles