Skip to main content

Hands-On: Give Your Hardware a Brain โ€” Build MCP Skills That Let AI Control Real Devices

Imagine telling your oven "Preheat to 200 degrees and bake for 25 minutes" โ€” and it just... does it. No app, no buttons, no menu diving. Just natural language, understood by an AI agent, executed on real hardware.

This guide shows you exactly how that works, using a Smart Oven project built with TuyaOpen. By the end, you'll know how to create your own hardware MCP skills for any device.


What You'll Buildโ€‹

An AI-powered Smart Oven where a chat agent can:

CommandWhat the Agent Does
"Turn on the oven"Calls oven.start โ†’ sets the power DP
"Preheat to 200ยฐC"Calls oven.set_temperature(200) โ†’ writes the temp DP
"Bake for 25 minutes"Calls oven.set_timer(1500) โ†’ sets countdown DP
"Is it still on?"Calls oven.get_state() โ†’ reads all DPs, returns JSON
"Run the pizza recipe"Calls oven.run_recipe("pizza") โ†’ sets temp + timer + starts
"Take a photo and check if the cake is done"Calls device.camera_shot() โ†’ captures a JPEG the AI can see

The magic glue? MCP Function Call โ€” the protocol that turns hardware operations into tools an AI agent can discover and invoke.


How It Works: The Architectureโ€‹

The key insight: Every hardware capability (set temperature, read state, capture image) is registered as an MCP tool โ€” a named function with typed parameters and a callback. The AI agent sees these tools, decides which to call based on user intent, and the callback drives the real hardware.


Step 1: Create the Cloud Productโ€‹

Before writing any firmware code, you need a product on the Tuya cloud platform. The product defines your device's data model (DPs), AI agent, and cloud capabilities. Everything downstream โ€” firmware, MCP tools, the app โ€” depends on this.

1a. Create the productโ€‹

  1. Log in to the Tuya Developer Platform โ†’ AI Product > Development โ†’ Create
  2. Select Custom to create a custom product from scratch (instead of picking a preset category)
  3. Complete the creation wizard โ€” you'll get a PID (Product ID)
tip

The fastest way: use the /tuya-iot-platform vibe coding skill in TuyaOpen IDE. Just describe your device in natural language and the Agent creates the product, defines DPs, and configures the AI Agent for you.

1b. Define Data Points (DPs)โ€‹

Data Points (DPs) are the digital twin of your hardware. Each DP maps to a controllable or readable feature. In the Function Definition tab, click Add to create these custom DPs (IDs 101โ€“199):

DP IDCodeTypeRangeDescription
101switchBoolโ€”Power on/off
102temp_setValue50โ€“250Target temperature (ยฐC)
103temp_currentValue0โ€“300Current temperature (ยฐC)
104timerValue0โ€“3600Countdown timer (seconds)
note

Standard DPs (ID < 100) are pre-defined by Tuya. Custom DPs (ID 101โ€“199) are yours to define. For the oven, all four are custom.

1c. Add AI Agent & MCP capabilitiesโ€‹

In the Function Definition tab โ†’ Product AI Capabilities โ†’ Add Agent:

  1. Model Configuration โ†’ Skills Configuration โ†’ select Plugin โ†’ add Device Control ยท Bound Only (this enables MCP tool calls to your device DPs)
  2. Prompt Development โ†’ write a system prompt that describes the oven's capabilities so the AI knows when to call each tool

This creates the cloud-side Agent that will discover and invoke the MCP tools you register in firmware.

1d. Generate the DP header for firmwareโ€‹

Once DPs are defined on the cloud, generate the C header your firmware will include:

tuyaopen dp generate --target embedded

This produces tuya_dp_profile.h โ€” the contract between cloud and device:

// tuya_dp_profile.h โ€” auto-generated by `tuyaopen dp generate`
#define DPID_SWITCH 101
#define DPID_TEMP_SET 102
#define DPID_TEMP_CURRENT 103
#define DPID_TIMER 104

#define DPID_TEMP_SET_MIN 50
#define DPID_TEMP_SET_MAX 250
#define DPID_TIMER_MIN 0
#define DPID_TIMER_MAX 3600
tip

The full product creation flow is documented in Create Your Product & Agent. For the oven demo, you can also let the AI Agent generate the product and DPs for you using the /tuya-iot-platform skill in TuyaOpen IDE.


Step 2: Implement the Mock Hardware Layerโ€‹

Before wiring up MCP tools, you need functions that simulate (or drive) the actual hardware. This keeps your tool callbacks clean:

// app_oven.h
typedef struct {
bool switch_on;
int temp_set;
int temp_current;
int timer_remaining;
} oven_state_t;

OPERATE_RET app_oven_set_switch(bool on);
OPERATE_RET app_oven_set_temp(int temp_c);
OPERATE_RET app_oven_set_timer(int seconds);
OPERATE_RET app_oven_add_timer(int seconds);
oven_state_t app_oven_get_state(void);
// app_oven.c โ€” each setter reports DPs to the cloud + updates the LCD
static oven_state_t g_oven_state = {
.switch_on = false,
.temp_set = 180,
.temp_current = 25,
.timer_remaining = 0
};

