Claude Code用MCPサーバーを高速構築する方法

Audrey Lopez

Audrey Lopez

12 6月 2025

Claude Code用MCPサーバーを高速構築する方法

Model Context Protocol(MCP)は、AIアシスタントが外部ツールやデータソースと連携する方法に革命をもたらします。MCPは、AIアプリケーションのためのユニバーサルなUSB-Cポートのようなものと考えてください。Claude Codeを、想像できるほぼすべてのデータソース、API、ツールに接続するための標準化された方法を提供します。この包括的なガイドでは、独自のMCPサーバーをゼロから構築する方法を順を追って説明し、Claude Codeが組み込み機能を超えてその能力を拡張するカスタム機能にアクセスできるようにします。

データベース、API、ファイルシステムを統合したい場合でも、まったく新しいカスタムツールを作成したい場合でも、MCPは無限の拡張性の基盤を提供します。このチュートリアルの終わりまでに、動作するMCPサーバーを手に入れ、あらゆるユースケースに合わせてそれを拡張する方法を理解できるでしょう。

💡
美しいAPIドキュメントを生成する優れたAPIテストツールをお探しですか?

最高の生産性で開発チームが連携するための統合されたオールインワンプラットフォームをお探しですか?

Apidogは、あなたのすべての要求に応え、Postmanをはるかに手頃な価格で置き換えます
button

MCPサーバーとは何か、なぜ話題になっているのか

MCPの何が違うのか

MCP(Model Context Protocol)は、Anthropicが開発したオープンプロトコルで、AIモデルが標準化されたインターフェースを通じて外部サーバーと通信できるようにします。特定のエンドポイントをハードコーディングする従来のAPI統合とは異なり、MCPはAIアシスタントが外部ツールを動的に発見、理解、利用するための構造化された方法を提供します。

MCPの素晴らしさは、その発見可能性にあります。Claude CodeがあなたのMCPサーバーに接続すると、利用可能なツール、その使い方、受け入れるパラメータを自動的に学習します。これは、Claude Code自体を更新することなく新しい機能を追加できることを意味します。

MCPアーキテクチャの詳細

このプロトコルは、明確に定義された役割を持つクライアントサーバーアーキテクチャに従います。

通信フローの説明

Claude Codeが外部ツールを使用する必要がある場合、次のことが起こります。

  1. 発見フェーズ: Claude Codeが利用可能なツールについてあなたのサーバーに問い合わせます
  2. スキーマ検証: あなたのサーバーはツール定義と入力スキーマで応答します
  3. ツール選択: Claude Codeはユーザーのリクエストに基づいて適切なツールを選択します
  4. 実行フェーズ: Claude Codeは検証済みのパラメータでツール呼び出しを送信します
  5. 結果処理: あなたのサーバーはリクエストを処理し、構造化された結果を返します

このフローにより、タイプセーフティ、適切なエラー処理、およびすべてのMCP統合における一貫した動作が保証されます。

前提条件と環境設定

システム要件分析

MCPサーバーを構築する前に、開発環境を理解し、適切なツールを選択する必要があります。MCPサーバーは複数の言語で構築できますが、PythonとTypeScriptが最も一般的にサポートされており、豊富なツールが提供されています。

Python開発の場合:

TypeScript/JavaScript開発の場合:

コア依存関係:

ステップバイステップの環境準備

1. Claude Code CLIのインストール

Claude Code CLIは、MCPサーバーを管理するための主要なツールです。どのディレクトリからでもアクセスできるようにグローバルにインストールします。

# Claude Codeをグローバルにインストール
npm install -g @anthropic-ai/claude-code

グローバルインストールが重要な理由: グローバルインストールにより、claudeコマンドがシステム全体で利用可能になり、異なるディレクトリからMCPサーバーを登録する際のパス関連の問題を防ぎます。

2. インストールの確認

Claude Codeが正しくインストールされ、アクセス可能であることを確認します。

# インストールを確認し、バージョンをチェック
claude --version

# 利用可能なコマンドをチェック
claude --help

3. 最初の重要な権限設定

このステップは絶対に不可欠であり、見落とされがちです。

# 権限バイパス付きの初期設定を実行
claude --dangerously-skip-permissions

このコマンドがすること:

なぜ必要か: このステップがないと、MCPサーバーはClaude Codeとの安全な接続を確立できず、認証失敗や接続タイムアウトが発生します。

セキュリティ上の考慮事項: --dangerously-skip-permissionsフラグは開発環境では安全ですが、通常のセキュリティプロンプトをバイパスします。本番環境では、各権限要求を慎重に確認してください。

重要な構成: MCPスコープの理解

構成スコープが重要な理由

MCPサーバーを構築する際の最も一般的な落とし穴の1つは、不適切な構成スコープ管理です。スコープを理解することは、MCPサーバーがClaude Codeでいつ、どこで利用可能になるかを決定するため、非常に重要です。多くの開発者は、スコープの誤構成に起因する「サーバーが見つかりません」というエラーのデバッグに何時間も費やしています。

Claude Codeは、セキュリティを維持しながら柔軟性を提供するように設計された階層的な構成システムを使用しています。各スコープは特定の目的を果たし、異なるユースケースがあります。

構成スコープ階層の説明

1. プロジェクトスコープ (.mcp.json) - 最高優先度

