MCP(Model Context Protocol)完全解説:AIとツールを繋ぐ新標準プロトコル

MCP(Model Context Protocol)完全解説:AIとツールを繋ぐ新標準プロトコル

Anthropicが開発したMCP(Model Context Protocol)の仕組み、アーキテクチャ、セットアップ方法、実装コード例、活用事例を日本語で詳しく解説。

2026年3月17日6分で読了

MCPとは何か?

2024年末にAnthropicが発表した**MCP(Model Context Protocol)**は、AIモデルが外部ツールやデータソースとやり取りするための標準プロトコルです。2025〜2026年にかけて急速に普及し、現在ではAI開発の世界で最も注目されている技術標準の一つとなっています。

簡単に言えば、MCPはAIモデルとさまざまなツール(データベース、ファイルシステム、外部API、開発ツールなど)を接続するための「共通言語」です。これにより、開発者は各ツールごとに異なるインテグレーションを作る必要がなくなり、一度MCP対応のサーバーを作れば、あらゆるMCP対応クライアント(AIモデル)から利用できるようになります。

なぜMCPが必要なのか?

MCPが登場する以前、AIモデルに外部ツールを使わせるためには、それぞれのAIシステム専用のカスタム統合を作成する必要がありました。OpenAI用の統合コード、Anthropic用の統合コード、Google用の統合コード――これらを別々に管理するのは非効率で、メンテナンスも大変でした。

MCPは、この問題を「USB-Cポートのような標準コネクタ」として解決します。MCPに対応したツールは、MCPに対応したどのAIモデルでも使えるようになるのです。


MCPのアーキテクチャ

MCPはクライアント・サーバーアーキテクチャを採用しています。

┌─────────────────────────────────────────────────────────┐
│                    MCP クライアント                        │
│           (Claude Desktop、Cursor、カスタムアプリ)        │
└─────────────────────┬───────────────────────────────────┘
                      │ MCP Protocol(JSON-RPC 2.0)
         ┌────────────┼────────────┐
         ▼            ▼            ▼
   ┌──────────┐ ┌──────────┐ ┌──────────┐
   │ MCPサーバー│ │ MCPサーバー│ │ MCPサーバー│
   │(ファイル)│ │(データベース)│(外部API)│
   └──────────┘ └──────────┘ └──────────┘

主要コンポーネント

MCPホスト(Host): AIモデルを実行するアプリケーション(Claude Desktop、カスタムのAIアプリケーションなど)。ホストはMCPクライアントを管理し、AIモデルとMCPサーバーの間を仲介します。

MCPクライアント(Client): ホスト内でMCPサーバーとの接続を管理するコンポーネント。各MCPサーバーに対して1つのクライアントが対応します。

MCPサーバー(Server): 外部ツールやデータソースへのアクセスを提供する軽量なプログラム。開発者が実装する部分で、ファイルシステム、データベース、GitHub APIなど、様々な機能をAIモデルに提供します。

MCPのトランスポート層

MCPは複数のトランスポート方式をサポートしています:

  1. stdio(標準入出力):ローカル開発で最も一般的。クライアントとサーバーが同じマシン上で動作する場合に使用。
  2. HTTP + SSE(Server-Sent Events):リモートサーバーとの通信に使用。スケーラブルなデプロイに対応。
  3. WebSocket:双方向のリアルタイム通信が必要な場合に使用。

MCPが提供する機能

MCPサーバーは主に3つの種類の機能を提供できます:

1. ツール(Tools)

AIモデルが実行できる操作です。ファイルの読み書き、APIコールの実行、データベースクエリの発行などが含まれます。

{
  "name": "read_file",
  "description": "ファイルシステムからファイルを読み取る",
  "inputSchema": {
    "type": "object",
    "properties": {
      "path": {
        "type": "string",
        "description": "読み取るファイルのパス"
      }
    },
    "required": ["path"]
  }
}

2. リソース(Resources)

AIモデルが参照できるデータやコンテンツです。ファイル、データベースレコード、Webページのコンテンツなどが含まれます。

{
  "uri": "file:///Users/username/documents/report.pdf",
  "name": "四半期レポート",
  "description": "2026年Q1の業績レポート",
  "mimeType": "application/pdf"
}

