コンテンツにスキップ

MCP(Model Context Protocol)サーバー構築ガイド

📁 docs/it-learning/artifact/20260309_MCP_サーバー構築ガイド.md

公式ドキュメント(modelcontextprotocol.io)ベースの網羅的な調査結果 調査日: 2026-03-09 Protocol Revision: 2025-06-18


目次

  1. MCPとは何か
  2. アーキテクチャ
  3. 基本構成要素(Tools, Resources, Prompts)
  4. MCPサーバーの作り方 - Python
  5. MCPサーバーの作り方 - TypeScript
  6. テスト・デバッグ方法
  7. クライアントへの接続方法
  8. デプロイ・配布方法
  9. よくあるパターン・ベストプラクティス
  10. 公式ドキュメント・リファレンス

1. MCPとは何か

概要

MCP(Model Context Protocol)は、AIアプリケーションを外部システムに接続するためのオープンソース標準プロトコル

USB-Cが電子機器の標準接続ポートであるように、MCPはAIアプリケーションと外部システムの標準接続方法を提供する。

MCPで何ができるか

  • AIアシスタントがGoogleカレンダーやNotionにアクセスし、パーソナライズされた支援を提供
  • Claude Codeが Figmaデザインから Webアプリ全体を生成
  • 企業チャットボットが組織内の複数データベースに接続し、チャットでデータ分析
  • AIモデルがBlenderで3Dデザインを作成し、3Dプリンターで出力

サポートされているクライアント

  • Claude Desktop / Claude.ai
  • ChatGPT
  • Visual Studio Code (Copilot)
  • Cursor
  • その他多数のAIツール

2. アーキテクチャ

参加者(Participants)

MCPはクライアント-サーバーアーキテクチャに従う。

┌─────────────────────────────────────────┐
│          MCP Host(AIアプリケーション)       │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│  │MCP Client│ │MCP Client│ │MCP Client│ │
│  │    1     │ │    2     │ │    3     │ │
│  └────┬─────┘ └────┬─────┘ └────┬─────┘ │
└───────┼────────────┼────────────┼────────┘
        │            │            │
   ┌────▼────┐  ┌────▼────┐ ┌────▼────┐
   │MCP Server│ │MCP Server│ │MCP Server│
   │  A(Local)│ │  B(Local)│ │ C(Remote)│
   └─────────┘  └─────────┘ └─────────┘
  • MCP Host: AIアプリケーション(Claude Desktop, VS Codeなど)。複数のMCPクライアントを管理
  • MCP Client: MCPサーバーとの接続を維持するコンポーネント。ホスト内に1サーバー1クライアント
  • MCP Server: コンテキスト(ツール、リソース、プロンプト)を提供するプログラム

2つのレイヤー

データ層(Data Layer)

  • JSON-RPC 2.0 ベースのプロトコル
  • ライフサイクル管理(初期化、能力ネゴシエーション、切断)
  • サーバー機能: Tools, Resources, Prompts
  • クライアント機能: Sampling, Elicitation, Logging
  • ユーティリティ: 通知、進捗追跡

トランスポート層(Transport Layer)

通信方式は2種類:

方式 用途 特徴
Stdio ローカルプロセス間通信 標準入出力を使用。ネットワークオーバーヘッドなし。ローカルサーバー向き
Streamable HTTP リモート通信 HTTP POSTでクライアント→サーバー、SSEでストリーミング。OAuth認証対応

ライフサイクル

  1. 初期化: クライアントが initialize リクエストを送信し、能力ネゴシエーション
  2. 能力交換: サーバーが対応するTools/Resources/Promptsを宣言
  3. 通常運用: ツール呼び出し、リソース読み取り等
  4. 通知: サーバーからリアルタイム更新
  5. 切断: 接続終了

3. 基本構成要素

MCPサーバーが提供できる3つのプリミティブ:

3.1 Tools(ツール)

モデル制御型 -- LLMが自動的に発見・呼び出しできる実行可能な関数。

{
  "name": "get_weather",
  "title": "Weather Information Provider",
  "description": "Get current weather information for a location",
  "inputSchema": {
    "type": "object",
    "properties": {
      "location": {
        "type": "string",
        "description": "City name or zip code"
      }
    },
    "required": ["location"]
  }
}

