相关链接:
AI语音智能体开发日记(一)如何为"小智"服务器启用并调试 License 功能-CSDN博客
AI语音智能体开发日记(二)解决 Wi-Fi 配网小程序的兼容性问题-CSDN博客
AI语音智能体开发日记(三)解决小程序配网中的蓝牙命名与MAC地址获取问题-CSDN博客
AI语音智能体开发日记(四)在FreeRTOS中构建线程安全的UART2通信模块-CSDN博客
AI语音智能体开发日记(五)为智能设备注入"灵魂"------详解MCP工具的注册与使用-CSDN博客
AI语音智能体开发日记(六)为智能体注入旋律------七牛云音乐服务的接入与避坑指南-CSDN博客
AI语音智能体开发日记(七)搞定功放控制------详解GX8006平台Mute电平配置-CSDN博客
推荐链接:
AI语音智能体架构解析(二)大模型(AI 的大脑)-CSDN博客
AI语音智能体架构解析(三)智控台(指挥中心)-CSDN博客
AI语音智能体架构解析(四)AI 语音终端(执行器官)-CSDN博客
AI语音智能体架构解析(五)小程序/APP(遥控器)-CSDN博客
推荐链接:
AI 应用 图文 解说 (一) -- 百度智能云 实现 语音 聊天-CSDN博客
AI 应用 图文 解说 (二) -- 百度智能云 ASR LIM TTS 语音AI助手程序 -CSDN博客
开发手记:为智能设备注入"灵魂"------详解MCP工具的注册与使用
在嵌入式开发中,硬件驱动是设备的"躯体",而业务逻辑则是其"灵魂"。今天,我们来深入探讨一下 lightning 项目中,如何通过MCP(Machine Control Protocol)工具系统,将简单的硬件指令封装成可供上层应用调用的、具有明确语义的功能模块。
这个过程主要围绕 project/ln_model_public/app/servers/qiniu/mcp_server/mcp_tools/smart_toilet/mcp_tools.c 文件展开,可以分为三个核心步骤:定义工具语义、实现指令函数、以及注册工具。
第一步:定义工具语义 (Mcp的语义定义)
MCP工具的核心思想是将一个功能抽象成一个结构体。这个结构体不仅包含了功能的名称,更重要的是定义了它的自然语言描述和参数规范,让AI或上层应用能够"理解"这个功能是做什么的,以及如何使用它。
以控制机械狗前进的 mcp_tool_dog_forward 为例:

1// 文件: mcp_tools.c
2
3const mcp_tool_t mcp_tool_dog_forward = {
4 // 1. 工具的唯一标识名
5 .name = "dog.action.forward",
6
7 // 2. 工具的自然语言描述,用于AI理解
8 .description = "靠近的类似词语认为是前进,控制机械狗向前行走。可指定持续时间(单位:秒),例如'向前3秒'。如果不指定时间,默认前进1秒。最大支持10秒。",
9
10 // 3. 关联的处理函数
11 .call = dog_forward_handler,
12
13 // 4. 是否在独立任务中执行(对于有延时的操作,必须为true)
14 .call_in_task = true,
15
16 // 5. 定义工具的参数列表
17 .properties = {
18 {
19 .name = "duration", // 参数名
20 .type = kPropertyTypeInteger, // 参数类型:整数
21 .has_min_value = true, // 是否有最小值
22 .min_value = 1, // 最小值为1秒
23 .has_max_value = true, // 是否有最大值
24 .max_value = 10 // 最大值为10秒
25 },
26 { .name = NULL } // 参数列表结束标志
27 }
28};
通过这样的定义,一个名为 dog.action.forward 的工具就拥有了清晰的"身份":它知道自己是干什么的(description),需要什么参数(properties),以及具体由哪个函数来执行(call)。
第二步:实现指令函数 (Mcp工具指令函数)
定义好语义后,就需要实现具体的业务逻辑。dog_forward_handler 函数就是 mcp_tool_dog_forward 的执行体。