場所: プロジェクトルートディレクトリの.mcp.jsonファイル内

目的: その特定のプロジェクトで作業しているときにのみ利用可能であるべきプロジェクト固有のMCPサーバー

ユースケース: プロジェクト固有のデータベース接続、プロジェクト固有のリンター、またはカスタムビルドツール

プロジェクトスコープが適切な場合:

2. ユーザースコープ (-scope user) - グローバル構成

場所: ユーザーのホームディレクトリ構成

目的: すべてのプロジェクトおよびディレクトリでグローバルに利用可能なMCPサーバー

ユースケース: 天気API、計算機ツール、システムユーティリティなどの汎用ツール

ユーザースコープが通常推奨される理由:

3. ローカルスコープ (デフォルト) - ディレクトリ固有

場所: 現在の作業ディレクトリのコンテキスト

目的: 短期的な、一時的なMCPサーバーのセットアップ

制限事項: その特定のディレクトリからClaude Codeを実行している場合にのみ動作します

一般的な構成ミス

❌ 間違ったアプローチ (ローカルスコープ - 機能が制限される):

claude mcp add my-server python3 /path/to/server.py

問題点: このサーバーは、登録した正確なディレクトリにいる場合にのみ動作します。

✅ 正しいアプローチ (ユーザースコープ - グローバルアクセス):

claude mcp add --scope user my-server python3 ~/.claude-mcp-servers/my-first-server/server.py

利点: このサーバーは、システム上のどのディレクトリからでも動作します。

戦略的なディレクトリ計画

推奨されるディレクトリ構造

長期的な保守性のために、整理されたディレクトリ構造を作成します。

# 永続的な保存場所を作成
mkdir -p ~/.claude-mcp-servers/

# 機能別に整理
mkdir -p ~/.claude-mcp-servers/apis/
mkdir -p ~/.claude-mcp-servers/utilities/
mkdir -p ~/.claude-mcp-servers/development/

整理された構造の利点

保守性: 後でサーバーを見つけて更新するのが簡単

セキュリティ: 異なる種類のツールの明確な分離

バックアップ: 1つのディレクトリをバックアップするだけで、すべてのMCPサーバーを簡単にバックアップ

共有: チームメンバーとサーバー構成を簡単に共有

スコープのトラブルシューティングガイド

スコープの問題の診断

MCPサーバーが表示されない場合は、次の診断シーケンスに従います。

  1. 現在のスコープ構成を確認:
claude mcp list

  1. 競合するプロジェクトスコープを持つディレクトリにいないことを確認:
ls .mcp.json

  1. 異なるディレクトリからテスト:
cd ~ && claude mcp list
cd /tmp && claude mcp list

スコープの問題の修正

問題: サーバーが1つのディレクトリでのみ動作する

解決策: ローカル構成を削除し、ユーザースコープで再追加

# 問題のあるローカル構成を削除
claude mcp remove my-server

# グローバルユーザースコープで再追加
claude mcp add --scope user my-server python3 ~/.claude-mcp-servers/my-first-server/server.py

最初のMCPサーバーの構築

開発プロセスの理解

MCPサーバーを構築するには、MCPプロトコルとユースケースの特定の要件の両方を理解する必要があります。基本を理解するために基本的な「Hello World」サーバーから始め、その基盤の上に構築を進めます。

開発プロセスは以下のフェーズに従います。

  1. サーバー構造のセットアップ: 基本的なファイル構造とエントリポイントの作成
  2. プロトコル実装: 必須のMCPメソッドの実装
  3. ツール定義: サーバーが提供するツールの定義
  4. 登録とテスト: Claude Codeへのサーバー追加と機能検証
  5. 機能強化と本番化: 実際の機能とエラー処理の追加

ステップ1: プロジェクトの基盤と構造

開発環境の作成

まず、MCPサーバーのための適切な開発環境を確立します。

# MCPサーバーディレクトリに移動
cd ~/.claude-mcp-servers/

# 新しいサーバープロジェクトを作成
mkdir my-first-server
cd my-first-server

# プロジェクト構造を初期化
touch server.py
touch requirements.txt
touch .env

この構造が重要な理由

整理された開発: 各サーバーを独自のディレクトリに保持することで、競合を防ぎ、メンテナンスが容易になります。

依存関係の分離: 各サーバーは、他のサーバーに影響を与えることなく、独自の要件を持つことができます。

構成管理: 環境ファイルを使用すると、値をハードコーディングすることなく安全な構成が可能になります。

MCPサーバーの要件の理解

すべてのMCPサーバーは、3つのコアJSON-RPCメソッドを実装する必要があります。

  1. initialize: 接続を確立し、サーバーの機能を宣言します
  2. tools/list: 利用可能なツールとそのスキーマを返します
  3. tools/call: 提供されたパラメータで特定のツールを実行します

ステップ2: コアサーバーフレームワークの実装

基本的なMCPサーバーテンプレートを含むserver.pyファイルを作成します。

#!/usr/bin/env python3
"""
Claude Code統合のためのカスタムMCPサーバー
"""

import json
import sys
import os
from typing import Dict, Any, Optional

# 適切なMCP通信のためにバッファリングなしの出力を保証
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 1)
sys.stderr = os.fdopen(sys.stderr.fileno(), 'w', 1)

