下書きのプレビューを表示中
📊

Claude Code × jupyter-mcp で実現する対話型データ分析環境

下書き

はじめに

趣味の自動取引ボット開発で、QuestDB(時系列DB)に蓄積した取引データを JupyterLab 上で分析しています。従来の Grafana では実現できなかった 対話型の高度なデータ分析環境 を、Jupyter MCP Server で実現できたので共有します。

本記事では、以下を解説します:

  • なぜJupyter + MCPなのか:Grafanaの課題と解決策
  • jupyter-mcpの導入方法:3ステップで完了
  • 実践例:Claude Codeによる自動操作とデータ分析
  • Grafana比較:mcp-grafanaとの比較
  • 実務Tips:併用戦略とトラブルシューティング

なぜ Grafana ではなく Jupyter なのか?

ボットの運用では、約定データ・ポジション履歴・スプレッド変動などを時系列で可視可・分析する必要があります。従来はGrafanaを使っていましたが、以下の課題がありました。

Grafana + mcp-grafana の限界

課題 詳細
高度な分析 ダッシュボードでは複雑な統計処理(回帰分析・クラスタリング等)が難しい
データ加工 SQLクエリベースで、複雑なデータ整形にはPython/Pandasが必要
データアクセス mcp-grafanaは、Loki/Prometheus 以外のデータソースの直接クエリ不可/他は制限あり
LLM指示 変数/マクロ前提が必須、集計の指示があいまいになり誤訳・誤生成が起きやすい
再現性 分析手順を共有・再実行しにくい

Jupyter + jupyter-mcp の優位性

一方、JupyterLab + jupyter-mcp(Model Context Protocol) では:

メリット 詳細
🤖 AIによる分析自動化 Claude Codeが自動でセルを追加・実行・デバッグ
📊 高度な統計分析 Python全エコシステム(scikit-learn, statsmodels等)を活用
🔄 再現性の保証 ノートブックで分析手順を完全に記録
柔軟なデータ処理 Pandas/NumPyで複雑な加工・集計が自由自在
📈 カスタム可視化 Matplotlib/Seabornなど独自グラフ作成、可視化の柔軟性

jupyter-mcp統合の全体像

アーキテクチャ

jupyter-mcp

動作フロー

  1. Claude Codeで「データを可視化して」と指示
  2. jupyter-mcp serverがJupyter Server API/セッションを介してノートブックを操作
  3. セルを自動挿入・編集・実行
  4. 結果をClaude Codeにフィードバック
  5. エラーがあればClaude Codeが自動デバッグ

セットアップ:3ステップで完了

1: 必要なパッケージのインストール

# Python仮想環境を作成
python3 -m venv venv
source venv/bin/activate

# Jupyter関連パッケージ
pip install \
  jupyterlab==4.4.9 \
  jupyter-collaboration==4.0.2 \
  datalayer_pycrdt==0.12.17

# データ分析パッケージ
pip install pandas matplotlib seaborn numpy psycopg2-binary

# uvx(MCP server実行用)をインストール
brew install uv

# venvに入れる場合
pip install jupyter-mcp-server

# あるいは uv を使う場合
uvx jupyter-mcp-server

*上記のバージョンは2025年10月時点のセットアップ例です。環境により最新のドキュメントに従って調整してください。

2: MCP設定ファイルの作成

プロジェクトルートに.mcp.jsonを作成:

{
  "mcpServers": {
    "jupyter": {
      "command": "/path/to/venv/bin/jupyter-mcp-server",
      "env": {
        "DOCUMENT_URL": "http://localhost:8888",
        "DOCUMENT_TOKEN": "${JUPYTER_TOKEN}",
        "RUNTIME_URL": "http://localhost:8888",
        "RUNTIME_TOKEN": "${JUPYTER_TOKEN}",
        "ALLOW_IMG_OUTPUT": "true"
      }
    }
  }
}

重要な設定項目

  • command: venv内のjupyter-mcp-serverのフルパスを指定
  • DOCUMENT_TOKEN / RUNTIME_TOKEN: JupyterLabの認証トークン(環境変数で管理)

3: 固定トークンでJupyterLab起動

トークンローテーション問題を回避するため、固定トークンで起動します。

トークンローテーション問題 とは、JupyterLab がデフォルトで、起動のたびに新しいアクセストークン(認証用の鍵)をランダム生成することです。

# 1. セキュアなトークンを生成
openssl rand -hex 32

# 2. .env ファイルに保存
echo "JUPYTER_TOKEN=生成されたトークン" >> .env

# 3. 固定トークンで起動
jupyter lab \
  --no-browser \
  --port=8888 \
  --IdentityProvider.token="${JUPYTER_TOKEN}"