1// 文件: mcp_tools.c
2
3static cJSON *dog_forward_handler(mcp_property_t *args, int args_count)
4{
5 int duration_sec = 1; // 默认1秒
6
7 // 1. 解析参数:遍历传入的参数列表,查找名为 "duration" 的参数
8 for (int i = 0; i < args_count; i++) {
9 mcp_property_t *prop = &args[i];
10 if (strcmp(prop->name, "duration") == 0 && prop->type == kPropertyTypeInteger) {
11 duration_sec = prop->value.ival; // 获取参数值
12 break;
13 }
14 }
15
16 // 2. 业务逻辑:将秒转换为毫秒,并进行FreeRTOS延时
17 int duration_ms = duration_sec * 1000;
18 LOG(LOG_LVL_INFO, "[MCP] Dog forward for %d seconds (%d ms)\r\n", duration_sec, duration_ms);
19
20 // 模拟前进动作(例如,通过UART发送指令)
21 uint8_t cmd_buf[5] = {0x55, 0x01, 0x00, 0x00, 0xAA}; // 示例指令帧
22 for(int i = 0; i < duration_sec * 10; i++) {
23 // 构造并发送"前进"指令
24 cmd_buf[1] = 0x02;
25 cmd_buf[4] = cmd_buf[0] + cmd_buf[1] + cmd_buf[2] + cmd_buf[3]; // 计算校验和
26 safe_cmd_uart_write((char*)cmd_buf, 5);
27 vTaskDelay(pdMS_TO_TICKS(100)); // 延时100ms
28 }
29
30 // 模拟停止动作
31 cmd_buf[1] = 0x00;
32 cmd_buf[4] = cmd_buf[0] + cmd_buf[1] + cmd_buf[2] + cmd_buf[3];
33 safe_cmd_uart_write((char*)cmd_buf, 5);
34
35 LOG(LOG_LVL_INFO, "[MCP] Dog stop\r\n");
36 return NULL;
37}
这个函数清晰地展示了MCP工具的执行流程:
- 参数解析 :从
args数组中安全地提取出duration参数的值。 - 逻辑执行 :根据参数值,执行具体的硬件操作。在这里,它通过一个循环,持续调用我们之前实现的
safe_cmd_uart_write函数,向外部设备发送"前进"指令,并在结束后发送"停止"指令。
第三步:注册工具 (Mcp的语义注册)
定义和实现都完成后,最后一步是将这些工具"注册"到MCP核心系统中,使其生效。这个过程在 mcp_tools_register_all 函数中完成。

1// 文件: mcp_tools.c
2
3static int mcp_tools_register_all(void)
4{
5 int result = 0;
6 // 将所有定义好的工具,通过 mcp_core_register_tool 函数逐一注册
7 result |= mcp_core_register_tool(&mcp_tool_device_get_status);
8 result |= mcp_core_register_tool(&mcp_tool_device_set_volume);
9 // ... 其他工具 ...
10 result |= mcp_core_register_tool(&mcp_tool_dog_forward); // 注册"前进"工具
11 result |= mcp_core_register_tool(&mcp_tool_dog_backward); // 注册"后退"工具
12 result |= mcp_core_register_tool(&mcp_tool_dog_turn_left); // 注册"左转"工具
13 result |= mcp_core_register_tool(&mcp_tool_dog_turn_right); // 注册"右转"工具
14 // ... 更多工具 ...
15
16 return result;
17}
这个函数就像一个总控开关,在系统初始化时被调用,将我们定义的所有"狗"的动作(前进、后退、左转、右转等)以及其他设备功能(获取状态、设置音量等)全部添加到MCP的工具列表中。
总结
通过"定义语义 -> 实现函数 -> 注册工具"这三步,我们成功地将底层的硬件操作(如UART通信)封装成了一个个高级的、语义化的MCP工具。
这种设计模式的优势非常明显:
- 高内聚,低耦合:每个工具都是一个独立的模块,职责单一。
- 易于扩展:增加新功能时,只需按照同样的模式定义、实现并注册一个新的工具即可,无需修改核心框架。
- AI友好:清晰的自然语言描述和参数定义,为AI理解和调用设备功能提供了标准化的接口。
这不仅是代码的组织方式,更是一种让嵌入式设备变得更"智能"、更易于集成的优秀架构思想。