特徴: - name: ツールの一意な識別子 - title: 表示用の人間に読みやすい名前(オプション) - description: 機能の説明 - inputSchema: JSON Schemaで入力パラメータを定義 - outputSchema: 出力の構造を定義(オプション) - annotations: ツールの動作に関するメタデータ(オプション)

レスポンスの種類: - テキスト (type: "text") - 画像 (type: "image", base64エンコード) - 音声 (type: "audio", base64エンコード) - リソースリンク (type: "resource_link") - 埋め込みリソース (type: "resource") - 構造化コンテンツ (structuredContent)

3.2 Resources(リソース)

アプリケーション制御型 -- ファイル、データベーススキーマ等のコンテキストデータ。URIで一意に識別。

{
  "uri": "file:///project/src/main.rs",
  "name": "main.rs",
  "title": "Rust Software Application Main File",
  "description": "Primary application entry point",
  "mimeType": "text/x-rust"
}

機能: - リソースの一覧取得 (resources/list) - リソースの読み取り (resources/read) - リソーステンプレート(URIテンプレートでパラメータ化) - サブスクリプション(リソース変更の監視)

URIスキーム: - https:// -- Web上のリソース - file:// -- ファイルシステムのリソース - git:// -- Gitバージョン管理 - カスタムURIスキーム

3.3 Prompts(プロンプト)

ユーザー制御型 -- 再利用可能なプロンプトテンプレート。スラッシュコマンドとして公開されることが多い。

{
  "name": "code_review",
  "title": "Request Code Review",
  "description": "Asks the LLM to analyze code quality and suggest improvements",
  "arguments": [
    {
      "name": "code",
      "description": "The code to review",
      "required": true
    }
  ]
}

特徴: - 引数によるカスタマイズ - role(user/assistant)を含むメッセージ配列を返す - テキスト、画像、音声、埋め込みリソースをサポート


4. MCPサーバーの作り方 - Python

4.1 環境セットアップ

# uvをインストール(パッケージマネージャー)
# macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

# プロジェクト作成
uv init my-mcp-server
cd my-mcp-server

# 仮想環境作成・有効化
uv venv
# macOS/Linux
source .venv/bin/activate
# Windows
.venv\Scripts\activate

# 依存関係インストール
uv add "mcp[cli]" httpx

要件: Python 3.10以上、MCP SDK 1.2.0以上

4.2 最小限のサーバー(Hello World)

# hello_server.py
from mcp.server.fastmcp import FastMCP

# FastMCPサーバーを初期化
mcp = FastMCP("hello")

@mcp.tool()
async def hello(name: str) -> str:
    """挨拶を返すツール。

    Args:
        name: 挨拶する相手の名前
    """
    return f"こんにちは、{name}さん!"

@mcp.resource("greeting://{name}")
async def get_greeting(name: str) -> str:
    """名前に基づく挨拶リソース。"""
    return f"{name}さんへの挨拶メッセージです。"

@mcp.prompt()
async def review_code(code: str) -> str:
    """コードレビュー用プロンプト。"""
    return f"以下のコードをレビューしてください:\n\n{code}"

def main():
    mcp.run(transport="stdio")

if __name__ == "__main__":
    main()

4.3 実用的なサーバー例(天気API連携)

公式クイックスタートの天気サーバー(NWS API連携):

# weather.py
from typing import Any
import httpx
from mcp.server.fastmcp import FastMCP

# FastMCPサーバーを初期化
mcp = FastMCP("weather")

# 定数
NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-app/1.0"


async def make_nws_request(url: str) -> dict[str, Any] | None:
    """NWS APIへのリクエスト(エラーハンドリング付き)。"""
    headers = {"User-Agent": USER_AGENT, "Accept": "application/geo+json"}
    async with httpx.AsyncClient() as client:
        try:
            response = await client.get(url, headers=headers, timeout=30.0)
            response.raise_for_status()
            return response.json()
        except Exception:
            return None


