概览
Mirobody 中的工具是res/mcp_tools/ 中的 C++ 文件。每个文件声明一个 Tool 并在编译时自注册;CMakeLists.txt 会把该目录下每个 .cpp 都 glob 进构建,因此整个流程就是:丢入一个新文件、重新构建,工具即上线 —— 无需手动注册,无需连接 router,无需手写 JSON schema。
这是一个编译期机制,而非运行时插件。C++ 引擎(Mirobody)中没有 Python 工具加载器 —— 参数在一张小表里声明,注册表会把它们展开成 MCP 的
inputSchema 以及 OpenAI / Gemini 的 function 描述符。一个工具的构成
一个工具声明五样东西(第六个raw_input_schema 是可选的应急出口):
参数类型有
Type::String、Integer、Number、Boolean、Array、Object。用带类型的访问器从 Args 读取参数(args.str("x")、args.integer("n", 20)、args.raw() 用于任意结构)。返回 Result::ok(json) 或 Result::error("message")。
快速开始
参考工具是echo.cpp —— 最小的完整示例。复制它然后开动。
1
创建文件
在
res/mcp_tools/ 中新增一个 .cpp:2
声明一个 Tool 和一个 handler
引入
mcp/tool.hpp,编写 handler,声明 Tool,并注册它:res/mcp_tools/weather.cpp
文件作用域处的
MIROBODY_REGISTER_TOOL(...) 这一行才是把工具接入的关键 —— 它初始化一个文件作用域的静态量,调用 registry().add(...)。3
重新构建
res/mcp_tools/*.cpp 会被 CMake glob,因此你的新文件无需任何其它改动即可被拾取。重启 ./mirobody,工具即上线。触及用户数据的工具
设置auth = true,引擎会在分发前解析调用者(JWT 或个人 MCP secret),并把身份作为 UserInfo 传入。对未认证的调用及时退出:
ToolContext 送达 —— 全部是借用指针,其中任何一个在对应后端未配置时都可能为空:
像内置工具那样,用一个干净的错误来容忍缺失的后端:
非扁平参数
声明的params 表会生成一个由扁平标量和数组构成的 JSON Schema,这覆盖了大多数工具。若某个工具的参数不是扁平的,用 args.raw() 读取原始对象(正如 render_chart 处理它的 ECharts option 那样),并且 —— 如果你需要对外声明的 schema 完全一致 —— 把 Tool 上可选的 raw_input_schema 字段设为一个会被逐字使用的 schema 字符串。
最佳实践
为模型撰写描述
为模型撰写描述
description 和每个 Param 的描述,是模型在决定是否以及如何调用你的工具时唯一拥有的上下文。要说清楚它做什么、何时使用,并在参数描述里给出一个具体的示例值。要让工具被正确调用,这一点比其它任何事都重要。返回结构化 JSON
返回结构化 JSON
用 rapidjson 构建一个小小的 JSON 对象并返回
Result::ok(to_json(d))。保持结果紧凑 —— 不要内联模型用不上的大块数据(看看 read_file 如何为二进制返回一个签名 url 而非字节本身)。干净地失败
干净地失败
对错误输入、缺失 auth 或未配置的后端,返回
Result::error("...")。注册表还会捕获任何 handler 异常并转成错误,因此一个工具绝不会让服务器崩溃。限定到调用者
限定到调用者
对
auth 工具,一切都从 user.user_id 派生。绝不要用 subject_user_id 来写入或暴露其它数据 —— 它是一个只读的护理圈提示,只有健康读取类工具才应遵从。验证工具已加载
用tools/list 请求 /mcp 端点,确认你的工具在返回的数组中:
res/mcp_tools/ 下、以一行 MIROBODY_REGISTER_TOOL(...) 结尾。
下一步
内置工具
默认提供的 9 个工具参考
MCP 集成
将你的工具连接到 Claude、Cursor 和 ChatGPT
工具与 Agent 概览
Agent、工具与 provider 如何协同