The 9Mod MCPBoard uses the UART-MCP protocol for communication between the STM32 MCU and the Ai-WV01-32S AI module. This document describes the frame format, tool registration/call flow, and error codes.
TIP
For the complete UART-MCP protocol documentation, refer to UART-MCP Protocol and User Guide.
1. UART Configuration
| Parameter | Value |
|---|---|
| Baud Rate | 115200 (default, configurable 300~2000000) |
| Data Bits | 8 |
| Stop Bits | 1 |
| Parity | None |
| Frame Terminator | \r\n (CR+LF) |
WARNING
Every JSON command must end with \r\n, otherwise the AI module will not recognize it.
2. JSON Frame Format
2.1 Common Frame Structure
All messages are JSON-format with these top-level fields:
| Field | Type | Required | Description |
|---|---|---|---|
role | string | Yes | Sender: "AI board" or "MCU" |
msgType | string | Yes | Message type (see below) |
data | string/object | Depends | Message content |
2.2 Message Types (msgType)
| msgType | Direction | Description |
|---|---|---|
status | AI → MCU | Status notification (startup, WiFi, wake, etc.) |
mcp_set | AI → MCU | MCP control command (AI calls a tool) |
mcp_check | AI → MCU | MCP query command |
MCP Text | AI → MCU | AI subtitle text |
tool_list | MCU → AI | Register MCP tool definitions |
ctrl_result | MCU → AI | Tool execution result |
volume | Bidirectional | Volume set/query |
wake-up | MCU → AI | Wake up AI module |
uart_baudrate | MCU → AI | Baud rate change |
3. AI Module → MCU Messages
3.1 Status Notifications
The AI module sends status changes to the MCU:
{"role":"AI board","msgType":"status","data":"<status info>"}Common status values:
| data value | Description |
|---|---|
AI Start | AI device started |
1.WiFi connect OK | WiFi connected |
2.WakeUP | Module woken up |
3.Sleep | Module sleeping |
4.NetCFG | Network configuration mode |
5.NetERR | Network error |
6.OTAUPDATE | OTA started |
7.OTA OK | OTA successful |
8.OTA ERR | OTA failed |
OK | Command executed successfully |
ERROR:<message> | Command execution failed |
3.2 MCP Control Commands (Tool Call)
The AI module sends a tool call request:
{"role":"AI board","msgType":"mcp_set","tools":"<tool_name>","data":{"<param>":<value>}}Example — AI calling the LED control tool:
{"role":"AI board","msgType":"mcp_set","tools":"led","data":{"enable":true}}3.3 MCP Query Commands
The AI module queries a tool's status:
{"role":"AI board","msgType":"mcp_check","tools":"<tool_name>"}Example — Query LED status:
{"role":"AI board","msgType":"mcp_check","tools":"led"}3.4 Subtitle Text
AI responses are delivered as subtitle text, suitable for OLED display:
{"role":"AI board","msgType":"MCP Text","data":"The current temperature is 25.3°C"}4. MCU → AI Module Messages
4.1 Registering MCP Tools
The MCU sends tool definitions to the AI module. Each tool includes a name, description, properties, and methods.
This is automatically handled by the emMCP library's emMCP_RegistrationTools() function. The underlying JSON format is:
<command_prefix>{"role":"MCU","msgType":"tool_list","data":[
{
"tool_name":"<tool_name>",
"description":"<description>",
"properties":{
"<prop_name>":{"description":"<desc>","type":"<type>"}
},
"methods":{
"<method_name>":{"description":"<desc>","parameters":{
"<param_name>":{"description":"<desc>","type":"<type>","required":true}
}}
}
}
]}Restrictions
- Tool names must not use
SpeakerorLight(system reserved) - Tool names should only contain
[a-z0-9_] - Maximum number of tools configurable via
MCP_SERVER_TOOL_NUMBLE_MAX(default: 4)
4.2 Tool Control Result
After executing the tool callback, the MCU returns the result to the AI:
{"role":"MCU","msgType":"ctrl_result","data":"<result JSON string>"}Success example:
{"role":"MCU","msgType":"ctrl_result","data":"{\"result\":\"ok\"}"}4.3 Tool Query Result
{"role":"MCU","msgType":"ctrl_result","data":"<query result JSON>"}Example — Radar status query:
{"role":"MCU","msgType":"ctrl_result","data":"{\"detected\":true}"}5. MCP Tool Registration and Call Flow
5.1 Tool Registration Flow
5.2 Tool Control Flow
5.3 Tool Query Flow
6. Error Codes
When the AI module detects a protocol error, it returns ERROR:<message>:
| Error Message | Description | Severity | Solution |
|---|---|---|---|
ERROR:Tools NULL | Tool list is empty | 🟢 | Create tools and call RegistrationTools |
ERROR:Invalid JSON format | Data is not valid JSON | 🔴 | Check JSON format |
ERROR:Invalid role | Missing role field | 🔴 | Check JSON for "role" |
ERROR:Invalid msgType | Missing msgType field | 🔴 | Check JSON for "msgType" |
ERROR:Invalid MCP | Missing MCP keyword | 🔴 | Check JSON for "MCP" |
ERROR:Invalid tools | Missing tools keyword | 🔴 | Check JSON for "tools" |
ERROR:Invalid tool_name | Missing tool_name | 🔴 | Check JSON for "tool_name" |
ERROR:tool_name already exists | Name conflict or reserved name | 🔴 | Change tool name, avoid Speaker/Light |
ERROR:Failed to save tools | Failed to save tools | 🔴 | Restart module and re-register |
ERROR:Failed to allocate memory | Memory allocation failed | 🔴 | Restart module |
ERROR:Failed to parse tools | Tool data not valid JSON | 🔴 | Check JSON format of tool definitions |
ERROR:params is null | MCP command missing params | 🟡 | Ask AI to re-send the command |
ERROR:tools call failed | Internal tool retrieval failed | 🟡 | Ask AI to re-send the command |
ERROR:Timeout | MCU did not respond in time | 🟡 | Ensure result is returned within 5 seconds |
For the complete error code list, refer to UART-MCP Error Messages.
7. Data Flow Example: Complete Conversation
A complete voice-controlled LED on/off session:
[User] → Voice → "Turn on the LED"
[AI] → UART → {"role":"AI board","msgType":"mcp_set","tools":"led","data":{"enable":true}}
[MCU] → Internal → Parse via emMCP → Call led.setRequestHandler
[MCU] → GPIO → HAL_GPIO_WritePin(PC13, SET)
[MCU] → UART → {"role":"MCU","msgType":"ctrl_result","data":"{\"result\":\"ok\"}"}
[AI] → Voice → "LED turned on"
