One Tool — the Description Matters More Than the Code
5 minThe server from part 1 could do nothing. Attach one tool.
Four pieces
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}')]),
);And declare the capability on.
capabilities: ServerCapabilities(tools: ToolsCapability(listChanged: true))Three of them we never read
Of the four, only handler is read by our code. The other three are all read by whoever calls.
Ask tools/list and this goes out.
{
"tools": [
{
"name": "desk.count",
"description": "How many people are waiting at the desk right now",
"inputSchema": {
"type": "object",
"properties": {}
}
}
]
}A human-written client draws a button from this list. A model decides which tool to call from it. The basis of that decision is one line of description.
So that line is not a comment. It is running code.
Naming
Use dotted names like desk.count. What it is about, then what it does.
desk.count counts who is waiting
desk.admit admits people from the queue
camera.settings reads the camera's settingsWith three tools it looks like it does not matter. At twenty, the absence of a rule shows. And a name cannot be changed once it ships — it is embedded in the caller's code.
What happens without a good description
Say two tools read like this.
desk.count "count"
desk.admit "admit"Nothing says what is counted or who is admitted. A model picks either. And picking wrong raises no error — the tool runs fine, only the answer is beside the point.
Written this way, it can choose.
desk.count "How many people are waiting at the desk right now"
desk.admit "Admit a number of people from the queue"The plant piece put "these steps are set by the plant engineer and must not be paraphrased" into a checklist tool's description for the same reason. That sentence is the only instruction that reaches the model.
Verification
Step 2's check is one line.
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"Registering and appearing in the list are two different events. Call addTool without turning the capability on and the list goes out empty.
Run it yourself
dart run bin/step2.dart
bash verify.shWhat to take
- The four pieces of
addTool— three of them are read from outside - Dotted names — decide at three tools or you cannot fix it at twenty
- Description as interface — it is what a model chooses from
Next
Take arguments. And refuse them when they are wrong.
Run the sample
cd course-server dart pub get dart run bin/step2.dart