MCPツールの作り方:AIに武器を与える
AIは、良い道具がなければただの賢い頭脳
前回、私たちは簡単なMCPサーバーを立ち上げ、AIからのリクエストを受け付ける箱を用意しました。しかし、AIに真に価値のある作業をしてもらうためには、その箱の中に入れる「ツール」の質が重要になります。
この記事では、より実践的で堅牢なMCPツールを設計し、実装するための具体的な方法を解説します。ツールの引数をどう受け取るか、エラーをどう扱うか、そしてAIにとって「使いやすい」ツールとは何か。これらの点に焦点を当てて、AIに強力な武器を与えていきましょう。
ツールの基本構造:ただの関数
はじめに思い出してほしいのは、MCPツールの実体は ただの関数 であるということです。特別な構文やクラス継承は必要ありません。しかし、AIから利用されることを前提とした、いくつかの設計上の配慮が必要です。
# Pythonでのツールの例 def get_file_size(path: str) -> int: """指定されたファイルのサイズをバイト単位で返す""" import os try: size = os.path.getsize(path) return size except FileNotFoundError: # エラーの扱い方が重要 raise Exception(f"ファイルが見つかりません: {path}")
この単純な例にも、良いツールを作るためのヒントが隠されています。
要するに、「ツールはただの関数だが、AIが利用することを意識した設計が必要である」ということです。
パラメータ(引数)の受け取り方
AIがツールを呼び出す際、どのようにして引数(パラメータ)が渡されるのでしょうか。JSON-RPCの仕様により、パラメータは 配列(リスト) または オブジェクト(辞書) の形式で渡されます。
■1. 配列(Positional Parameters)
引数が順番に意味を持つ場合に利用されます。シンプルで分かりやすいですが、引数の順番を間違えやすいという欠点もあります。
AIからのリクエスト (JSON)
{"method": "add", "params": [5, 10]}
Node.jsでの実装
function add(params) { const [a, b] = params; return a + b; }
■2. オブジェクト(Named Parameters)
引数に名前が付いているため、順番を気にする必要がなく、可読性が高まります。引数が多い場合や、オプションの引数がある場合に特に有効です。
AIからのリクエスト (JSON)
{"method": "create_user", "params": {"name": "佐藤", "role": "admin"}}
Pythonでの実装
def create_user(name: str, role: str = "guest"): # ... 処理 ... return {"status": "success", "user": name, "role": role}
Pythonのライブラリは、多くの場合、辞書をキーワード引数に自動的にマッピングしてくれます。
どちらを使うかは設計次第ですが、一般的には 引数が3つ以上になる場合はオブジェクト形式の方が堅牢 です。
要するに、「ツールの引数は配列かオブジェクトで渡され、可読性と堅牢性を考えて形式を選ぶべきである」ということです。
戻り値の設計:AIが理解しやすいように
ツールが処理を終えた後、AIに返す値(戻り値)もまた重要です。AIがその後の対話や判断に利用しやすいように、構造化されたデータを返すことを心がけましょう。
- 単純な値:
123
や"hello"
のような単一の値を返すこともできます。 - 構造化されたオブジェクト: 複数の情報を返す場合は、JSONオブジェクト(Pythonでは辞書、Node.jsではオブジェクト)を使うのがベストです。
悪い例
return "ユーザーID: 123, 名前: 鈴木"
(ただの文字列)
良い例
return {"user_id": 123, "name": "鈴木"}
(構造化データ)
良い例のように返せば、AIは「ユーザーIDは123ですね」と正確に認識できますが、悪い例では文字列を解析する必要があり、誤認識の元になります。
要するに、「戻り値は、AIが後続処理で使いやすいように、できるだけ構造化されたデータ(JSON)で返す」のが良いプラクティスです。
エラーハンドリング:失敗を正直に伝える
ツールは常に成功するとは限りません。ファイルが見つからなかったり、APIの認証に失敗したり。そのような場合に、何が起きたのかをAIに正確に伝えることが、システム全体の安定性にとって不可欠です。
JSON-RPCには、エラーを伝えるための標準的なフォーマットが定められています。ライブラリを使っていれば、通常は関数内で 例外(Exception)を発生させる だけで、ライブラリが適切なエラーレスポンスを生成してくれます。
def get_user(user_id: int): user = db.find_user(user_id) if user is None: # 例外を発生させる raise ValueError(f"ID {user_id} のユーザーは存在しません") return user
このように実装すると、ユーザーが見つからなかった場合に、クライアント(AI)に対して「そのようなユーザーはいない」というエラーが明確に伝わります。AIはその情報に基づき、「別のIDを試しますか?」といった次の対話に進むことができます。
要するに、「ツール内で問題が起きたら例外を発生させ、AIに失敗したことを正直に伝える」ことが重要です。黙って処理を中断してはいけません。
まとめ
今回は、AIにとって使いやすく、堅牢なMCPツールを設計・実装するための要点を見てきました。
- ツールの実体はただの関数だが、AIが使うことを意識した設計が求められる。
- 引数の受け取り方には配列とオブジェクトの2形式があり、適切に使い分ける。
- 戻り値は、AIが処理しやすいように構造化されたデータ(JSON)で返すのが望ましい。
- 処理が失敗した場合は、例外を発生させてAIにエラーを明確に伝える必要がある。
これらの原則を守ることで、あなたの作るツールはAIにとって信頼できる「手足」となり、より高度で複雑なタスクの自動化が可能になります。
次回は、これらのツール作成の知識を活かして、より具体的な応用例である「データベースとの連携」に挑戦します。