def send_response(response: Dict[str, Any]):
    """Claude CodeにJSON-RPCレスポンスを送信"""
    print(json.dumps(response), flush=True)

def handle_initialize(request_id: Any) -> Dict[str, Any]:
    """MCP初期化ハンドシェイクを処理"""
    return {
        "jsonrpc": "2.0",
        "id": request_id,
        "result": {
            "protocolVersion": "2024-11-05",
            "capabilities": {
                "tools": {}
            },
            "serverInfo": {
                "name": "my-custom-server",
                "version": "1.0.0"
            }
        }
    }

def handle_tools_list(request_id: Any) -> Dict[str, Any]:
    """Claude Codeのために利用可能なツールをリストアップ"""
    tools = [
        {
            "name": "hello_world",
            "description": "簡単なデモンストレーションツール",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "name": {
                        "type": "string",
                        "description": "挨拶する名前"
                    }
                },
                "required": ["name"]
            }
        }
    ]

    return {
        "jsonrpc": "2.0",
        "id": request_id,
        "result": {
            "tools": tools
        }
    }

def handle_tool_call(request_id: Any, params: Dict[str, Any]) -> Dict[str, Any]:
    """Claude Codeからのツール呼び出しを実行"""
    tool_name = params.get("name")
    arguments = params.get("arguments", {})

    try:
        if tool_name == "hello_world":
            name = arguments.get("name", "World")
            result = f"Hello, {name}! Your MCP server is working perfectly."
        else:
            raise ValueError(f"Unknown tool: {tool_name}")

        return {
            "jsonrpc": "2.0",
            "id": request_id,
            "result": {
                "content": [
                    {
                        "type": "text",
                        "text": result
                    }
                ]
            }
        }
    except Exception as e:
        return {
            "jsonrpc": "2.0",
            "id": request_id,
            "error": {
                "code": -32603,
                "message": str(e)
            }
        }

def main():
    """JSON-RPC通信を処理するメインサーバーループ"""
    while True:
        try:
            line = sys.stdin.readline()
            if not line:
                break

            request = json.loads(line.strip())
            method = request.get("method")
            request_id = request.get("id")
            params = request.get("params", {})

            if method == "initialize":
                response = handle_initialize(request_id)
            elif method == "tools/list":
                response = handle_tools_list(request_id)
            elif method == "tools/call":
                response = handle_tool_call(request_id, params)
            else:
                response = {
                    "jsonrpc": "2.0",
                    "id": request_id,
                    "error": {
                        "code": -32601,
                        "message": f"Method not found: {method}"
                    }
                }

            send_response(response)

        except json.JSONDecodeError:
            continue
        except EOFError:
            break
        except Exception as e:
            if 'request_id' in locals():
                send_response({
                    "jsonrpc": "2.0",
                    "id": request_id,
                    "error": {
                        "code": -32603,
                        "message": f"Internal error: {str(e)}"
                    }
                })

if __name__ == "__main__":
    main()

コードアーキテクチャの説明

入出力設定: 最初の数行は、MCP通信に不可欠なバッファリングなしのI/Oを構成します。バッファリングされた出力は、プロトコルを壊すメッセージ配信の遅延を引き起こす可能性があります。

JSON-RPC処理: メインループはstdinからJSON-RPCリクエストを読み取り、stdoutにレスポンスを書き込みます。これはローカルサーバー通信のためのMCP仕様に従います。

エラー処理戦略: コードは複数の層のエラー処理を実装しています。

プロトコル準拠: 各レスポンスには、適切な相関のための必須フィールドjsonrpc: "2.0"とリクエストIDが含まれています。

ステップ3: サーバーの準備とテスト

サーバーを実行可能にする

# サーバーを実行可能にする
chmod +x server.py

実行権限が重要な理由: MCPサーバーはClaude Codeによってサブプロセスとして起動されます。実行権限がないと、起動は不可解な権限エラーで失敗します。

手動プロトコルテスト

Claude Codeに登録する前に、サーバーのプロトコル実装をテストします。

# 初期化ハンドシェイクをテスト
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | python3 server.py

期待される応答構造: プロトコルバージョンと機能を含むJSON応答が表示されるはずです。エラーメッセージが表示されるか、出力がない場合は、Pythonのインストールとスクリプトの構文を確認してください。

検証ステップ

続行する前に、これらの検証チェックを実行します。

  1. 構文チェック: python3 -m py_compile server.py
  2. インポートテスト: python3 -c "import json, sys, os"
  3. 実行テスト: 手動プロトコルテストが機能することを確認

ステップ4: Claude Codeへの登録

サーバーの追加

適切なスコープと絶対パスを使用してサーバーを登録します。

# グローバルユーザースコープで登録し、ユニバーサルアクセスを可能にする
claude mcp add --scope user my-first-server python3 ~/.claude-mcp-servers/my-first-server/server.py

重要な詳細:

検証とトラブルシューティング

# 登録を確認
claude mcp list

# 接続の問題をチェック
claude mcp get my-first-server

一般的な登録の問題:

高度な例: 天気API統合

「Hello World」を超える

MCPサーバーの基本的な構造を理解したので、現実世界の統合パターンを示すより実用的なサーバーを構築しましょう。この天気APIサーバーでは、以下を学びます。

