道具ひとつ — 説明文がコードより重要だ

5 分
目標MCP サーバー講座 2 編目。道具をひとつ登録する。名前・説明・入力スキーマ・ハンドラの四つだが、そのうち三つは我々ではなく呼ぶ側が読む。だから説明文をうまく書くことがハンドラをうまく書くことより値が大きい。

1 編目のサーバーは何もできなかった。道具をひとつ付ける。

四つの部品

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

持ち帰るもの

  1. addTool の四つの部品 — そのうち三つは外が読む
  2. 点表記の名前 — 三つのうちに決めないと二十で直せない
  3. 説明文=インターフェース — モデルが道具を選ぶ根拠

次の編

引数を受け取る。そして受け取った引数が誤っているときに拒む方法。

サンプルを実行する

makemind-academy/course_server/
git clone https://github.com/makemind-academy/course_server
cd course_server
dart pub get
dart run bin/step2.dart
GitHub で開く →