文章目录
- 1 什么是 MCP(Model Context Protocol)
- 2 为什么要做一个 ROS2 的 MCP 工具
- 3 工具选型
- 3.1 现阶段 Agent 能用的工具形态
- 3.2 为什么选择 Qoder,以及 Qoder 如何支持 MCP
- 3.2.1 为什么是 Qoder
- 3.2.2 Qoder 中对 MCP 的支持方式
- 4 MCP Server 实现(核心代码)
- 4.1 MCP Server初体验
- 4.2 获取 ROS2 Node List 的底层实现
- 4.3 暴露为 MCP Tool(Agent 可调用)
- 4.4 启动 MCP Server
- 5 解决关键问题:ROS2 环境如何注入 MCP
- 5.1 解决方案:启动脚本统一环境
- 6 在 Qoder 中注册 MCP 服务
- 6.1 注册MCP服务
- 6.2 验证
- 7 效果:Agent 如何“使用”这个能力
谨以本文记录我第一次使用自定义 MCP 服务,将Agent接入ROS2 系统的全过程。
1 什么是 MCP(Model Context Protocol)
简单来说,MCP 是一种标准化协议,用于让大模型:
- 发现你暴露的能力(Tools / Resources)
- 理解参数含义(Schema)
- 调用外部系统
- 将执行结果重新纳入上下文进行推理
与传统 API 不同,MCP 并不是“给人调用的接口”,而是:
专门为大模型设计的“能力协议”
它解决的是三个核心问题:
- 模型如何知道“你能做什么”
- 模型如何安全、结构化地调用能力
- 调用结果如何自然进入模型上下文
2 为什么要做一个 ROS2 的 MCP 工具
在机器人与自动化系统中,ROS2 是事实上的基础设施,但它有一个天然痛点:
系统状态复杂,但对外不“可读”
比如:
- 当前有哪些节点在运行?
- 系统是否处于预期状态?
- 是否可以安全执行下一步操作?
如果 Agent 想要真正参与系统决策,它必须先**“看见世界”**。
因此,我选择从一个最基础、也是最关键的能力入手:
让 Agent 能够获取当前 ROS2 Node List
这是一个:
- 只读
- 无副作用
- 非常适合 Agent 推理的能力
3 工具选型
3.1 现阶段 Agent 能用的工具形态
在当前阶段,大模型真正“可用”的能力主要集中在三类:
函数 / Tool 调用(Function Calling)
通过结构化参数调用外部能力,模型可以基于返回结果继续推理。上下文注入(Context / Resource)
将外部系统状态作为“只读信息”提供给模型,用于决策判断。有限的执行代理(Agent Loop)
在“看 → 想 → 做”的闭环中,逐步推进任务完成。
但在工程实践中可以明显感受到一个问题:
模型并不适合直接“操作系统”,它更擅长“理解系统状态”。
因此,本次设计并没有一上来就做“启动 / 停止 ROS2 节点”之类的强执行能力,而是从最安全、最基础、也最有价值的工具开始:
- 读取 ROS2 Node List
- 让 Agent 对当前系统状态形成认知
这类工具具备三个特点:
- 只读、无副作用
- 可反复调用
- 非常利于模型推理
这也是“Agent 先看世界,再动手”原则在工程层面的具体落地。
3.2 为什么选择 Qoder,以及 Qoder 如何支持 MCP
在工具选型上,我最终选择了Qoder作为 Agent 侧的承载平台,主要基于以下几个现实原因。
3.2.1 为什么是 Qoder
首先是可落地性。
Qoder 是阿里体系内推出的 Agent / 编程助手工具,在国内网络环境下具备几个非常明显的优势:
- 无需复杂网络环境
- 调用稳定
- 整体成本可控,性价比高
相比一些需要海外网络、或者对账号和配额要求较高的方案,Qoder 在工程实践中更容易长期使用。
其次是定位非常工程化。
Qoder并不是单纯的“聊天模型”,而是天然围绕:
- 代码理解
- 工具调用
- 工程上下文
来设计的,这使得它非常适合用来承载 MCP 这种“面向系统能力”的协议。
3.2.2 Qoder 中对 MCP 的支持方式
从使用体验来看,Qoder 对 MCP 的支持是非常直接且工程友好的。
其核心机制可以概括为三点:
- 通过配置文件注册 MCP Server
- 启动时自动发现 MCP Tool
- 在对话中按需调用并回收结果
也就是说,只要 MCP Server 符合标准协议,Qoder 就可以:
- 自动识别你暴露了哪些工具
- 理解工具参数含义
- 在合适的上下文中主动调用
- 将执行结果注入到模型上下文中
在本文的实现中:
- MCP Server 使用 Python 编写
- 通过 stdio 方式运行
- Qoder 负责进程生命周期管理
这使得整体架构非常干净:
Qoder ↓ MCP(标准协议) 自定义 MCP Server(Python) ↓ ROS2 rclpyAgent 不需要关心 ROS2 的任何细节,
而 ROS2 系统也不需要“适配模型”,
MCP 成为了两者之间稳定、可演进的接口层。
4 MCP Server 实现(核心代码)
4.1 MCP Server初体验
importasynciofrommcp.server.fastmcpimportFastMCP mcp=FastMCP("Hello-MCP")def_get_node_list()->list[str]:importrclpyfromrclpy.nodeimportNodeifnotrclpy.ok():rclpy.init()node=Node("mcp_list_nodes_tmp")nodes=node.get_node_names()node.destroy_node()returnnodes@mcp.tool()asyncdefget_ros2_node_list()->list[str]:returnawaitasyncio.to_thread(_get_node_list)if__name__=="__main__":mcp.run()FastMCP提供了一个非常轻量的方式来定义 MCP Server,不需要关心底层协议细节。
4.2 获取 ROS2 Node List 的底层实现
def_get_node_list()->list[str]:importrclpyfromrclpy.nodeimportNodeifnotrclpy.ok():rclpy.init()node=Node("mcp_list_nodes_tmp")nodes=node.get_node_names()node.destroy_node()returnnodes几点说明:
- 使用
rclpy原生接口 - 临时节点只用于查询,不参与通信
- 返回值是
list[str],非常利于模型理解
4.3 暴露为 MCP Tool(Agent 可调用)
@mcp.tool()asyncdefget_ros2_node_list()->list[str]:returnawaitasyncio.to_thread(_get_node_list)这里有两个关键点:
- 使用
@mcp.tool()显式声明能力 - 通过
asyncio.to_thread避免阻塞 MCP 主线程
这一步完成后,Agent 已经可以“看见”这个工具了。
4.4 启动 MCP Server
if__name__=="__main__":mcp.run()默认使用stdio 模式,非常适合 IDE / Agent 集成。
5 解决关键问题:ROS2 环境如何注入 MCP
一个非常容易踩的坑是:
conda 环境中的 Python 默认无法 import rclpy
原因是:
rclpy并不是 pip 包- 它依赖 ROS2 的环境变量
5.1 解决方案:启动脚本统一环境
#!/usr/bin/env bashsource/opt/ros/humble/setup.bashsource~/Softwares/Miniconda/bin/activate robot python3 path_to/server.py这个脚本保证了:
- ROS2 环境已就绪
- MCP Server 运行在 conda 的
robot环境中 - rclpy 可以被正确 import
6 在 Qoder 中注册 MCP 服务
最后一步,是让 Qoder 知道这个 MCP Server 的存在。
这里也很简单
6.1 注册MCP服务
按下ctrl+shift+,,进入Qoder设置页面。
选中MCP服务。
点击右上角 +添加,会打开一个json文件编辑页面
输入以下内容即可。
{"mcpServers":{"My-mcp":{"command":"/home/caston/Code/mcp/start_ros2_mcp.sh"}}}6.2 验证
添加完成后,不要急,我们还需要验证一下是否有问题,回到配置页面看一下是否和我的截图一样,工具一栏出现了
如果有,恭喜你,配置成功。
如果没有,标红,那么你还需要检查一下是不是哪里搞错了。根据报错解决以后,执行一下刷新。
如果一切ok,那就ok了。哈哈,说句废话。
配置完成后,Qoder 会:
- 启动 MCP Server
- 发现
get_ros2_node_list工具 - 在合适的时机自动调用
- 将返回的 Node List 注入模型上下文
此时,Agent 已经真正具备了感知 ROS2 系统状态的能力。
开始享用美食!!!!!
7 效果:Agent 如何“使用”这个能力
仍然简单!!!
问他,命令他。
ok,我们向Qoder提问:“看看现在有哪些ROS2节点”
Qoder老老实实的调用了自定义的MCP工具,并给出准确的答复。
nice!
从 Agent 的视角看,行为大致是:
- 调用
get_ros2_node_list - 获得当前系统节点列表
- 判断系统状态是否符合预期
- 根据指令考虑还有哪些步骤需要执行
- 决定是否执行下一步操作(未来扩展)
整个过程无需人为干预。
后续我会继续记录 MCP + ROS2 + Agent 的更多实践,最终目标是:
让大模型长出双手成为一个真正“理解并参与系统运行”的 Agent,而不仅是对话工具。