API統合の計画

コードを書く前に、これらの統合側面を考慮します。

API選択: シンプルさと無料枠があるOpenWeatherMap APIを使用します。

データフロー: ユーザーリクエスト → パラメータ検証 → API呼び出し → 応答フォーマット → Claude応答

エラーシナリオ: ネットワーク障害、無効なAPIキー、不正な形式の応答、レート制限

セキュリティ: 環境変数に保存されたAPIキー、入力サニタイズ

実装戦略

このサーバーを段階的に構築し、各部分を完全なエラー処理で実装しましょう。

#!/usr/bin/env python3
import json
import sys
import os
import requests
from typing import Dict, Any

# 設定 - セキュリティのために環境変数を使用
WEATHER_API_KEY = os.environ.get("OPENWEATHER_API_KEY", "your-api-key-here")

def get_weather(city: str) -> str:
    """指定された都市の現在の天気データを取得"""
    try:
        url = "<http://api.openweathermap.org/data/2.5/weather>"
        params = {
            "q": city,
            "appid": WEATHER_API_KEY,
            "units": "metric"
        }
        response = requests.get(url, params=params, timeout=10)
        data = response.json()

        if response.status_code == 200:
            temp = data["main"]["temp"]
            desc = data["weather"][0]["description"]
            humidity = data["main"]["humidity"]
            return f"{city}の天気: {temp}°C、{desc.title()}、湿度: {humidity}%"
        else:
            return f"天気取得エラー: {data.get('message', '不明なエラー')}"
    except requests.RequestException as e:
        return f"ネットワークエラー: {str(e)}"
    except Exception as e:
        return f"天気データ処理エラー: {str(e)}"

def handle_tools_list(request_id: Any) -> Dict[str, Any]:
    """天気機能を備えた強化されたツールリスト"""
    tools = [
        {
            "name": "get_weather",
            "description": "世界中の任意の都市の現在の気象条件を取得",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "都市名(例: 'London', 'Tokyo', 'New York')"
                    }
                },
                "required": ["city"]
            }
        }
    ]

    return {
        "jsonrpc": "2.0",
        "id": request_id,
        "result": {
            "tools": tools
        }
    }

def handle_tool_call(request_id: Any, params: Dict[str, Any]) -> Dict[str, Any]:
    """天気機能を備えた強化されたツール実行"""
    tool_name = params.get("name")
    arguments = params.get("arguments", {})

    try:
        if tool_name == "get_weather":
            city = arguments.get("city")
            if not city:
                raise ValueError("都市名が必要です")
            result = get_weather(city)
        else:
            raise ValueError(f"不明なツール: {tool_name}")

        return {
            "jsonrpc": "2.0",
            "id": request_id,
            "result": {
                "content": [
                    {
                        "type": "text",
                        "text": result
                    }
                ]
            }
        }
    except Exception as e:
        return {
            "jsonrpc": "2.0",
            "id": request_id,
            "error": {
                "code": -32603,
                "message": str(e)
            }
        }

# 基本的な例と同じmain()関数およびその他のハンドラを含む

高度な機能の説明

環境変数によるセキュリティ: APIキーは環境変数からロードされ、ハードコードされることはありません。これにより、バージョン管理での偶発的な露出を防ぎます。

堅牢なエラー処理: get_weather()関数は複数のエラーシナリオを処理します。

強化されたツールスキーマ: 天気ツールのスキーマには詳細な説明と例が含まれており、Claude Codeがツールを効果的に使用する方法を理解するのに役立ちます。

ステップ5: プロフェッショナルな依存関係と構成管理

適切な要件ファイルの作成

requests>=2.28.0
python-dotenv>=1.0.0

バージョン固定戦略: 最小バージョン要件(>=)を使用することで、セキュリティアップデートを許可しながら互換性を確保します。本番サーバーの場合は、厳密なバージョン固定を検討してください。

安全な環境構成

構成管理のために.envファイルを作成します。

# 天気API構成
OPENWEATHER_API_KEY=your_actual_api_key_here

# サーバー構成
MCP_LOG_LEVEL=INFO
MCP_DEBUG=false

# オプション: レート制限
MCP_MAX_REQUESTS_PER_MINUTE=60

セキュリティのベストプラクティス:

依存関係のインストールと分離

# 分離のための仮想環境を作成
python3 -m venv mcp-env
source mcp-env/bin/activate  # Windowsの場合: mcp-env\\\\Scripts\\\\activate

# 依存関係をインストール
pip install -r requirements.txt

# インストールを確認
python3 -c "import requests; print('Dependencies installed successfully')"

仮想環境が重要な理由: 分離により、異なるMCPサーバーとシステムPythonインストールの間の依存関係の競合を防ぎます。

MCPサーバーのテストとデバッグ

包括的なテスト戦略

MCPサーバーのテストには、プロトコル準拠と機能の正確性の両方を扱うため、多層的なアプローチが必要です。体系的なテスト戦略は、問題が本番環境に到達するのを防ぎ、デバッグをはるかに容易にします。

MCPサーバーのためのテストピラミッド

  1. ユニットテスト: 個々の関数のテスト
  2. プロトコルテスト: JSON-RPC準拠の検証
  3. 統合テスト: Claude Codeとのインタラクションテスト
  4. エンドツーエンドテスト: 全ワークフローの検証

