MCPの基本的な仕組み
皆さん、こんにちは。LP開発グループのn-ozawanです。
イラン文化圏では春分の日をノウルーズと言い、イラン暦の元日に該当します。
本題です。
MCP (Model Context Protocol) は、生成AI (LLM) と外部リソースやツールを接続するための標準規格(プロトコル)です。その仕組みはどうなっているのでしょうか?今回はMCPの仕組みについてのお話です。
目次
MCPの仕組み
サーバーとクライアント
MCPはクライアント・サーバー型で動作します。厳密に言うならば、MCPホスト、MCPクライアント、MCPサーバーの3つの構造となっています。

MCPホストは生成AIが動作する環境(アプリ)であり、VS CodeやClaude Desktopなどが該当します。MCPホストはユーザーからの指示を受け取り、MCPクライアントを通じて、MCPサーバーが提供する各種サービスを実行させます。通信するMCPサーバーは複数あり、MCPホストはMCPサーバーごとにMCPクライアントを作成し、それらを管理します。
MCPクライアントはMCPホストとMCPサーバーを橋渡しするコンポーネントです。生成AIからの命令を受けて、MCPサーバーを通して外部APIやローカルファイルへアクセスし、結果をAIへ返します。
MCPサーバーは生成AIにリソースや機能を提供するコンポーネントです。MCPサーバーは対応する外部システムごとに構築します。例えばGitHubへのアクセスや操作を可能するためのMCPサーバー、などです。また、「サーバー」と聞くとクラウド上に構築されたものと想像しますが、実際の多くはローカル環境でMCPサーバーを動作させます。前回、draw.ioのMCPを使ってみましたが、あれはローカル環境にdraw.io用のMCPサーバーが動作しています。

JSON-RPC
MCPクライアントとMCPサーバーはJSON-RPCという規格で通信を行います。RPCとは、Remote Procedure Call の略で、ネットワーク上の別のコンピュータで動作するプログラム(関数やメソッド)を、手元のプログラムから直接呼び出して実行させるプロトコルです。JSON-PRCとは、そんなRPCをJSONで通信するプロトコルです。
例えば、MCPクライアントは以下のようなJSONを、MCPサーバーへ送信します。
{
"jsonrpc": "2.0", // JSONRPC のバージョン
"Id": 1, // 識別子
"method": "tools/call", // ツールの実行
"params": { // 引数
"name": "example",
"arguments": {
"query": "hello world!"
}
}
}MCPサーバーは受け取ったJSONの内容を元に処理を実行します。そしてその処理が成功した場合、以下のようなレスポンスをMCPクライアントへ返却します。
{
"jsonrpc": "2.0", // JSON-RPC のバージョン
"id": 1, // 識別子(リクエストと同じ番号が設定される)
"result": { // 処理が成功した場合の結果
"content": [
{
"type": "text",
"text": "hello world!",
}
]
}
}MCPサーバーの基本機能
MCPサーバーにはプリミティブと呼ばれる3つの基本機能があります。
ツール
ツールは、生成AIが外部システムと連携して、何かしらの処理を実行するための機能です。
MCPクライアントは、MCPサーバーがどんなツールを提供しているのかを問い合わせます。その際は、"method": "tools/list"のリクエストを送信します。
{
"jsonrpc": "2.0", // JSONRPC のバージョン
"id": 1, // 識別子
"method": "tools/list", // MCPサーバーが提供するツールの一覧を取得
"params": {} // 引数
}MCPサーバーは"method": "tools/list"のリクエストに対して、利用可能なツールの情報をレスポンスします。以下のレスポンスでは、fetch_pageというツールが提供されていることが分かります。
{
"jsonrpc": "2.0", // JSON-RPC のバージョン
"id": 1, // 識別子
"result": { // ツールの一覧を返却する
"tools": [
{
"name": "fetch_page", // ツール名
"inputSchema": {
"type": "object",
"required": ["url"]
}
}
]
}
}そのレスポンスから、生成AIは使用するツールを判断して、MCPクライアントがそのツールを実行するリクエストを送信します。
{
"jsonrpc": "2.0", // JSONRPC のバージョン
"id": 1, // 識別子
"method": "tools/call", // MCPサーバーが提供するツールを実行
"params": { // 引数
"name": "fetch_page", // 実行したいツール名
"arguments": {
"url": "https://www.ios-net.co.jp"
}
}
}リソース
リソースは、生成AIが外部システムが持つリソースを取得するための機能です。
MCPクライアントは、MCPサーバーからどのようなリソースを取得できるのかを問い合わせます。その際は、"method": "resources/list"のリクエストを送信します。
{
"jsonrpc": "2.0", // JSONRPC のバージョン
"id": 1, // 識別子
"method": "resources/list", // リソースの一覧を取得
"params": {} // 引数
}MCPサーバーは"method": "resources/list"のリクエストに対して、取得可能なリソースをレスポンスします。以下のレスポンスでは、file:///example/README.mdというリソースが取得可能であることがわかります。
{
"jsonrpc": "2.0", // JSON-RPC のバージョン
"id": 1, // 識別子
"result": { // リソースの一覧を返却する
"resources": [
{
"uri": "file:///example/README.md",
"mimeType": "text/markdown"
}
]
}
}そのレスポンスから、生成AIはMCPクライアントを通して、外部システムのリソースを取得するリクエストを送信します。
{
"jsonrpc": "2.0", // JSONRPC のバージョン
"id": 1, // 識別子
"method": "resources/read", // リソースの取得
"params": { // 引数
"uri": "file:///example/README.md"
}
}プロンプト
プロンプトは、よく使う指示や質問(プロンプト)の形式を予め用意しておく「テンプレート」です。処理した結果や取得したリソースを生成AIが有効活用するためには、それに適したプロンプトが必要です。そのようなプロンプトをMCPサーバーから取得することができます。プロンプトのあり/なしや、その内容によっては生成AIの精度が大きく変わってきますので、MCPサーバーからプロンプトを提供することで、安定した精度を確保します。
MCPクライアントとの通信はツールやリソースとほぼ同じで、"method": "prompts/list"でプロンプトの一覧を取得し、"method": "prompts/get"でプロンプトを取得します。
おわりに
MCPはAIに関係するプロトコルですので、複雑で難しい印象を受けていましたが、意外とシンプルな仕様でした。
今回はMCPクライアントからMCPサーバーへの通信をあげましたが、その逆で、MCPサーバーからMCPクライアントへの通信もあります。ファイルの削除など、本当にその操作をしても良いのか?とユーザーに確認するために、MCPサーバーからMCPクライアントへ問い合わせます。
ではまた。
