09 MCPサーバーの実装 MCPツール定義 - HiroyukiMakita/mcp-server-tutorial GitHub Wiki
09. MCPサーバーの実装 - MCPツール定義
これまでに、APIレスポンスの型定義と、実際にOpenWeatherMap APIと通信するAPIクライアント関数を作成しました。 いよいよ、これらの部品を使ってMCPサーバーに具体的な「ツール」を定義していきます。
MCPツールは、MCPサーバーが外部に提供する機能の単位です。クライアント(RooのようなAIエージェント)は、このツール名を指定し、定義された入力パラメータを渡すことで、サーバーの機能を呼び出すことができます。
このセクションでは、以下の2つのツールを定義します。
get_current_weather
: 指定した都市の現在の天気情報を取得する。get_forecast
: 指定した都市の数日間の天気予報を取得する。
McpServer
インスタンスの準備
1. まず、weather-server/src/index.ts
ファイルで McpServer
クラスのインスタンスを作成します。
このインスタンスに対してツールを登録していきます。
// weather-server/src/index.ts
import { Server as McpServer } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
ListToolsRequestSchema,
CallToolRequestSchema,
ListResourcesRequestSchema,
ListResourceTemplatesRequestSchema,
ReadResourceRequestSchema
} from "@modelcontextprotocol/sdk/types.js";
import { z } from 'zod';
2. ツール定義とハンドラーの作成
MCPサーバーでは、以下の重要なハンドラーを実装する必要があります:
ListToolsRequestSchema
: 利用可能なツールの一覧を返すCallToolRequestSchema
: 実際のツール実行を処理するListResourcesRequestSchema
: 利用可能なリソースの一覧を返すListResourceTemplatesRequestSchema
: 利用可能なリソーステンプレートの一覧を返す
これらのハンドラーを使って、ツールとリソースの定義と実行ロジックを実装していきます。
ツール一覧を返すハンドラー(ListToolsRequestSchema)の実装
[前半部分は同じなので省略...]
リソース関連のハンドラーの実装
// リソーステンプレートの定義
const weatherResourceTemplate = {
uriTemplate: "weather://{city}/{type}",
parameters: {
city: z.string(),
type: z.enum(["current", "forecast"])
}
};
// リソース一覧を返すハンドラー
server.setRequestHandler(ListResourcesRequestSchema, async () => {
return {
resources: [
{
name: "weather",
description: "都市の気象情報を提供するリソース",
uriTemplate: weatherResourceTemplate.uriTemplate,
uri: "weather://tokyo/current" // サンプルURIを提供
},
],
};
});
// リソーステンプレート一覧を返すハンドラー
server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => {
return {
resourceTemplates: [
{
name: "weather",
description: "都市の気象情報を提供するリソース",
uriTemplate: "weather://{city}/{type}",
parameters: {
city: {
type: "string",
description: "天気を取得したい都市名"
},
type: {
type: "string",
description: "取得する情報の種類(current または forecast)",
enum: ["current", "forecast"]
}
},
required: ["city", "type"]
}
]
};
});
ポイント:
- リソーステンプレートはURI形式で定義し、パラメータは波括弧
{}
で囲みます - リソース一覧ではサンプルURIを提供して、クライアントが使い方を理解しやすくします
- テンプレート一覧では各パラメータの詳細な説明とバリデーションルールを提供します
リソース読み取りのハンドラーの実装
// リソース読み取りのハンドラー
server.setRequestHandler(ReadResourceRequestSchema, async (request: ReadResourceRequest) => {
const uri = new URL(request.params.uri);
const [city, type] = uri.pathname.split('/').slice(1);
if (!city || !type) {
throw new Error("Invalid URI format: city and type are required");
}
if (!["current", "forecast"].includes(type)) {
throw new Error(`Invalid resource type: ${type}. Must be either 'current' or 'forecast'`);
}
// 以降は各typeに応じた処理...
});
ポイント:
- URIのパスから必要なパラメータを抽出し、適切にバリデーション
- パラメータの有無と値の妥当性を確認
- エラーメッセージは具体的に、原因と期待される値を含める