MCPサーバーのツール設計 — AIが迷わない「道具」の分割と説明の書き方
はじめに
MCPサーバーの最小実装が動くようになると、次に必ずぶつかる壁があります。
- ツールが増えてきたが、AIがどれを使うべきか選べていない気がする
- 1つのツールに機能を詰め込んだら、引数の指定を間違え始めた
- 動いたのはいいけれど、AIが意図しない書き込みを実行してヒヤッとした
これらはモデルの性能の問題ではなく、ほぼツール設計の問題です。MCPは「AIに道具を渡す」プロトコルなので、道具の作り方がそのままAIの精度になります。
この記事では FastMCP でサーバーを書く前提で、実装で効くツール設計の原則をコードと合わせて整理します。
前提: 動く最小サーバー
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("task-server")
@mcp.tool()
def ping() -> str:
"""疎通確認用。サーバーが応答するかだけを確認する。"""
return "pong"
if __name__ == "__main__":
mcp.run()
この土台にツールを足していくとき、設計を誤るとAIの成功率が落ちます。以降はよくある失敗と、その修正方法です。
原則1: ツールは「動詞単位」で分割する
最も多いアンチパターンが何でも屋ツールです。
# ❌ アンチパターン: 1つのツールに全部やらせる
@mcp.tool()
def manage_task(action: str, task_id: str = "", title: str = "", status: str = "") -> str:
"""タスクを管理する。action は create/update/delete/list のいずれか。"""
...
一見DRYで便利ですが、AIから見ると次の問題が起きます。
-
actionの値によって必要な引数が変わるため、スキーマだけでは正否が判断できない(listなのにtitleを渡す、など) - 引数の取り違えに、ツール側で弾くまで気づけない
- 説明文が「全機能の説明」になり、どの場面で使うかが曖昧になる
正解は、動詞ごとにツールを分けることです。
# ✅ 良い設計: 1ツール1責務
@mcp.tool()
def create_task(title: str, due_date: str | None = None) -> dict:
"""新しいタスクを作成する。title は必須。due_date は YYYY-MM-DD 形式。"""
...
@mcp.tool()
def list_tasks(status: str = "open") -> list[dict]:
"""タスク一覧を取得する。status は open/done/all のいずれか。"""
...
@mcp.tool()
def complete_task(task_id: str) -> dict:
"""指定したタスクを完了にする。task_id は list_tasks で取得できる値を使う。"""
...
スキーマが引数の意味を語り、説明文が「いつ使うか」を語る。AIはこの2つだけを手がかりにツールを選ぶため、分割はそのまま精度に直結します。
ツール名も動詞で始めると、AIが役割を推測しやすくなります(create_* / list_* / get_* / search_* / update_* / delete_*)。
原則2: description は「AIへのプロンプト」として書く
MCPのツール定義にある description は、人間向けのドキュメントではなくプロンプトです。AIはこれを読んで呼び出しを決めます。ここを削ると、実装が正しくても使われません。
# ❌ 情報量がゼロ
@mcp.tool()
def search(q: str) -> list[dict]:
"""検索する。"""
# ✅ 用途・入力形式・戻り値・次の一手まで書く
@mcp.tool()
def search_documents(q: str, limit: int = 5) -> list[dict]:
"""社内ドキュメントを全文検索する。
キーワード検索のため、自然文の質問より語句を並べた方が精度が高い
(例: "経費 締め日")。関連度の高い順に最大 limit 件を返す。
各結果には doc_id / title / snippet が含まれる。本文全体が必要な場合は
get_document(doc_id) を続けて呼ぶこと。
"""
...
書くべきポイントは4つです。
- いつ使うか(全文検索であり、意味検索ではない)
- 入力の書き方(自然文より語句を並べる)
-
戻り値の構造(
doc_id/title/snippet) -
次の一手(全文が要るなら
get_document)
特に「次の一手」を書いておくと、AIがツールを連鎖させてタスクを完遂できるようになります。1回の呼び出しで完結しないタスクほど、この一文が効きます。
原則3: 戻り値は「AIが読む前提」で削る
戻り値は人間が読むログではなく、コンテキストに載るトークンです。生のAPIレスポンスをそのまま返すと、AIはノイズに埋もれて判断を誤ります。
# ❌ 生データを丸ごと返す(不要なフィールドが大量に混ざる)
return requests.get(f"{API}/issues/{id}").json()
# ✅ AIの判断に必要な項目だけを構造化して返す
raw = requests.get(f"{API}/issues/{id}").json()
return {
"id": raw["id"],
"title": raw["title"],
"state": raw["state"],
"assignee": (raw.get("assignee") or {}).get("name"),
"updated_at": raw["updated_at"],
"body_excerpt": raw["body"][:500], # 長文は切り詰める
}
判断に必要な情報を先頭に置き、長文は切り詰める。この一手間がAIの推論精度とコストの両方に効きます。特に一覧系ツールは、件数が増えるほど効いてきます。
原則4: 書き込み操作は「分離」と「確認」を設計に入れる
読み取りと書き込みは、別ツール・できれば別サーバーに分けるのが基本です。
-
読み取り(
list_*/get_*/search_*): 冪等で安全。積極的に公開してよい -
書き込み(
create_*/update_*): 影響範囲を説明文に明記し、可能なら dry-run を用意 -
破壊的(
delete_*/deploy_*): 別サーバーに隔離し、人間の承認を挟む
さらに、いきなり実行しない設計も有効です。
@mcp.tool()
def update_document(doc_id: str, body: str, dry_run: bool = True) -> dict:
"""ドキュメント本文を上書き更新する。
dry_run=True(既定)では変更差分のみを返し、実際には書き込まない。
内容を確認したうえで dry_run=False を指定すると反映される。
既存の本文は完全に置き換わるため、事前に get_document で確認すること。
"""
...
dry_run を既定にするだけでも、AIが誤って本番データを書き換える事故は大きく減ります。「AIは間違える前提で道具を作る」——これがMCP設計の基本姿勢です。
ツール設計チェックリスト
実装前に、次の7項目を確認してください。
- 1ツール1責務になっているか(動詞単位で分割されているか)
-
descriptionに「いつ使うか・入力形式・戻り値・次の一手」が書かれているか -
引数は型ヒント付きで、
Optionalと既定値が妥当か - 戻り値は必要項目に絞り、長文は切り詰めているか
- 読み取りと書き込みが分離されているか
- 破壊的操作に dry-run または承認ステップがあるか
- エラー時に「AIが次に何をすべきか」が分かるメッセージを返しているか
最後の項目は見落とされがちです。エラー文字列をそのまま返すのではなく、「再試行すべきか、別のツールに切り替えるべきか」がAIに伝わる文言にします。
まとめ
- MCPのツール設計は「AIに渡す道具の粒度」を決める作業であり、そのままAIの性能になる
- 何でも屋ツールは禁止。動詞ごとに分割してスキーマに意味を持たせる
-
descriptionはプロンプト。用途・入力形式・戻り値・次の一手を書く - 戻り値はAIが読むトークン。必要な項目だけを構造化して返す
- 書き込み・破壊的操作は分離と dry-run で事故を防ぐ
ツールを1つ足すたびに「AIはこれを見て正しく使えるか」と自問する。この積み重ねが、実用的なエージェントを作ります。
MCPの基本概念からTools/Resources/Promptsの実装、Claude Desktop統合、複数サーバーの運用、実践プロジェクト集まで体系的にまとめた書籍を出版しています。
読者特典(無料)
本記事のような実装パターンを横断的にまとめたチートシートと、Obsidian・Notionのテンプレート集を無料配布しています。8冊の内容から「何をどのツールでやるか」の判断チャートも含みます。
📗 『MCP実践入門』(Kindle・Kindle Unlimited読み放題対象)(Kindle)
ツール設計の章では、本記事の原則を実際のサーバー実装に落とし込む手順を、コード付きで解説しています。Kindle Unlimited会員は読み放題対象です。