自動起動スクリプト例scripts/start-all.sh):

#!/bin/bash

# .envから環境変数を読み込み
source .env

# JupyterLabを固定トークンで起動
jupyter lab \
  --no-browser \
  --port=8888 \
  --IdentityProvider.token="${JUPYTER_TOKEN}" \
  > /tmp/jupyter-lab.log 2>&1 &

echo "✅ Jupyter Lab起動完了"
echo "   アクセスURL: http://localhost:8888/lab?token=${JUPYTER_TOKEN}"
echo "   🔒 固定トークン使用中(MCP連携対応)"

実践例:時系列データ分析の自動化

実際の取引ボットで、QuestDBに蓄積した約定データを分析する例を示します。

Claude Codeでの操作例

例1: データ取得と可視化

プロンプト例

notebooks/analysis/daily_pnl.ipynb を新規作成して、
今日の約定データを取得し、累積損益を可視化してください

Claude Codeが自動生成するコード(抜粋):

# データ取得
with QuestDBClient() as client:
    df = client.query("""
        SELECT * FROM trading_fills
        WHERE timestamp >= dateadd('d', -1, now())
    """)

# 累積損益の可視化
df['cumulative_pnl'] = df['pnl'].cumsum()
ax.plot(df['timestamp'], df['cumulative_pnl'])
ax.set_title('累積損益の推移')

ポイント:Claude Codeが自動でセルを挿入・実行・デバッグし、可視化結果をフィードバック

例2: バッチ処理の自動化

プロンプト例

notebooks/analysis/ 内のすべてのノートブックを順番に実行して、
エラーがあれば報告してください

Claude Codeの動作

  1. list_notebooksで全ノートブック一覧を取得
  2. 各ノートブックをopen_notebookで開く
  3. すべてのセルをexecute_cellで順次実行
  4. エラーが発生したセルを特定し、修正提案

再利用可能なヘルパーモジュール

分析の効率化のため、共通処理をnotebooks/utils/にモジュール化しています。

QuestDB接続ヘルパー(questdb_helper.py)

import psycopg2
import pandas as pd

class QuestDBClient:
    """QuestDB接続のコンテキストマネージャー"""

    def __init__(self, host='localhost', port=8812,
                 database='qdb', user='admin', password='quest'):
        self.conn_params = {...}

    def query(self, sql: str) -> pd.DataFrame:
        """SQLクエリを実行してDataFrameで返す"""
        return pd.read_sql_query(sql, self.conn)

使用例

with QuestDBClient() as client:
    df = client.query("SELECT * FROM trading_fills LIMIT 100")

Grafana vs Jupyter MCP:詳細比較

パフォーマンス

指標 Grafana Jupyter + MCP
初期表示速度 ⚡ 高速(〜1秒) 🐢 中速(2〜5秒)
複雑クエリ ⚠️ 遅延あり ✅ Pandas最適化で高速
リアルタイム更新 ✅ 自動リフレッシュ ⚠️ 手動実行

結論:リアルタイム監視ならGrafana、深い分析ならJupyter + MCP

機能比較

機能 Grafana Jupyter + MCP
基本的な可視化 ✅ 豊富なパネル ✅ Matplotlib/Seaborn
統計分析 ❌ SQLのみ ✅ scikit-learn等
機械学習 ❌ 不可 ✅ TensorFlow/PyTorch
AIアシスト ❌ なし ✅ Claude Code統合
カスタム計算 ⚠️ 限定的 ✅ Python全機能
データ加工 ⚠️ SQL変換 ✅ Pandas自在
再現性 ❌ ダッシュボード依存 ✅ ノートブック完全記録
共有・配布 ✅ ダッシュボードJSON ✅ .ipynbファイル

ユースケース別の推奨

ユースケース 推奨ツール 理由
リアルタイム監視 Grafana 自動更新・アラート機能が強力
日次レポート Jupyter + MCP 複雑な集計・グラフ作成が容易
アドホック分析 Jupyter + MCP AIアシストで探索的分析が高速
統計モデリング Jupyter + MCP Python統計ライブラリ必須
経営ダッシュボード Grafana 非エンジニアでも閲覧可能
研究・論文 Jupyter + MCP 再現性が必須

併用戦略(ベストプラクティス)

実際のプロジェクトでは、両者を併用しています:

jupyter-mcp-grafana

運用フロー

  1. Grafanaで異常を検知
  2. Claude Codeに「XXの原因を分析して」と指示
  3. Jupyter + MCPで自動的にデータ取得・分析
  4. 結果をもとに戦略パラメータを調整