def format_alert(feature: dict) -> str:
    """アラート情報をフォーマット。"""
    props = feature["properties"]
    return f"""
Event: {props.get("event", "Unknown")}
Area: {props.get("areaDesc", "Unknown")}
Severity: {props.get("severity", "Unknown")}
Description: {props.get("description", "No description available")}
Instructions: {props.get("instruction", "No specific instructions provided")}
"""


@mcp.tool()
async def get_alerts(state: str) -> str:
    """Get weather alerts for a US state.

    Args:
        state: Two-letter US state code (e.g. CA, NY)
    """
    url = f"{NWS_API_BASE}/alerts/active/area/{state}"
    data = await make_nws_request(url)

    if not data or "features" not in data:
        return "Unable to fetch alerts or no alerts found."

    if not data["features"]:
        return "No active alerts for this state."

    alerts = [format_alert(feature) for feature in data["features"]]
    return "\n---\n".join(alerts)


@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:
    """Get weather forecast for a location.

    Args:
        latitude: Latitude of the location
        longitude: Longitude of the location
    """
    # まずforecastグリッドエンドポイントを取得
    points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"
    points_data = await make_nws_request(points_url)

    if not points_data:
        return "Unable to fetch forecast data for this location."

    # pointsレスポンスからforecast URLを取得
    forecast_url = points_data["properties"]["forecast"]
    forecast_data = await make_nws_request(forecast_url)

    if not forecast_data:
        return "Unable to fetch detailed forecast."

    # 期間をフォーマット
    periods = forecast_data["properties"]["periods"]
    forecasts = []
    for period in periods[:5]:  # 次の5期間のみ表示
        forecast = f"""
{period["name"]}:
Temperature: {period["temperature"]}°{period["temperatureUnit"]}
Wind: {period["windSpeed"]} {period["windDirection"]}
Forecast: {period["detailedForecast"]}
"""
        forecasts.append(forecast)

    return "\n---\n".join(forecasts)


def main():
    mcp.run(transport="stdio")


if __name__ == "__main__":
    main()

4.4 FastMCPの主要デコレータ

# ツール定義 -- LLMが呼び出せる関数
@mcp.tool()
async def my_tool(param: str) -> str:
    """ツールの説明(docstringが自動的にdescriptionになる)。

    Args:
        param: パラメータの説明(型ヒントからスキーマが自動生成)
    """
    return "結果"

# リソース定義 -- コンテキストデータの提供
@mcp.resource("myapp://config")
async def get_config() -> str:
    """設定情報を返すリソース。"""
    return "config data"

# リソーステンプレート -- パラメータ化されたリソース
@mcp.resource("myapp://users/{user_id}")
async def get_user(user_id: str) -> str:
    """ユーザー情報リソース。"""
    return f"User: {user_id}"

# プロンプト定義 -- 再利用可能なテンプレート
@mcp.prompt()
async def analyze(topic: str) -> str:
    """分析用プロンプト。"""
    return f"{topic}について詳しく分析してください。"

4.5 ログに関する重要な注意点

STDIOベースのサーバーでは、絶対にprint()(stdout)を使わないこと。 JSON-RPCメッセージが破損する。

import sys
import logging

# NG: stdoutに書き込む
print("Processing request")

# OK: stderrに書き込む
print("Processing request", file=sys.stderr)

# OK: loggingモジュールを使用
logging.info("Processing request")

5. MCPサーバーの作り方 - TypeScript

5.1 環境セットアップ

# Node.js 16以上が必要
node --version
npm --version

# プロジェクト作成
mkdir my-mcp-server
cd my-mcp-server
npm init -y

# 依存関係インストール
npm install @modelcontextprotocol/sdk zod@3
npm install -D @types/node typescript

# ソースディレクトリ作成
mkdir src

package.json に追加:

{
  "type": "module",
  "bin": {
    "my-mcp-server": "./build/index.js"
  },
  "scripts": {
    "build": "tsc && chmod 755 build/index.js"
  },
  "files": ["build"]
}

tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./build",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

5.2 最小限のサーバー(Hello World)

// src/index.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

const server = new McpServer({
  name: "hello",
  version: "1.0.0",
});