レイヤー1: 手動プロトコルテスト

コアMCPメソッドのテスト

統合の前に、サーバーがMCPプロトコルを正しく実装していることを確認します。

# 初期化ハンドシェイクをテスト
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | python3 server.py

期待される応答構造:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2024-11-05",
    "capabilities": {"tools": {}},
    "serverInfo": {"name": "your-server", "version": "1.0.0"}
  }
}

ツール発見のテスト

# ツールリストエンドポイントをテスト
echo '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' | python3 server.py

検証チェックリスト:

ツール実行のテスト

# 実際のツール機能をテスト
echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"hello_world","arguments":{"name":"Test"}}}' | python3 server.py

確認すべきこと:

レイヤー2: 自動テストフレームワーク

テストスクリプトの作成

自動テストのためにtest_server.pyファイルを作成します。

#!/usr/bin/env python3
import json
import subprocess
import sys

def test_mcp_method(method, params=None):
    """特定のMCPメソッドをテスト"""
    request = {
        "jsonrpc": "2.0",
        "id": 1,
        "method": method,
        "params": params or {}
    }

    try:
        result = subprocess.run(
            [sys.executable, "server.py"],
            input=json.dumps(request),
            capture_output=True,
            text=True,
            timeout=10
        )
        return json.loads(result.stdout.strip())
    except Exception as e:
        return {"error": str(e)}

# テストスイート
tests = [
    ("initialize", None),
    ("tools/list", None),
    ("tools/call", {"name": "hello_world", "arguments": {"name": "Test"}})
]

for method, params in tests:
    response = test_mcp_method(method, params)
    print(f"Testing {method}: {'✓ PASS' if 'result' in response else '✗ FAIL'}")

レイヤー3: Claude Codeとの統合テスト

サーバー登録と検証

# サーバーを登録
claude mcp add --scope user test-server python3 /full/path/to/server.py

# 登録を確認
claude mcp list | grep test-server

# サーバーのヘルスチェック
claude mcp get test-server

ライブ統合テスト

# テストモードでClaude Codeを起動
claude

# Claude Codeでツール発見をテスト
/mcp

# ツール実行をテスト
mcp__test-server__hello_world name:"Integration Test"

ツール命名パターン: Claude Codeは、命名衝突を避けるためにツールにmcp__<サーバー名>__<ツール名>というプレフィックスを付けます。

高度なデバッグ技術

デバッグロギングの有効化

サーバーに包括的なロギングを追加します。

import logging
import sys