3. プロンプト(Prompts)

再利用可能なプロンプトテンプレートです。特定のタスクに最適化されたプロンプトをサーバー側で定義し、クライアントから呼び出すことができます。


MCPサーバーの実装:TypeScript編

実際にMCPサーバーを実装してみましょう。ここでは、簡単なファイル操作とJSONデータの処理を行うMCPサーバーを作成します。

プロジェクトのセットアップ

mkdir my-mcp-server
cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk
npm install -D typescript @types/node ts-node

tsconfig.jsonを作成:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true
  }
}

基本的なMCPサーバーの実装

// src/index.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import * as fs from "fs/promises";
import * as path from "path";

// MCPサーバーのインスタンスを作成
const server = new Server(
  {
    name: "my-file-server",
    version: "1.0.0",
  },
  {
    capabilities: {
      tools: {},
    },
  }
);

// 利用可能なツールのリストを定義
server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: "read_file",
        description: "指定したパスのファイルを読み取ります",
        inputSchema: {
          type: "object",
          properties: {
            path: {
              type: "string",
              description: "読み取るファイルのパス",
            },
          },
          required: ["path"],
        },
      },
      {
        name: "write_file",
        description: "指定したパスにファイルを書き込みます",
        inputSchema: {
          type: "object",
          properties: {
            path: {
              type: "string",
              description: "書き込むファイルのパス",
            },
            content: {
              type: "string",
              description: "ファイルの内容",
            },
          },
          required: ["path", "content"],
        },
      },
      {
        name: "format_json",
        description: "JSON文字列を整形して返します",
        inputSchema: {
          type: "object",
          properties: {
            json_string: {
              type: "string",
              description: "整形するJSON文字列",
            },
            indent: {
              type: "number",
              description: "インデントのスペース数(デフォルト: 2)",
            },
          },
          required: ["json_string"],
        },
      },
    ],
  };
});

// ツールの実行ハンドラー
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  try {
    if (name === "read_file") {
      const filePath = args?.path as string;
      const content = await fs.readFile(filePath, "utf-8");
      return {
        content: [
          {
            type: "text",
            text: content,
          },
        ],
      };
    }

    if (name === "write_file") {
      const filePath = args?.path as string;
      const content = args?.content as string;

      // ディレクトリが存在しない場合は作成
      await fs.mkdir(path.dirname(filePath), { recursive: true });
      await fs.writeFile(filePath, content, "utf-8");

      return {
        content: [
          {
            type: "text",
            text: `ファイルを正常に書き込みました: ${filePath}`,
          },
        ],
      };
    }

    if (name === "format_json") {
      const jsonString = args?.json_string as string;
      const indent = (args?.indent as number) ?? 2;

      const parsed = JSON.parse(jsonString);
      const formatted = JSON.stringify(parsed, null, indent);

      return {
        content: [
          {
            type: "text",
            text: formatted,
          },
        ],
      };
    }

    throw new Error(`不明なツール: ${name}`);
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : String(error);
    return {
      content: [
        {
          type: "text",
          text: `エラーが発生しました: ${errorMessage}`,
        },
      ],
      isError: true,
    };
  }
});

// サーバーを起動
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("MCPサーバーが起動しました");
}

main().catch(console.error);

MCPサーバーの実装:Python編

Pythonでも同様のMCPサーバーを実装できます。

# server.py
import asyncio
import json
import os
from pathlib import Path
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp import types

# MCPサーバーのインスタンスを作成
app = Server("python-file-server")


@app.list_tools()
async def list_tools() -> list[types.Tool]:
    """利用可能なツールのリストを返す"""
    return [
        types.Tool(
            name="read_file",
            description="指定したパスのファイルを読み取ります",
            inputSchema={
                "type": "object",
                "properties": {
                    "path": {
                        "type": "string",
                        "description": "読み取るファイルのパス"
                    }
                },
                "required": ["path"]
            }
        ),
        types.Tool(
            name="list_directory",
            description="ディレクトリの内容を一覧表示します",
            inputSchema={
                "type": "object",
                "properties": {
                    "path": {
                        "type": "string",
                        "description": "一覧表示するディレクトリのパス"
                    }
                },
                "required": ["path"]
            }
        ),
        types.Tool(
            name="search_files",
            description="ファイル内の文字列を検索します",
            inputSchema={
                "type": "object",
                "properties": {
                    "directory": {
                        "type": "string",
                        "description": "検索するディレクトリ"
                    },
                    "pattern": {
                        "type": "string",
                        "description": "検索する文字列パターン"
                    },
                    "file_extension": {
                        "type": "string",
                        "description": "対象ファイルの拡張子(例: .py, .js)"
                    }
                },
                "required": ["directory", "pattern"]
            }
        )
    ]