OPERATE_RET app_oven_set_temp(int temp_c) {
if (temp_c < DPID_TEMP_SET_MIN || temp_c > DPID_TEMP_SET_MAX)
return OPRT_INVALID_PARM;
g_oven_state.temp_set = temp_c;
__oven_report_dp(); // sync to cloud + LCD
return OPRT_OK;
}

Step 3: Register MCP Tools (The Core Step)โ€‹

This is where the AI agent gets its "hands" on your hardware. Each tool is registered with:

  • Name โ€” what the AI sees (use dot-notation: oven.set_temperature)
  • Description โ€” LLM-friendly text explaining when/how to call it
  • Parameters โ€” typed input properties with ranges
  • Callback โ€” the function that runs when the AI calls this tool

The Registration Patternโ€‹

#include "ai_mcp_server.h"
#include "tal_event_info.h"

// Called once when MQTT connects (deferred registration)
static OPERATE_RET __oven_mcp_on_mqtt_connected(void *data) {
(void)data;

// Tool 1: Start the oven
TUYA_CALL_ERR_GOTO(AI_MCP_TOOL_ADD(
"oven.start",
"Turn on the oven. Use when the user wants to start cooking, "
"preheat, or begin baking.\nParameters: none\nReturns: bool",
__oven_start_cb, NULL
));

// Tool 2: Set temperature
TUYA_CALL_ERR_GOTO(AI_MCP_TOOL_ADD(
"oven.set_temperature",
"Set the oven target temperature in Celsius (50-250).\n"
"Parameters: temperature (int)\nReturns: int (applied temp)",
__oven_set_temp_cb, NULL,
MCP_PROP_INT_RANGE("temperature", "Target temperature in ยฐC (50-250).",
DPID_TEMP_SET_MIN, DPID_TEMP_SET_MAX),
MCP_PROP_END
));

// Tool 3: Get full state
TUYA_CALL_ERR_GOTO(AI_MCP_TOOL_ADD(
"oven.get_state",
"Get the current oven state: power, target temp, current temp, "
"timer remaining.\nParameters: none\nReturns: JSON object",
__oven_get_state_cb, NULL
));

// ... more tools
return OPRT_OK;
}

OPERATE_RET app_oven_mcp_init(void) {
return tal_event_subscribe(
EVENT_MQTT_CONNECTED, "oven_mcp_tools",
__oven_mcp_on_mqtt_connected, SUBSCRIBE_TYPE_ONETIME);
}

The Callback Patternโ€‹

Each callback reads AI-supplied arguments from properties, calls the hardware function, and returns a result:

static OPERATE_RET __oven_set_temp_cb(const MCP_PROPERTY_LIST_T *properties,
MCP_RETURN_VALUE_T *ret_val,
void *user_data) {
// 1. Read the AI-supplied parameter
int temp = properties->properties[0]->value.int_val;

// 2. Call the hardware function
OPERATE_RET rt = app_oven_set_temp(temp);

// 3. Return the result to the AI
ai_mcp_return_value_set_int(ret_val,
(rt == OPRT_OK) ? temp : -1);
return OPRT_OK;
}

For JSON returns (like get_state):

static OPERATE_RET __oven_get_state_cb(const MCP_PROPERTY_LIST_T *properties,
MCP_RETURN_VALUE_T *ret_val,
void *user_data) {
oven_state_t s = app_oven_get_state();
cJSON *json = cJSON_CreateObject();
cJSON_AddBoolToObject(json, "switch_on", s.switch_on);
cJSON_AddNumberToObject(json, "temp_set", s.temp_set);
cJSON_AddNumberToObject(json, "temp_current", s.temp_current);
cJSON_AddNumberToObject(json, "timer_remaining", s.timer_remaining);
ai_mcp_return_value_set_json(ret_val, json);
return OPRT_OK;
}

Step 4: Wire It Into the Boot Sequenceโ€‹

In your app_chat_bot.c, call your MCP init right after ai_mcp_init():

#if defined(ENABLE_COMP_AI_MCP) && (ENABLE_COMP_AI_MCP == 1)
TUYA_CALL_ERR_RETURN(ai_mcp_init());
TUYA_CALL_ERR_RETURN(app_oven_mcp_init()); // โ† your tools
#endif

Tools register automatically when MQTT connects. That's it.


Step 5: Build and Testโ€‹

cd source/embedded
tos.py build

Verify the tool appears in the agent's tool list, then try these interactions:

You SayAgent CallsResult
"Preheat to 200 and bake for 25 minutes"oven.set_temperature(200) โ†’ oven.set_timer(1500) โ†’ oven.start()Oven heats up, timer counts down
"Roast a chicken"oven.run_recipe("roast")200ยฐC, 40 min, auto-start
"Is it still on? How hot?"oven.get_state()Returns {switch_on: true, temp_set: 200, ...}
"Take a photo and check if the cake is done"device.camera_shot()AI receives a JPEG and can visually inspect

