速水拓真 営業×AI 実践シリーズ
書き下ろし

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から見ると次の問題が起きます。

  1. action の値によって必要な引数が変わるため、スキーマだけでは正否が判断できないlist なのに title を渡す、など)
  2. 引数の取り違えに、ツール側で弾くまで気づけない
  3. 説明文が「全機能の説明」になり、どの場面で使うかが曖昧になる

正解は、動詞ごとにツールを分けることです。

# ✅ 良い設計: 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統合、複数サーバーの運用、実践プロジェクト集まで体系的にまとめた書籍を出版しています。

📗 MCP実践入門 — AIエージェントを拡張するModel Context Protocol(Kindle)

ツール設計の章では、本記事の原則を実際のサーバー実装に落とし込む手順を、コード付きで解説しています。Kindle Unlimited会員は読み放題対象です。


著者: 葉山悠希 — 書籍シリーズは Zenn / Amazon で公開中

営業×AI実践シリーズ 全3作

Kindle Unlimited 読み放題対象 — 追加料金なしで読めます

← 記事一覧へ

← 導入効果を4週間で数字にする — 営業のAI化を…問い合わせフォームに送った営業メールは、3秒で消… →