// ツール登録
server.registerTool(
  "hello",
  {
    description: "挨拶を返すツール",
    inputSchema: {
      name: z.string().describe("挨拶する相手の名前"),
    },
  },
  async ({ name }) => {
    return {
      content: [
        {
          type: "text",
          text: `こんにちは、${name}さん!`,
        },
      ],
    };
  },
);

async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("Hello MCP Server running on stdio");
}

main().catch((error) => {
  console.error("Fatal error in main():", error);
  process.exit(1);
});

5.3 実用的なサーバー例(天気API連携)

// src/index.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

const NWS_API_BASE = "https://api.weather.gov";
const USER_AGENT = "weather-app/1.0";

const server = new McpServer({
  name: "weather",
  version: "1.0.0",
});

// ヘルパー関数: NWS APIリクエスト
async function makeNWSRequest<T>(url: string): Promise<T | null> {
  const headers = {
    "User-Agent": USER_AGENT,
    Accept: "application/geo+json",
  };

  try {
    const response = await fetch(url, { headers });
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return (await response.json()) as T;
  } catch (error) {
    console.error("Error making NWS request:", error);
    return null;
  }
}

interface AlertFeature {
  properties: {
    event?: string;
    areaDesc?: string;
    severity?: string;
    status?: string;
    headline?: string;
  };
}

interface AlertsResponse {
  features: AlertFeature[];
}

interface PointsResponse {
  properties: {
    forecast?: string;
  };
}

interface ForecastPeriod {
  name?: string;
  temperature?: number;
  temperatureUnit?: string;
  windSpeed?: string;
  windDirection?: string;
  shortForecast?: string;
}

interface ForecastResponse {
  properties: {
    periods: ForecastPeriod[];
  };
}

function formatAlert(feature: AlertFeature): string {
  const props = feature.properties;
  return [
    `Event: ${props.event || "Unknown"}`,
    `Area: ${props.areaDesc || "Unknown"}`,
    `Severity: ${props.severity || "Unknown"}`,
    `Status: ${props.status || "Unknown"}`,
    `Headline: ${props.headline || "No headline"}`,
    "---",
  ].join("\n");
}

// ツール登録: 天気アラート取得
server.registerTool(
  "get_alerts",
  {
    description: "Get weather alerts for a state",
    inputSchema: {
      state: z
        .string()
        .length(2)
        .describe("Two-letter state code (e.g. CA, NY)"),
    },
  },
  async ({ state }) => {
    const stateCode = state.toUpperCase();
    const alertsUrl = `${NWS_API_BASE}/alerts?area=${stateCode}`;
    const alertsData = await makeNWSRequest<AlertsResponse>(alertsUrl);

    if (!alertsData) {
      return {
        content: [{ type: "text" as const, text: "Failed to retrieve alerts data" }],
      };
    }

    const features = alertsData.features || [];
    if (features.length === 0) {
      return {
        content: [{ type: "text" as const, text: `No active alerts for ${stateCode}` }],
      };
    }

    const formattedAlerts = features.map(formatAlert);
    return {
      content: [
        {
          type: "text" as const,
          text: `Active alerts for ${stateCode}:\n\n${formattedAlerts.join("\n")}`,
        },
      ],
    };
  },
);

