一个工具 — 说明文比代码更要紧
5 分钟目标MCP 服务端课程第二篇。注册一个工具。它由名字、说明、输入模式、处理器四块组成,其中三块不是我们读,而是调用方读。所以把说明文写好,比把处理器写好更值钱。
第一篇的服务端什么都干不了。给它接一个工具。
四个部件
server.addTool(
name: 'desk.count',
description: 'How many people are waiting at the desk right now',
inputSchema: const {'type': 'object', 'properties': {}},
handler: (args) async =>
CallToolResult(content: [TextContent(text: '{"waiting":3}')]),
);再声明把这项能力打开。
capabilities: ServerCapabilities(tools: ToolsCapability(listChanged: true))有三块不是我们读的
四块里只有 handler 是我们的代码在读。其余三块全都由调用方来读。
问一句 tools/list,出去的是这个。
{
"tools": [
{
"name": "desk.count",
"description": "How many people are waiting at the desk right now",
"inputSchema": {
"type": "object",
"properties": {}
}
}
]
}人写的客户端会照这份清单画按钮。模型则会读这份清单,决定该调哪个工具。 而这个判断的依据,就是 description 那一行。
所以那一行不是注释。它是会跑的代码。
命名
用 desk.count 这样带点的名字。前面是关于什么,后面是做什么。
desk.count 数有多少人在等
desk.admit 从队列里放人进来
camera.settings 读摄像头的设置工具只有三个时看着无所谓。到二十个,没规矩这件事就露出来了。 而且名字一旦发出去就改不了——它已经嵌在调用方的代码里。
说明文写不好会发生什么
假设两个工具是这样:
desk.count 「计数」
desk.admit 「放行」没写数的是什么、放的是谁。模型会随便挑一个。而且 挑错也不报错——工具照常执行,只是答案不着边际。
写成这样,它就挑得出来:
desk.count "How many people are waiting at the desk right now"
desk.admit "Admit a number of people from the queue"设备那篇之所以在点检表工具的说明文里写上 「这些步骤由工厂工程师制定,不得改写」,也是同一个理由。那句话是唯一能传达给模型的指令。
校验
第 2 级的检查只有一行。
ask step2 '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' > captures/s2.txt
grep -q 'desk.count' captures/s2.txt || die "step2: tool not listed"注册了和出现在清单里,是两件事。调了 addTool 却没打开 capability,清单就是空的。
自己跑一遍
dart run bin/step2.dart
bash verify.sh可以带走的
addTool的四个部件 — 其中三块由外面来读- 带点的命名 — 三个的时候不定,二十个的时候就改不动了
- 说明文=接口 — 模型挑工具的依据
下一篇
接收参数。以及参数不对时怎么拒绝。
运行示例
makemind-academy/course_server/git clone https://github.com/makemind-academy/course_server cd course_server dart pub get dart run bin/step2.dart