10 MCPサーバーの実装 エラーハンドリング - HiroyukiMakita/mcp-server-tutorial GitHub Wiki
10. MCPサーバーの実装 - エラーハンドリング
堅牢なアプリケーションを作成する上で、エラーハンドリングは非常に重要な要素です。MCPサーバーも例外ではありません。 外部APIとの通信、予期しない入力、内部ロジックの不具合など、様々な原因でエラーが発生する可能性があります。 このセクションでは、作成中の天気情報MCPサーバーにおいて、どのようにエラーを処理し、クライアント(AIエージェントなど)に適切に伝えるかについて説明します。
エラーハンドリングの基本方針
- エラーの捕捉:
try...catch
ブロックを使用して、エラーが発生しうる箇所(特にAPIリクエストや外部ライブラリの呼び出し)でエラーを捕捉します。 - エラー情報の特定: 発生したエラーがどのような種類のものか(例:
axios
のAPI通信エラー、zod
のバリデーションエラー、その他の予期せぬエラー)を特定します。 - ログ出力: サーバー側のデバッグや問題追跡のために、エラーの詳細情報をコンソールなどに出力します。
- クライアントへの通知: MCPクライアントに対して、エラーが発生したことと、可能であればエラーの原因を示すメッセージを返します。MCPツールでは、戻り値の
Content
オブジェクトにisError: true
フラグを立ててエラーであることを示します。
1. APIクライアントにおけるエラーハンドリング
「08-MCPサーバーの実装-APIクライアント」で作成した getCurrentWeather
関数や getForecast
関数では、既に基本的なエラーハンドリングが実装されています。
// (getCurrentWeather 関数のエラー処理部分の再掲)
// ...
} catch (error) {
if (axios.isAxiosError(error)) {
// axios によるネットワークエラーやAPIからのエラーレスポンス
console.error(`現在の天気取得APIエラー (都市: ${city}):`, error.response?.data || error.message);
const errorMessage = (error.response?.data as any)?.message || error.message; // APIからのエラーメッセージを取得試行
return { error: `天気の取得に失敗しました: ${errorMessage}` }; // エラー情報をオブジェクトで返す
}
// axios以外の予期せぬエラー
console.error(`予期せぬエラー (現在の天気取得 - 都市: ${city}):`, error);
return { error: '天気の取得中に予期せぬエラーが発生しました。' };
}
// ...
ポイント:
axios.isAxiosError(error)
:axios
に起因するエラーかどうかを判別します。これにより、ネットワークの問題やAPIサーバーからのエラーレスポンス(4xx, 5xx系)を他のエラーと区別できます。error.response?.data
: APIサーバーがエラーレスポンスボディに詳細なエラー情報を含めている場合、これを参照します。OpenWeatherMap APIの場合、message
プロパティにエラー内容が含まれていることがあります。console.error
: サーバーログにエラーの詳細を出力します。- 関数の戻り値: 正常なレスポンスの型 (
CurrentWeatherResponse
など) とは異なる、エラー情報を含むオブジェクト ({ error: string }
) を返すことで、呼び出し元がエラーを判別できるようにしています。
2. MCPツール定義におけるエラーハンドリング
「09-MCPサーバーの実装-MCPツール定義」で定義したMCPツール内でも、APIクライアント関数からのエラーを適切に処理し、MCPクライアントに伝えます。
// (get_current_weather ツールのエラー処理部分の再掲)
// ...
const weatherData = await getCurrentWeather(city);
if ('error' in weatherData) { // APIクライアント関数がエラーオブジェクトを返した場合
return {
content: [{ type: "text", text: `エラー: ${weatherData.error}` }],
isError: true, // MCPクライアントにエラーであることを伝える
};
}
// ...
ポイント:
- APIクライアント関数がエラーオブジェクト (
{ error: string }
) を返したかどうかをチェックします。 - エラーの場合、MCPツールの戻り値として
content
にエラーメッセージを含め、isError: true
を設定します。これにより、MCPクライアントはツール実行が失敗したことを認識できます。
zod
によるバリデーションエラーの処理
3. zod
を使用してAPIレスポンスやツールの入力値をパース・バリデーションする際にもエラーが発生する可能性があります。safeParse
を使用すると、パース結果オブジェクトからエラー情報を取得できます。
// (APIクライアント関数内でのzodパース処理の再掲)
// ...
const parseResult = CurrentWeatherResponseSchema.safeParse(response.data);
if (!parseResult.success) {
// パース失敗
console.error("現在の天気APIレスポンスのパースに失敗:", parseResult.error.flatten());
// parseResult.error.issues に詳細なエラー情報が含まれる
// parseResult.error.message で包括的なエラーメッセージを取得可能
return { error: `APIレスポンスの形式が不正です: ${parseResult.error.message}` };
}
// パース成功
return parseResult.data;
// ...
ポイント:
parseResult.success
: パースとバリデーションが成功したかどうかを示します。parseResult.error
: パース失敗時にZodError
オブジェクトが含まれます。parseResult.error.flatten()
: エラー情報をフィールドごとに分かりやすく整形します。parseResult.error.issues
: 個々のバリデーションエラーの詳細なリスト。parseResult.error.message
:zod
が生成する包括的なエラーメッセージ文字列。
- これらの情報をログに出力したり、クライアントに返すエラーメッセージに含めたりすることで、問題の原因究明に役立ちます。
4. APIキー未設定時のエラー処理
環境変数 OPENWEATHER_API_KEY
が設定されていない場合、API呼び出しは必ず失敗します。
「09-MCPサーバーの実装-MCPツール定義」の冒頭で、APIキーが存在しない場合はサーバーを起動せずにエラー終了する処理を追加しました。
// (APIキーチェック部分の再掲)
const OPENWEATHER_API_KEY = process.env.OPENWEATHER_API_KEY;
if (!OPENWEATHER_API_KEY) {
console.error('致命的エラー: 環境変数 OPENWEATHER_API_KEY が設定されていません。サーバーを起動できません。');
process.exit(1); // プロセスを終了
}
これは、サーバー起動時の前提条件が満たされていない場合に、早期に問題を検出し、無駄な処理を防ぐための重要なエラーハンドリングです。
まとめ
エラーハンドリングは、アプリケーションの信頼性と使いやすさを向上させるために不可欠です。 以下の点を意識して実装しましょう。
- エラーが発生しうる箇所を特定し、適切に捕捉する。
- エラーの原因を特定し、ログに詳細な情報を残す。
- ユーザー(この場合はMCPクライアント)に分かりやすいエラーメッセージを返す。
- 可能な場合は、エラーからの回復処理や代替処理を検討する(今回のチュートリアルではそこまで踏み込みません)。
次のページでは、これまでに作成した各部品を組み合わせて src/index.ts
を完成させ、ユニットテストの導入について説明します。