// ツール登録: 天気予報取得
server.registerTool(
  "get_forecast",
  {
    description: "Get weather forecast for a location",
    inputSchema: {
      latitude: z.number().min(-90).max(90).describe("Latitude of the location"),
      longitude: z.number().min(-180).max(180).describe("Longitude of the location"),
    },
  },
  async ({ latitude, longitude }) => {
    const pointsUrl = `${NWS_API_BASE}/points/${latitude.toFixed(4)},${longitude.toFixed(4)}`;
    const pointsData = await makeNWSRequest<PointsResponse>(pointsUrl);

    if (!pointsData) {
      return {
        content: [
          {
            type: "text" as const,
            text: `Failed to retrieve grid point data for coordinates: ${latitude}, ${longitude}.`,
          },
        ],
      };
    }

    const forecastUrl = pointsData.properties?.forecast;
    if (!forecastUrl) {
      return {
        content: [{ type: "text" as const, text: "Failed to get forecast URL" }],
      };
    }

    const forecastData = await makeNWSRequest<ForecastResponse>(forecastUrl);
    if (!forecastData) {
      return {
        content: [{ type: "text" as const, text: "Failed to retrieve forecast data" }],
      };
    }

    const periods = forecastData.properties?.periods || [];
    const formattedForecast = periods.map((period: ForecastPeriod) =>
      [
        `${period.name || "Unknown"}:`,
        `Temperature: ${period.temperature || "Unknown"}°${period.temperatureUnit || "F"}`,
        `Wind: ${period.windSpeed || "Unknown"} ${period.windDirection || ""}`,
        `${period.shortForecast || "No forecast available"}`,
        "---",
      ].join("\n"),
    );

    return {
      content: [
        {
          type: "text" as const,
          text: `Forecast for ${latitude}, ${longitude}:\n\n${formattedForecast.join("\n")}`,
        },
      ],
    };
  },
);

// サーバー起動
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("Weather MCP Server running on stdio");
}

main().catch((error) => {
  console.error("Fatal error in main():", error);
  process.exit(1);
});

5.4 ビルドと実行

# ビルド
npm run build

# 実行
node build/index.js

5.5 ログに関する重要な注意点

STDIOベースのサーバーでは、絶対にconsole.log()を使わないこと。 JSON-RPCメッセージが破損する。

// NG: stdoutに書き込む
console.log("Server started");

// OK: stderrに書き込む
console.error("Server started");

6. テスト・デバッグ方法

6.1 MCP Inspector

MCPサーバーのインタラクティブなテスト・デバッグツール。インストール不要で npx で直接実行可能。

# 基本的な使い方
npx @modelcontextprotocol/inspector <command>

# npmパッケージのサーバーを検査
npx -y @modelcontextprotocol/inspector npx @modelcontextprotocol/server-filesystem /Users/username/Desktop

# PyPIパッケージのサーバーを検査
npx @modelcontextprotocol/inspector uvx mcp-server-git --repository ~/code/mcp/servers.git

# ローカル開発中のTypeScriptサーバーを検査
npx @modelcontextprotocol/inspector node path/to/server/index.js args...

# ローカル開発中のPythonサーバーを検査
npx @modelcontextprotocol/inspector uv --directory path/to/server run package-name args...

Inspector の機能: - Resources タブ: リソース一覧、メタデータ、内容の確認 - Prompts タブ: プロンプトテンプレートの表示・テスト - Tools タブ: ツール一覧、スキーマ確認、カスタム入力でのテスト実行 - Notifications ペイン: サーバーログ、通知の確認

6.2 Claude Desktop のデバッグ

# macOSでログをリアルタイム監視
tail -n 20 -F ~/Library/Logs/Claude/mcp*.log

Chrome DevTools を有効化:

# macOS
echo '{"allowDevTools": true}' > ~/Library/Application\ Support/Claude/developer_settings.json
# DevToolsを開く: Command-Option-Shift-i

6.3 サーバーサイドログ

# Python: MCPのログ通知を使用
server.request_context.session.send_log_message(
    level="info",
    data="Server started successfully",
)
// TypeScript: MCPのログ通知を使用
server.sendLoggingMessage({
  level: "info",
  data: "Server started successfully",
});

6.4 デバッグワークフロー

  1. 初期開発: Inspectorで基本的な接続確認 → コア機能実装 → ログポイント追加
  2. 統合テスト: Claude Desktopでテスト → ログ監視 → エラーハンドリング確認
  3. エッジケース: 無効な入力、欠落した引数、並行操作、エラーレスポンスの確認

7. クライアントへの接続方法

7.1 Claude Desktop

設定ファイルの場所: - macOS: ~/Library/Application Support/Claude/claude_desktop_config.json - Windows: %APPDATA%\Claude\claude_desktop_config.json

Python サーバーの設定

{
  "mcpServers": {
    "my-server": {
      "command": "uv",
      "args": [
        "--directory",
        "C:\\absolute\\path\\to\\my-server",
        "run",
        "server.py"
      ]
    }
  }
}