@app.call_tool()
async def call_tool(
    name: str, arguments: dict
) -> list[types.TextContent]:
    """ツールを実行する"""

    if name == "read_file":
        file_path = arguments["path"]
        try:
            with open(file_path, "r", encoding="utf-8") as f:
                content = f.read()
            return [types.TextContent(type="text", text=content)]
        except FileNotFoundError:
            return [types.TextContent(
                type="text",
                text=f"エラー: ファイルが見つかりません: {file_path}"
            )]

    elif name == "list_directory":
        dir_path = arguments["path"]
        try:
            entries = os.listdir(dir_path)
            formatted = "\n".join(
                f"{'📁' if os.path.isdir(os.path.join(dir_path, e)) else '📄'} {e}"
                for e in sorted(entries)
            )
            return [types.TextContent(type="text", text=formatted)]
        except FileNotFoundError:
            return [types.TextContent(
                type="text",
                text=f"エラー: ディレクトリが見つかりません: {dir_path}"
            )]

    elif name == "search_files":
        directory = arguments["directory"]
        pattern = arguments["pattern"]
        extension = arguments.get("file_extension", "")

        results = []
        for root, dirs, files in os.walk(directory):
            for file in files:
                if extension and not file.endswith(extension):
                    continue
                file_path = os.path.join(root, file)
                try:
                    with open(file_path, "r", encoding="utf-8") as f:
                        for line_num, line in enumerate(f, 1):
                            if pattern in line:
                                results.append(
                                    f"{file_path}:{line_num}: {line.rstrip()}"
                                )
                except (UnicodeDecodeError, PermissionError):
                    continue

        if results:
            return [types.TextContent(
                type="text",
                text="\n".join(results)
            )]
        else:
            return [types.TextContent(
                type="text",
                text=f"'{pattern}' を含むファイルは見つかりませんでした"
            )]

    else:
        raise ValueError(f"不明なツール: {name}")


async def main():
    async with stdio_server() as (read_stream, write_stream):
        await app.run(
            read_stream,
            write_stream,
            app.create_initialization_options()
        )


if __name__ == "__main__":
    asyncio.run(main())

Claude DesktopでMCPサーバーを使う

Claude DesktopでカスタムMCPサーバーを使用するには、設定ファイルを編集します。

設定ファイルの場所

  • macOS~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows%APPDATA%\Claude\claude_desktop_config.json

設定例

{
  "mcpServers": {
    "my-file-server": {
      "command": "node",
      "args": ["/path/to/my-mcp-server/dist/index.js"],
      "env": {
        "NODE_ENV": "production"
      }
    },
    "python-server": {
      "command": "python",
      "args": ["/path/to/server.py"]
    },
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/username/Documents"
      ]
    }
  }
}

設定後、Claude Desktopを再起動すると、MCPサーバーが有効になります。


既存のMCPサーバー(公式・コミュニティ製)

Anthropicと開発者コミュニティによって、多数のMCPサーバーが公開されています。

公式MCPサーバー

サーバー名機能
@modelcontextprotocol/server-filesystemローカルファイルシステムへのアクセス
@modelcontextprotocol/server-githubGitHub APIとの連携
@modelcontextprotocol/server-postgresPostgreSQLデータベースへのアクセス
@modelcontextprotocol/server-sqliteSQLiteデータベースへのアクセス
@modelcontextprotocol/server-brave-searchBrave Search APIによるWeb検索
@modelcontextprotocol/server-puppeteerPuppeteerによるブラウザ自動化

