← MCPで Claude を業務システムと統合する
LESSON 06 / 06

MCP デバッグとトラブルシューティング

所要時間 13分 上級レベル

MCPは標準仕様と言いつつ、実装で 「動かない」 ことが頻繁に起きます。本レッスン(コース最終回)では、デバッグの実用テクニックをまとめます。

MCP Inspector の活用

公式の MCP Inspector は 最強のデバッグツール

# MCP Inspector の起動
npx @modelcontextprotocol/inspector python server.py

# ブラウザで http://localhost:5173 が開く
# できること:
# - Tools/Resources/Promptsの一覧
# - 各ツールの呼び出しテスト
# - JSON-RPC通信のリアルタイム表示
# - エラーメッセージの確認

ログ出力の鉄則

MCP は stdio で通信するため、標準出力(stdout)にログを出してはいけません

# 悪い例(NGパターン)
print("debug message")  # stdout に出てしまい通信が壊れる

# 正しい例
import sys
import logging

logging.basicConfig(
    level=logging.DEBUG,
    stream=sys.stderr,  # stderr に出力
    format='%(asctime)s [%(levelname)s] %(name)s: %(message)s',
)

logger = logging.getLogger("mcp_server")
logger.info("Server starting...")

Claude Desktop のログ確認

OS ログパス
macOS ~/Library/Logs/Claude/mcp*.log
Windows %APPDATA%Claudelogsmcp*.log
# macOS で確認
tail -f ~/Library/Logs/Claude/mcp-server-myserver.log

# Windowsで確認
Get-Content -Path "$env:APPDATAClaudelogsmcp-server-myserver.log" -Wait

よくあるエラー Top10

1. ImportError / ModuleNotFoundError

# 原因: 仮想環境が活性化されていない
# 対処: フルパスで Python を指定

# config.json
{
  "mcpServers": {
    "myserver": {
      "command": "/path/to/.venv/bin/python",  // フルパス
      "args": ["/path/to/server.py"]
    }
  }
}

2. ツールが認識されない

# 原因: ツール名が無効
# - 半角英数字とアンダースコアのみ
# - スネークケース推奨

# 悪い例
@mcp.tool()
def 検索ツール(query: str):  # 日本語名はNG
    ...

# 正しい例
@mcp.tool()
def search_tool(query: str):
    ...

3. JSON シリアライズエラー

# 原因: ツール結果にシリアライズ不可な型
# - datetime, Decimal, custom class 等

# 対処: json.dumps の default を指定
import json
from datetime import datetime, date

def custom_serializer(obj):
    if isinstance(obj, (datetime, date)):
        return obj.isoformat()
    raise TypeError(f"Type {type(obj)} not serializable")


@mcp.tool()
def get_user(user_id: int) -> str:
    user = db.query(...)
    return json.dumps(user, default=custom_serializer)

4. タイムアウト

# 原因: ツール処理が60秒以上かかる
# 対処: 非同期化 or 結果を分割

@mcp.tool()
async def long_running_task(query: str) -> str:
    # 短時間で完了する範囲に絞る
    if estimated_time(query) > 30:
        return "処理時間が長すぎます。範囲を絞ってください"

    return await do_work(query)

5. 環境変数が読めない

# 原因: env が config に書かれていない
# 対処: config.jsonに明記

{
  "mcpServers": {
    "myserver": {
      "command": "python",
      "args": ["server.py"],
      "env": {
        "API_KEY": "...",
        "DATABASE_URL": "..."
      }
    }
  }
}

6. Pythonバージョン非互換

# 原因: Python 3.10未満では mcp ライブラリが動かない
# 対処: Pythonバージョン確認・更新

python --version  # 3.10+

# pyenv で複数バージョン管理
pyenv install 3.11.0
pyenv local 3.11.0

7. パスの空白・特殊文字

# 原因: パスに空白や日本語があるとパース失敗
# 対処: シンボリックリンクまたはエスケープ

# macOS/Linux
ln -s "/path with spaces/server.py" /tmp/server.py
# config.json の args に /tmp/server.py を指定

# Windows
# args は配列で渡されるので空白OK、ただし  でエスケープ
"args": ["C:\Users\Name\Documents\server.py"]

8. ツール定義のスキーマエラー

# 原因: input_schema が JSON Schema 違反
# 対処: 厳密に従う

# 悪い例
{
  "type": "object",
  "properties": {
    "id": "integer"  // type を指定していない
  }
}

# 正しい例
{
  "type": "object",
  "properties": {
    "id": {
      "type": "integer",
      "description": "..."
    }
  },
  "required": ["id"]
}

9. 並列実行で DB コネクション枯渇

# 原因: ツールが同時実行されると DB 接続が増える
# 対処: コネクションプール

from psycopg2.pool import SimpleConnectionPool

pool = SimpleConnectionPool(minconn=1, maxconn=10, dsn=DATABASE_URL)

@mcp.tool()
def search(query: str) -> str:
    conn = pool.getconn()
    try:
        with conn.cursor() as cur:
            cur.execute(query)
            return json.dumps(cur.fetchall())
    finally:
        pool.putconn(conn)

10. プロセスが死ぬ

# 原因: 致命的例外で MCP サーバープロセス終了
# 対処: グローバル例外ハンドラ

import sys
import traceback

def crash_handler(exctype, value, tb):
    logger.critical("Uncaught exception:", exc_info=(exctype, value, tb))
    # スタックトレースを保存
    with open("/tmp/mcp_crash.log", "a") as f:
        traceback.print_exception(exctype, value, tb, file=f)

sys.excepthook = crash_handler

パフォーマンス計測

# 各ツールの実行時間を計測

import time
from functools import wraps

def measure_time(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        try:
            return func(*args, **kwargs)
        finally:
            duration = time.time() - start
            logger.info(f"{func.__name__}: {duration:.3f}s")
            metrics_db.record(func.__name__, duration)
    return wrapper


@mcp.tool()
@measure_time
def search(query: str):
    ...

本番運用のためのチェックリスト

項目 確認
ロギング stderrに構造化ログ
エラー処理 すべての例外を捕捉、ユーザー向けメッセージに変換
タイムアウト 長い処理に明示的タイムアウト
接続プール DB・APIクライアントを再利用
キャッシュ 頻繁な参照はTTLキャッシュ
認証 環境変数 or シークレット管理
テスト 主要シナリオを自動テスト
監視 レイテンシ・エラー率の継続監視

このレッスンのまとめ

「MCP Inspectorでテスト → stderrログ → よくあるエラーの先回り対処 → パフォーマンス計測」のフローでデバッグできます。本コース「MCPで Claude を業務システムと統合する」はこれで修了です。最後の上級コース「Claudeを本番運用するためのインフラ・モニタリング・ガバナンス」へ。

よくある質問

この記事に関連する質問と答えをまとめました。

Q.MCP サーバーが動かない時のデバッグ手順は?
A.
①MCP Inspector でテスト、②stderr ログ確認、③Claude Desktop のログ確認、④Pythonバージョン確認、⑤環境変数の確認、の順に切り分けるのが効率的です。
Q.よくあるエラーと対処は?
A.
ImportError(仮想環境)、ツール認識NG(名前の不正)、JSON シリアライズエラー、タイムアウト、環境変数読込失敗の5つが頻出。Lesson 6に対処法を体系的にまとめています。