TypeScript サーバーの設定

{
  "mcpServers": {
    "my-server": {
      "command": "node",
      "args": ["C:\\absolute\\path\\to\\my-server\\build\\index.js"]
    }
  }
}

npm パッケージとして公開されたサーバーの設定

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "C:\\Users\\username\\data"
      ]
    }
  }
}

環境変数の設定

{
  "mcpServers": {
    "my-server": {
      "command": "node",
      "args": ["path/to/server.js"],
      "env": {
        "API_KEY": "your-api-key-here"
      }
    }
  }
}

7.2 Claude Code

Claude Code の設定ファイル(.claude/settings.local.json または ~/.claude/settings.json):

{
  "mcpServers": {
    "my-server": {
      "command": "uv",
      "args": [
        "--directory",
        "/absolute/path/to/my-server",
        "run",
        "server.py"
      ]
    }
  }
}

または claude mcp add コマンドで追加:

# stdioトランスポートでサーバーを追加
claude mcp add my-server uv --directory /path/to/server run server.py

7.3 VS Code

.vscode/settings.json に追加:

{
  "mcp": {
    "servers": {
      "my-server": {
        "command": "node",
        "args": ["path/to/server/build/index.js"]
      }
    }
  }
}

7.4 重要な注意点

  • 必ず絶対パスを使用すること。 Claude Desktopは起動場所が不定(macOSでは / になることがある)
  • Windows ではバックスラッシュをエスケープ (\\) するか、スラッシュ (/) を使用
  • command にはフルパスを指定するのが確実(which uvwhere uv で取得)
  • 設定変更後は Claude Desktop を再起動

8. デプロイ・配布方法

8.1 npm パッケージとして配布(TypeScript)

// package.json
{
  "name": "@your-scope/mcp-server-myapp",
  "version": "1.0.0",
  "type": "module",
  "bin": {
    "mcp-server-myapp": "./build/index.js"
  },
  "files": ["build"],
  "scripts": {
    "build": "tsc && chmod 755 build/index.js"
  }
}
# ビルド & 公開
npm run build
npm publish

利用者は以下で使用:

npx -y @your-scope/mcp-server-myapp

8.2 pip/PyPI パッケージとして配布(Python)

# pyproject.toml
[project]
name = "mcp-server-myapp"
version = "1.0.0"
dependencies = ["mcp[cli]>=1.2.0", "httpx"]

[project.scripts]
mcp-server-myapp = "mcp_server_myapp:main"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
# ビルド & 公開
uv build
uv publish

利用者は以下で使用:

uvx mcp-server-myapp

8.3 Docker コンテナとして配布

FROM python:3.12-slim

WORKDIR /app
COPY . .
RUN pip install -e .

ENTRYPOINT ["mcp-server-myapp"]

Claude Desktop設定:

{
  "mcpServers": {
    "myapp": {
      "command": "docker",
      "args": ["run", "-i", "--rm", "mcp-server-myapp"]
    }
  }
}

8.4 リモートサーバー(Streamable HTTP)

Streamable HTTPトランスポートを使用すると、サーバーをリモートでホストできる。OAuth認証をサポート。

# HTTPサーバーとして実行する場合
mcp = FastMCP("my-server")
mcp.run(transport="streamable-http", host="0.0.0.0", port=8000)

9. よくあるパターン・ベストプラクティス

9.1 ツール設計

  • 明確な名前と説明: LLMがツールを理解し適切に使えるよう、namedescription を丁寧に書く
  • 型ヒントの活用: Python の型ヒント、TypeScript の Zod スキーマを活用してinputSchemaを自動生成
  • docstring/description をLLM向けに: AIモデルが読むことを意識した説明を書く
  • エラーハンドリング: 例外をキャッチし、人間に読みやすいエラーメッセージを返す

9.2 セキュリティ

  • すべてのツール入力をバリデーション
  • アクセス制御を実装
  • ツール呼び出しをレート制限
  • ツール出力をサニタイズ
  • 機密データをログに出さない
  • 人間が承認するループ(Human-in-the-loop)を必ず設ける