Grafana + mcp-grafana を併用する場合の課題、Tips

実際のプロジェクトでGrafana + mcp-grafanaとJupyter + jupyter-mcpを併用する場合の実務的なTipsです。

データソース役割分担

  • Prometheus/Lokiの探索はGrafana側に寄せ、重い集計や実験はJupyterへ回す(役割分担)。
  • mcp-grafanaの公式対応データソース(Prometheus/Loki)以外は、Jupyter経由でアクセスする。

参考:

マクロ展開の注意点

$__intervalを直接関数に渡さない

  1. (対応するデータソースであれば)$__interval_longSQLリテラルに展開してからDATE_BIN(INTERVAL '1 MINUTE', …)に適用。利用可否はデータソースに依存します(Databricksなど一部で対応)。

    参考:Databricks data source for Grafana

  2. あるいは**$__customInterval()想定粒度のホワイトリスト**(1m/5m/1h…)を事前分岐し、安全な断片に展開。

  3. どうしても難しい場合は、固定バケット(例:INTERVAL '5 minutes')に寄せる。

タイムゾーンと相対時間の扱い

タイムゾーンや相対時間のズレに注意

$__timeFilterは展開後のUTC相対指定の解釈で差が出る報告があるため、絶対指定デバッグを一度挟む。

参考:$__timeFilter() no longer respects the local time zone #13769

LLMプロンプトのコツ

LLMプロンプトで「Grafana特有の語彙」を明示

パネル種別、変数、マクロ、クエリビルダー/コードモードの切替など生成の前提を与える。特に$__intervalの自動調整挙動を理解させないと、意図しない粒度になる可能性があります。

参考:The $__interval macro returns wrong values - Grafana Community Forums

QuestDB + Grafanaの場合

QuestDBをGrafanaで使用する場合:

  • PostgreSQL Wire Protocolで接続
  • $__timeFiltertimestampカラムに対して展開
  • DATE_BIN相当の機能はSAMPLE BYを使用(QuestDB独自構文)

安全な時間粒度指定の例

-- Grafana変数を使わない安全な書き方
SELECT
  timestamp,
  avg(price) as avg_price,
  count(*) as fill_count
FROM trading_fills
WHERE timestamp >= '2025-01-01T00:00:00Z'
  AND timestamp < '2025-01-02T00:00:00Z'
SAMPLE BY 5m;  -- QuestDB独自の時間集約構文

一方、Jupyter + Pandasでは:

# Pandasでの明示的な粒度制御
df = client.query("SELECT * FROM trading_fills WHERE timestamp >= '2025-01-01'")
df['timestamp'] = pd.to_datetime(df['timestamp'])
df_resampled = df.set_index('timestamp').resample('5min').agg({
    'price': 'mean',
    'size': 'sum'
})

このように、Pandasのresample('5min')粒度が明示的で、LLMに指示しやすく、型エラーも起きません。

トラブルシューティング

MCPサーバーが接続できない

症状:Claude Codeで「MCP server connection failed」

対処法

  1. JupyterLabが起動しているか確認:
curl -f http://localhost:8888/ && echo "✅ Running"
  1. トークンが正しいか確認:
grep JUPYTER_TOKEN .env
  1. .mcp.jsoncommandパスを確認:
ls -la /path/to/venv/bin/jupyter-mcp-server
  1. Claude Codeを再起動(MCP接続をリセット)
トークンが無効(401 Unauthorized)

原因:JupyterLabが再起動でトークンを再生成した

解決策:固定トークンで起動(上記Step 3参照)

# 固定トークンで起動すれば解決
jupyter lab --IdentityProvider.token="${JUPYTER_TOKEN}"
pyarrowのビルドエラー

症状pip install jupyter-collaborationで失敗

対処法

# macOS
brew install apache-arrow

# Ubuntu
sudo apt install libarrow-dev libarrow-python-dev

# その後、再度pipインストール
pip install jupyter-collaboration==4.0.2

まとめ

Jupyter + MCPの導入効果

  1. 探索的分析:「異常な約定を検出して」→ Claude Codeが自動でデータ探索
  2. パラメータ最適化:複数パターンの検証を自動化
  3. デバッグ:エラーの原因をAIが自動で特定・修正

Grafanaとの使い分け

  • Grafana:リアルタイム監視・アラート
  • Jupyter + MCP:深い分析・統計処理・AI活用

両者を併用することで、リアルタイム性分析の深さを両立できます。

Jupyter + MCPにより、データ分析が「対話型」になり、AIと共同で分析する新しい体験が実現しました。取引ボットや時系列データでの分析を行う方は、ぜひ試してみてください。

参考リンク

この記事は下書きです