# stderrにロギングを構成 (JSON-RPCと干渉しない)
logging.basicConfig(
    level=logging.DEBUG,
    stream=sys.stderr,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

logger = logging.getLogger(__name__)

def handle_tool_call(request_id, params):
    logger.debug(f"Received tool call: {params}")
    # ... ツールのロジック
    logger.debug(f"Tool execution completed successfully")

MCPサーバーログ分析

Claude Codeは各MCPサーバーのログを保持しています。

# 最新のログを表示 (macOS)
tail -f ~/Library/Logs/Claude/mcp-server-*.log

# 最新のログを表示 (Linux)
tail -f ~/.config/claude/logs/mcp-server-*.log

# エラーを検索
grep -i error ~/Library/Logs/Claude/mcp-server-*.log

一般的なデバッグパターン

問題: サーバーは起動するがツールが表示されない

診断: tools/list応答形式を確認

解決策: JSONスキーマ準拠を検証

問題: ツール呼び出しがサイレントに失敗する

診断: tools/callのエラー処理を確認

解決策: 包括的な例外処理を追加

問題: サーバー接続が切断される

診断: バッファリングなしI/Oと適切な例外処理を確認

解決策: sys.stdout構成とメインループのエラー処理を検証

パフォーマンスと信頼性のテスト

サーバーのロードテスト

# 複数の高速リクエストをテスト
for i in {1..10}; do
  echo '{"jsonrpc":"2.0","id":'$i',"method":"tools/list","params":{}}' | python3 server.py &
done
wait

メモリとリソースの監視

# サーバーのリソース使用状況を監視
python3 -m memory_profiler server.py

# 拡張操作中のメモリリークをチェック
python3 -m tracemalloc server.py

一般的な問題のトラブルシューティング

プロトコルレベルの問題

  1. 無効なJSON応答: json.loads()を使用して出力を検証
  2. 必須フィールドの欠落: MCP仕様準拠を確認
  3. 不正なエラーコード: 標準のJSON-RPCエラーコードを使用

統合の問題

  1. サーバーが表示されない: ファイル権限とPythonパスを検証
  2. ツールにアクセスできない: スコープ構成と登録を確認
  3. 認証失敗: 適切なMCP初期化を保証

ベストプラクティスとセキュリティ上の考慮事項

本番対応のエラー処理

堅牢な検証の実装

MCPサーバーのエラー処理は、障害がClaude Codeとの通信チェーン全体を破壊する可能性があるため、包括的である必要があります。複数のレベルで検証を実装します。

def validate_arguments(arguments: Dict[str, Any], required: List[str]):
    """必須の引数が存在することを確認"""
    missing = [field for field in required if field not in arguments]
    if missing:
        raise ValueError(f"Missing required fields: {', '.join(missing)}")

def handle_tool_call(request_id: Any, params: Dict[str, Any]) -> Dict[str, Any]:
    """適切な検証を伴うツール実行"""
    try:
        tool_name = params.get("name")
        arguments = params.get("arguments", {})

        # 処理前に検証
        if tool_name == "get_weather":
            validate_arguments(arguments, ["city"])

        # ここでツールのロジックを処理

    except ValueError as ve:
        return create_error_response(request_id, -32602, str(ve))
    except Exception as e:
        return create_error_response(request_id, -32603, f"Internal error: {str(e)}")

エラー応答基準

JSON-RPC 2.0のエラーコード規則に従います。

包括的なセキュリティフレームワーク

1. シークレット管理

機密情報をハードコードしないでください。構成には階層的なアプローチを使用します。

import os
from pathlib import Path

def load_config():
    """フォールバック階層で構成をロード"""
    # 1. 環境変数 (最高優先度)
    api_key = os.environ.get("API_KEY")

    # 2. ローカルの.envファイル
    if not api_key:
        env_path = Path(".env")
        if env_path.exists():
            # .envファイルからロード
            pass

    # 3. システムキーリング (本番)
    if not api_key:
        try:
            import keyring
            api_key = keyring.get_password("mcp-server", "api_key")
        except ImportError:
            pass

    if not api_key:
        raise ValueError("API key not found in any configuration source")

    return {"api_key": api_key}

2. 入力サニタイズと検証

インジェクション攻撃を防ぐために厳密な入力検証を実装します。

import re
from typing import Any, Dict

def sanitize_string_input(value: str, max_length: int = 100) -> str:
    """文字列入力をサニタイズ"""
    if not isinstance(value, str):
        raise ValueError("Expected string input")

    # 潜在的に危険な文字を削除
    sanitized = re.sub(r'[<>"\\\\']', '', value)

    # DoSを防ぐために長さを制限
    if len(sanitized) > max_length:
        raise ValueError(f"Input too long (max {max_length} characters)")

    return sanitized.strip()

def validate_city_name(city: str) -> str:
    """都市名入力を検証"""
    sanitized = sanitize_string_input(city, 50)

    # 文字、スペース、一般的な句読点のみを許可
    if not re.match(r'^[a-zA-Z\\\\s\\\\-\\\\.]+$', sanitized):
        raise ValueError("Invalid city name format")

    return sanitized

3. レート制限とリソース保護

悪用を防ぐためにレート制限を実装します。

import time
from collections import defaultdict
from threading import Lock

class RateLimiter:
    def __init__(self, max_requests: int = 60, window_seconds: int = 60):
        self.max_requests = max_requests
        self.window_seconds = window_seconds
        self.requests = defaultdict(list)
        self.lock = Lock()

    def allow_request(self, client_id: str = "default") -> bool:
        """レート制限の下でリクエストが許可されるかチェック"""
        now = time.time()

        with self.lock:
            # 古いリクエストをクリーンアップ
            self.requests[client_id] = [
                req_time for req_time in self.requests[client_id]
                if now - req_time < self.window_seconds
            ]

            # 制限をチェック
            if len(self.requests[client_id]) >= self.max_requests:
                return False

            # このリクエストを記録
            self.requests[client_id].append(now)
            return True

# グローバルレート制限インスタンス
rate_limiter = RateLimiter()

高度なロギングと監視

構造化ロギングの実装

デバッグと監視を改善するために構造化ロギングを使用します。

import logging
import json
import sys
from datetime import datetime

class MCPFormatter(logging.Formatter):
    """MCPサーバーログ用のカスタムフォーマッター"""

    def format(self, record):
        log_entry = {
            "timestamp": datetime.utcnow().isoformat(),
            "level": record.levelname,
            "message": record.getMessage(),
            "module": record.module,
            "function": record.funcName,
        }

        # 利用可能な場合は追加のコンテキストを追加
        if hasattr(record, 'tool_name'):
            log_entry["tool_name"] = record.tool_name
        if hasattr(record, 'request_id'):
            log_entry["request_id"] = record.request_id

        return json.dumps(log_entry)

# 構造化ロギングを構成
logger = logging.getLogger(__name__)
handler = logging.StreamHandler(sys.stderr)
handler.setFormatter(MCPFormatter())
logger.addHandler(handler)
logger.setLevel(logging.INFO)

パフォーマンス監視

サーバーのパフォーマンスメトリックを追跡します。

import time
import statistics
from collections import deque

class PerformanceMonitor:
    def __init__(self, max_samples: int = 1000):
        self.response_times = deque(maxlen=max_samples)
        self.error_count = 0
        self.request_count = 0

    def record_request(self, duration: float, success: bool):
        """リクエストメトリックを記録"""
        self.request_count += 1
        self.response_times.append(duration)

        if not success:
            self.error_count += 1

    def get_stats(self) -> Dict[str, Any]:
        """現在のパフォーマンス統計を取得"""
        if not self.response_times:
            return {"no_data": True}

        return {
            "total_requests": self.request_count,
            "error_rate": self.error_count / self.request_count,
            "avg_response_time": statistics.mean(self.response_times),
            "p95_response_time": statistics.quantiles(self.response_times, n=20)[18],
            "p99_response_time": statistics.quantiles(self.response_times, n=100)[98]
        }

# グローバルパフォーマンスモニター
perf_monitor = PerformanceMonitor()

デプロイメントとメンテナンス戦略

バージョン管理

MCPサーバーの適切なバージョン管理を実装します。

__version__ = "1.2.3"
__mcp_version__ = "2024-11-05"

def get_server_info():
    """MCP初期化のためのサーバー情報を返す"""
    return {
        "name": "my-production-server",
        "version": __version__,
        "mcp_protocol_version": __mcp_version__,
        "capabilities": ["tools", "resources"],  # サポートする機能を宣言
    }

ヘルスチェックの実装

監視のためのヘルスチェック機能を追加します。

def handle_health_check(request_id: Any) -> Dict[str, Any]:
    """監視のためのヘルスチェックエンドポイント"""
    try:
        # コア機能のテスト
        test_db_connection()  # ヘルスチェックの例
        test_external_apis()  # ヘルスチェックの例

        return {
            "jsonrpc": "2.0",
            "id": request_id,
            "result": {
                "status": "healthy",
                "timestamp": datetime.utcnow().isoformat(),
                "version": __version__,
                "uptime_seconds": time.time() - start_time,
                "performance": perf_monitor.get_stats()
            }
        }
    except Exception as e:
        return {
            "jsonrpc": "2.0",
            "id": request_id,
            "result": {
                "status": "unhealthy",
                "error": str(e),
                "timestamp": datetime.utcnow().isoformat()
            }
        }

グレースフルシャットダウン処理

サーバーシャットダウン時の適切なクリーンアップを実装します。

import signal
import sys

class MCPServer:
    def __init__(self):
        self.running = True
        self.active_requests = set()

        # シグナルハンドラを登録
        signal.signal(signal.SIGINT, self.shutdown_handler)
        signal.signal(signal.SIGTERM, self.shutdown_handler)

    def shutdown_handler(self, signum, frame):
        """グレースフルシャットダウンを処理"""
        logger.info(f"Received signal {signum}, initiating graceful shutdown")
        self.running = False

        # アクティブなリクエストが完了するまで待機
        timeout = 30  # 秒
        start_time = time.time()

        while self.active_requests and (time.time() - start_time) < timeout:
            time.sleep(0.1)

        logger.info("Shutdown complete")
        sys.exit(0)

現実世界のユースケースと高度なアプリケーション

エンタープライズ統合パターン

MCPサーバーは、Claude Codeが既存のビジネスシステムと統合する必要があるエンタープライズ環境で優れています。以下は実証済みの統合パターンです。

データベース統合サーバー

開発ワークフロー自動化

システム監視と運用

高度なアーキテクチャパターン

マルチサーバーオーケストレーション

複雑なワークフローの場合、互いに連携するMCPサーバーを設計します。

# サーバー連携パターン
def coordinate_workflow(workflow_id: str, steps: List[Dict]) -> Dict:
    """サーバー間で多段階ワークフローを連携"""
    results = {}

    for step in steps:
        server_name = step["server"]
        tool_name = step["tool"]
        params = step["params"]

        # Claude Codeを通じて他のMCPサーバーを呼び出し
        result = call_mcp_tool(server_name, tool_name, params)
        results[step["id"]] = result

        # ステップ間の依存関係を処理
        if step.get("depends_on"):
            inject_dependencies(params, results, step["depends_on"])

    return {"workflow_id": workflow_id, "results": results}

キャッシングとパフォーマンス最適化

頻繁に要求されるデータのためにインテリジェントなキャッシングを実装します。

import hashlib
import pickle
from datetime import datetime, timedelta

class IntelligentCache:
    def __init__(self, default_ttl: int = 3600):
        self.cache = {}
        self.default_ttl = default_ttl

    def get_cache_key(self, tool_name: str, params: Dict) -> str:
        """一貫性のあるキャッシュキーを生成"""
        key_data = f"{tool_name}:{json.dumps(params, sort_keys=True)}"
        return hashlib.md5(key_data.encode()).hexdigest()

    def get(self, tool_name: str, params: Dict) -> Optional[Any]:
        """有効な場合はキャッシュされた結果を取得"""
        key = self.get_cache_key(tool_name, params)

        if key in self.cache:
            data, expiry = self.cache[key]
            if datetime.now() < expiry:
                return data
            else:
                del self.cache[key]

        return None

    def set(self, tool_name: str, params: Dict, result: Any, ttl: Optional[int] = None):
        """TTL付きで結果をキャッシュ"""
        key = self.get_cache_key(tool_name, params)
        expiry = datetime.now() + timedelta(seconds=ttl or self.default_ttl)
        self.cache[key] = (result, expiry)

本番デプロイメント戦略

コンテナ化されたデプロイメント

一貫性のあるデプロイメントのために、MCPサーバーをDockerコンテナとしてパッケージ化します。

FROM python:3.11-slim

WORKDIR /app

# システム依存関係をインストール
RUN apt-get update && apt-get install -y \\\\
    curl \\\\
    && rm -rf /var/lib/apt/lists/*

# Python依存関係をコピーしてインストール
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# アプリケーションコードをコピー
COPY server.py .
COPY config/ ./config/

# 非rootユーザーを作成
RUN useradd -m -s /bin/bash mcpuser
USER mcpuser

# ヘルスチェック
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \\\\
    CMD python3 -c "import requests; requests.get('<http://localhost:8080/health>')"

CMD ["python3", "server.py"]

Kubernetesデプロイメント

スケーラビリティと信頼性のために、MCPサーバーをKubernetesにデプロイします。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mcp-weather-server
spec:
  replicas: 3
  selector:
    matchLabels:
      app: mcp-weather-server
  template:
    metadata:
      labels:
        app: mcp-weather-server
    spec:
      containers:
      - name: mcp-server
        image: your-registry/mcp-weather-server:latest
        ports:
        - containerPort: 8080
        env:
        - name: OPENWEATHER_API_KEY
          valueFrom:
            secretKeyRef:
              name: mcp-secrets
              key: openweather-api-key
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "256Mi"
            cpu: "200m"
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10

スケーリングとパフォーマンスの考慮事項

水平スケーリングパターン

MCPサーバーを水平スケーリングをサポートするように設計します。

  1. ステートレス設計: サーバーをステートレスに保ち、容易なレプリケーションを可能にする
  2. ロードバランシング: 複数のサーバーインスタンスにリクエストを分散
  3. データベースプーリング: データベースバックエンドのサーバーに接続プーリングを使用
  4. キャッシング戦略: 共有キャッシングのためにRedisまたはMemcachedを実装

パフォーマンス最適化技術

import asyncio
import aiohttp
from concurrent.futures import ThreadPoolExecutor

class HighPerformanceMCPServer:
    def __init__(self):
        self.executor = ThreadPoolExecutor(max_workers=10)
        self.session = None

    async def async_tool_call(self, tool_name: str, params: Dict) -> Dict:
        """ツール呼び出しを非同期で処理"""
        if not self.session:
            self.session = aiohttp.ClientSession()

        # I/Oバウンドタスクに非同期操作を使用
        if tool_name == "web_search":
            return await self.async_web_search(params)
        elif tool_name == "database_query":
            return await self.async_database_query(params)
        else:
            # CPUバウンドタスクにスレッドプールを使用
            loop = asyncio.get_event_loop()
            return await loop.run_in_executor(
                self.executor,
                self.sync_tool_call,
                tool_name,
                params
            )

結論と次のステップ

MCP開発をマスターする

Claude CodeのためのMCPサーバー構築は、AIアプリケーション開発におけるパラダイムシフトを表しています。ハードコードされた接続を必要とする従来のAPI統合とは異なり、MCPはAIアシスタントを真に拡張可能にする動的で発見可能なインターフェースを提供します。

この包括的なガイドを通じて、あなたは以下を学びました。

基礎スキル:

本番対応:

高度な機能:

戦略的な開発アプローチ

フェーズ1: 基盤構築 (1-2週目)

プロトコルを理解するために、シンプルで単一目的のサーバーから始めます。

フェーズ2: 統合拡張 (3-4週目)

既存のシステムと統合するより複雑なサーバーを構築します。

フェーズ3: エンタープライズデプロイメント (2ヶ月目以降)

完全な運用サポート付きで本番対応サーバーをデプロイします。

長期的な成功戦略

コミュニティへの参加

継続的な改善

イノベーションの機会

MCP開発の未来

Model Context Protocolは、AI統合アプリケーションの新しいエコシステムの基盤を表しています。MCPサーバーを構築する際、あなたはClaude Codeのためのツールを作成しているだけでなく、MCP互換のAIアシスタントの拡大するエコシステム全体で機能する再利用可能なコンポーネントを構築しています。

MCP開発への投資は、以下を通じて利益をもたらします。

成功のための重要なリマインダー

MCP開発の旅に乗り出すにあたり、これらの不可欠な原則を覚えておいてください。

  1. 構成スコープの習得: プロジェクトレベルの制限が特に必要な場合を除き、開発サーバーには常に-scope userを使用
  2. セキュリティ第一: シークレットをハードコードせず、常に入力を検証し、レート制限を実装
  3. エラー処理の完全性: すべての障害モードを予測し、適切に処理
  4. テストの徹底: プロトコル準拠、機能、統合をテスト
  5. ドキュメントの品質: チーム連携とメンテナンスのためにサーバーをドキュメント化

ヘルプとリソースの入手

課題に遭遇した場合:

今日から構築を開始し、迅速にイテレーションを行い、Model Context Protocolを通じてAI機能を拡張する開発者の成長するコミュニティに参加してください。あなたのカスタムMCPサーバーは、私たちが想像し始めたばかりのAI支援ワークフローのための新しい可能性を解き放ちます。

覚えておいてください: すべての複雑な統合は、シンプルな「Hello World」サーバーから始まりました。基本から始め、基礎をマスターし、作業方法を変革するAI統合ツールを徐々に構築してください。

💡
美しいAPIドキュメントを生成する優れたAPIテストツールをお探しですか?

最高の生産性で開発チームが連携するための統合されたオールインワンプラットフォームをお探しですか?

Apidogは、あなたのすべての要求に応え、Postmanをはるかに手頃な価格で置き換えます
button

ApidogでAPIデザイン中心のアプローチを取る

APIの開発と利用をよりシンプルなことにする方法を発見できる