人気のコミュニティMCPサーバー

  • mcp-server-notion:NotionのページとデータベースへのAIアクセス
  • mcp-server-slack:SlackチャンネルとメッセージへのAIアクセス
  • mcp-server-jira:Jiraチケットの読み書き
  • mcp-server-aws:AWSリソースの管理と操作
  • mcp-server-docker:Dockerコンテナの管理

実際の活用事例

ケース1:コードレビューの自動化

GitHubのMCPサーバーを使って、AIにプルリクエストを自動レビューさせる仕組みを構築できます。AIはコードの変更差分を読み込み、問題点を指摘し、改善提案を生成します。

# GitHubサーバーのセットアップ
npx @modelcontextprotocol/server-github \
  --token $GITHUB_TOKEN

ケース2:データベースへの自然言語クエリ

PostgreSQLのMCPサーバーを使って、自然言語でデータベースに問い合わせることができます。「先月の売上上位10商品を教えて」というプロンプトを送るだけで、AIが適切なSQLを生成して実行し、結果を返します。

JSONレスポンスの確認にはJSONフォーマッターが便利です。

ケース3:ドキュメントの自動生成

ファイルシステムのMCPサーバーを使って、AIがコードベースを読み込み、APIドキュメントやREADMEを自動生成できます。

プロンプト例:
「src/apiディレクトリのすべてのTypeScriptファイルを読んで、
各エンドポイントのAPIドキュメントをMarkdown形式で生成してください」

MCPのセキュリティ考慮事項

MCPサーバーはファイルシステムやデータベースなど、センシティブなリソースへのアクセスを提供できるため、セキュリティには十分注意が必要です。

主要なセキュリティ対策

1. 最小権限の原則 MCPサーバーには、必要最小限の権限だけを与えましょう。ファイルシステムサーバーは、特定のディレクトリだけにアクセスを限定すべきです。

2. 入力バリデーション

// パストラバーサル攻撃を防ぐ
function validatePath(userPath: string, basePath: string): string {
  const resolvedPath = path.resolve(basePath, userPath);
  if (!resolvedPath.startsWith(basePath)) {
    throw new Error("パスが許可された範囲外です");
  }
  return resolvedPath;
}

3. 認証とアクセス制御 リモートMCPサーバーを公開する場合は、適切な認証機構を実装してください。

4. ログの記録 すべてのツール呼び出しをログに記録し、不正なアクセスを検出できるようにしましょう。


MCPとFunctionCallingの違い

MCPと混同されやすいのが、OpenAIのFunction Calling(現在はTool Useと呼ばれる)です。

比較項目MCPFunction Calling / Tool Use
標準化オープンスタンダード各プロバイダー独自
ツールの定義場所サーバー側クライアント側(APIリクエスト時)
再利用性高い(どのMCPクライアントでも使用可能)低い(各AIシステム専用)
動的なツール発見対応非対応(事前定義が必要)
ステートフル対応非対応
主な用途永続的なツール統合単発のAPIコール

MCPの将来展望

MCPは2025〜2026年にかけて急速に普及しており、今後さらなる発展が期待されます。

短期的な展望(2026年):

  • より多くのIDEとの統合(VS Code、JetBrains)
  • エンタープライズ向けセキュリティ機能の強化
  • より豊富な公式MCPサーバーの提供

中長期的な展望:

  • AIエージェントの「ツールエコシステム」として確立
  • クロスAIプラットフォームの標準として採用拡大
  • IoTデバイスや物理システムとのMCP統合

まとめ

MCP(Model Context Protocol)は、AIモデルと外部ツールを接続するための革新的な標準プロトコルです。USB-Cが様々なデバイスを接続する共通規格となったように、MCPはAIエコシステムにおける共通コネクターとなりつつあります。

開発者として今からMCPを学んでおくことは、AI開発のトレンドを先取りする上で非常に重要です。簡単なMCPサーバーから始めて、徐々に複雑な統合に挑戦してみてください。

APIレスポンスのデバッグにはJSONフォーマッターを、実装中の正規表現パターンのテストには別途ツールを活用しながら、効率的なMCP開発を進めましょう。

MCPは単なるプロトコルではなく、AIが現実世界のシステムと深く統合される未来への入り口です。今こそ、この新しい標準を習得する最良のタイミングです。

関連記事