9.3 エラーハンドリングの2種類

  1. プロトコルエラー: JSON-RPCエラー(不明なツール、無効な引数など)
  2. ツール実行エラー: isError: true をレスポンスに含める
# Python: ツール実行エラーの例
@mcp.tool()
async def fetch_data(url: str) -> str:
    """URLからデータを取得。"""
    try:
        async with httpx.AsyncClient() as client:
            response = await client.get(url, timeout=30.0)
            response.raise_for_status()
            return response.text
    except httpx.HTTPError as e:
        # エラーメッセージを文字列として返す(MCPが自動的にisError:trueに)
        return f"データ取得に失敗: {str(e)}"

9.4 ログ戦略

  • 構造化ログ(一貫したフォーマット、コンテキスト付き、タイムスタンプ、リクエストID)
  • 重要イベントのログ: 初期化、リソースアクセス、ツール実行、エラー、パフォーマンス

9.5 よくある問題と対処法

問題 原因 対処法
サーバーが接続できない パスが間違っている 絶対パスを使用、where/which で確認
ツールが表示されない 設定JSONの構文エラー JSONバリデーション、必須フィールド確認
stdoutにログ出力 print()やconsole.log()の使用 stderr/ログファイルに変更
環境変数が見つからない MCPサーバーは限定的な環境変数のみ継承 env キーで明示的に指定

10. 公式ドキュメント・リファレンス

コアドキュメント

ページ URL
公式サイトトップ https://modelcontextprotocol.io/
Introduction https://modelcontextprotocol.io/introduction
Architecture Overview https://modelcontextprotocol.io/docs/learn/architecture
Server Concepts https://modelcontextprotocol.io/docs/learn/server-concepts
Client Concepts https://modelcontextprotocol.io/docs/learn/client-concepts

開発ガイド

ページ URL
Build an MCP Server https://modelcontextprotocol.io/docs/develop/build-server
Build an MCP Client https://modelcontextprotocol.io/docs/develop/build-client

仕様(Specification)

ページ URL
Tools https://modelcontextprotocol.io/docs/concepts/tools
Resources https://modelcontextprotocol.io/docs/concepts/resources
Prompts https://modelcontextprotocol.io/docs/concepts/prompts
Specification (Latest) https://modelcontextprotocol.io/specification/latest

ツール・デバッグ

ページ URL
Debugging Guide https://modelcontextprotocol.io/docs/tools/debugging
MCP Inspector https://modelcontextprotocol.io/docs/tools/inspector

SDK

言語 URL
Python SDK https://modelcontextprotocol.io/sdk/python
TypeScript SDK https://modelcontextprotocol.io/sdk/typescript
Java SDK https://modelcontextprotocol.io/sdk/java

GitHub リポジトリ

リポジトリ URL
MCP Specification https://github.com/modelcontextprotocol/specification
Python SDK https://github.com/modelcontextprotocol/python-sdk
TypeScript SDK https://github.com/modelcontextprotocol/typescript-sdk
MCP Inspector https://github.com/modelcontextprotocol/inspector
Reference Servers https://github.com/modelcontextprotocol/servers
Quickstart Resources https://github.com/modelcontextprotocol/quickstart-resources

クライアント一覧

クライアント URL
対応クライアント一覧 https://modelcontextprotocol.io/clients

付録: Python vs TypeScript 比較表

項目 Python TypeScript
SDK mcp[cli] (pip/uv) @modelcontextprotocol/sdk (npm)
サーバークラス FastMCP McpServer
ツール定義 @mcp.tool() デコレータ + 型ヒント server.registerTool() + Zod スキーマ
リソース定義 @mcp.resource("uri") デコレータ server.registerResource()
プロンプト定義 @mcp.prompt() デコレータ server.registerPrompt()
トランスポート mcp.run(transport="stdio") new StdioServerTransport() + server.connect()
ログ禁止 print() (stdoutに書く) console.log() (stdoutに書く)
ログOK print(file=sys.stderr), logging console.error()
ビルド 不要(直接実行) tsc でビルド必要
パッケージマネージャー uv / pip npm
実行方法 uv run server.py node build/index.js