The Complete Tool Setโ€‹

Here's the full set of MCP tools for the Smart Oven:

ToolParametersReturnsPurpose
oven.startโ€”boolPower on
oven.stopโ€”boolPower off
oven.set_temperaturetemperature (int, 50โ€“250)intSet target temp
oven.set_timerseconds (int, 0โ€“3600)intSet countdown
oven.add_timeseconds (int)intAdd time to timer
oven.get_stateโ€”JSONRead all DPs
oven.list_recipesโ€”JSON arrayList preset programs
oven.run_reciperecipe (string)JSONApply recipe + start
device.camera_shotโ€”image/jpegCapture a photo

Built-in Recipesโ€‹

RecipeTempTimeBest For
bake180ยฐC30 minCakes, bread, casseroles
roast200ยฐC40 minMeat and vegetables
broil230ยฐC10 minQuick browning
pizza220ยฐC15 minHigh-heat pizza
grill250ยฐC8 minIntense grilling
reheat120ยฐC5 minLeftovers
warm80ยฐC30 minKeep food warm

AI Coding Prompts: Tips for Developersโ€‹

When using AI coding assistants (Cursor, Claude Code, Copilot) to build hardware MCP skills, these prompt patterns will accelerate your development:

Prompt Pattern 0: Generate the Full Cloud Product from a Descriptionโ€‹

/tuya-iot-platform
Create a new AI product for a smart oven with these capabilities:
- Power on/off (bool)
- Temperature setting 50-250ยฐC (value)
- Current temperature readback 0-300ยฐC (value, read-only)
- Countdown timer 0-3600 seconds (value)

Add an AI Agent with device control MCP plugin.
Generate the DP definitions and the embedded DP header.

Why it works: The /tuya-iot-platform skill creates the cloud product, defines DPs, configures the AI Agent, and generates the firmware DP header โ€” all from a natural-language device description. This is the fastest way to go from idea to code.

Prompt Pattern 1: Describe the Device, Not the Codeโ€‹

I have a smart oven with these features:
- Power on/off
- Temperature control (50-250ยฐC)
- Timer (0-3600 seconds)
- Current temperature sensor
- Camera for visual inspection

Create MCP tool registrations for each feature.
Use the AI_MCP_TOOL_ADD macro pattern from the otto_robot example.

Why it works: The AI maps your device description directly to tool names, descriptions, and parameters.

Prompt Pattern 2: Specify the DP Mappingโ€‹

My oven DPs are:
- DP 101: switch (bool, rw)
- DP 102: temp_set (value, 50-250, rw)
- DP 103: temp_current (value, 0-300, ro)
- DP 104: timer (value, 0-3600, rw)

Generate the tuya_dp_profile.h header and the MCP tool callbacks
that read/write these DPs.

Why it works: Explicit DP definitions eliminate ambiguity about parameter types and ranges.

Prompt Pattern 3: Request LLM-Friendly Descriptionsโ€‹

For each MCP tool, write descriptions that help an LLM understand:
1. WHEN to use this tool (what user intent triggers it)
2. WHAT parameters it takes (with units and ranges)
3. WHAT it returns (type and meaning)

Example: "Set the oven target temperature in Celsius (50-250).
Use when the user says 'preheat', 'set temp', or 'bake at X degrees'."

Why it works: Good tool descriptions are the #1 factor in the AI picking the right tool.

Prompt Pattern 4: Ask for Error Handlingโ€‹

Add input validation to each MCP tool callback:
- Clamp temperature to the DP range (50-250)
- Return -1 on invalid parameters
- For run_recipe, return {ok: false, available: [...]} on unknown recipe names

Why it works: The AI can self-correct when it gets structured error responses.

Prompt Pattern 5: Generate the Full Stack at Onceโ€‹

/tuyaopen-dev-loop
Create a complete Smart Oven project:
1. Cloud product with DPs (switch, temp_set, temp_current, timer)
2. Embedded firmware with mock hardware (app_oven.c)
3. MCP tools for all oven features (app_oven_mcp.c)
4. LVGL UI showing oven state on the T5-AI board display
5. Wire everything in app_chat_bot.c

Why it works: The /tuyaopen-dev-loop skill orchestrates the full cloud-to-device workflow.


Key Takeawaysโ€‹

  1. Start with the cloud product โ€” Create the product, define DPs, and add the AI Agent on the cloud platform before touching firmware. The product is the foundation.
  2. DPs are the contract โ€” Define them on the cloud, generate the header, and everything else follows.
  3. Tool descriptions matter โ€” Write them for LLMs: when to use, what params, what returns.
  4. Defer registration to MQTT connect โ€” Use tal_event_subscribe(EVENT_MQTT_CONNECTED, ..., SUBSCRIBE_TYPE_ONETIME) so tools register when the cloud link is ready.
  5. Keep hardware separate from MCP โ€” Your app_oven.c handles hardware; app_oven_mcp.c handles tool registration. Clean separation.
  6. Return structured data โ€” JSON responses with ok: false + available options let the AI self-correct.

Next Stepsโ€‹