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統合の全体像
アーキテクチャ

動作フロー:
- Claude Codeで「データを可視化して」と指示
- jupyter-mcp serverがJupyter Server API/セッションを介してノートブックを操作
- セルを自動挿入・編集・実行
- 結果をClaude Codeにフィードバック
- エラーがあれば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の動作:
-
list_notebooksで全ノートブック一覧を取得 - 各ノートブックを
open_notebookで開く - すべてのセルを
execute_cellで順次実行 - エラーが発生したセルを特定し、修正提案
再利用可能なヘルパーモジュール
分析の効率化のため、共通処理を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 | 再現性が必須 |
併用戦略(ベストプラクティス)
実際のプロジェクトでは、両者を併用しています:

運用フロー:
- Grafanaで異常を検知
- Claude Codeに「XXの原因を分析して」と指示
- Jupyter + MCPで自動的にデータ取得・分析
- 結果をもとに戦略パラメータを調整
Grafana + mcp-grafana を併用する場合の課題、Tips
実際のプロジェクトでGrafana + mcp-grafanaとJupyter + jupyter-mcpを併用する場合の実務的なTipsです。
データソース役割分担
- Prometheus/Lokiの探索はGrafana側に寄せ、重い集計や実験はJupyterへ回す(役割分担)。
- mcp-grafanaの公式対応データソース(Prometheus/Loki)以外は、Jupyter経由でアクセスする。
参考:
マクロ展開の注意点
$__intervalを直接関数に渡さない:
-
(対応するデータソースであれば)
$__interval_longでSQLリテラルに展開してからDATE_BIN(INTERVAL '1 MINUTE', …)に適用。利用可否はデータソースに依存します(Databricksなど一部で対応)。 -
あるいは**
$__customInterval()で想定粒度のホワイトリスト**(1m/5m/1h…)を事前分岐し、安全な断片に展開。 -
どうしても難しい場合は、固定バケット(例:
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で接続
-
$__timeFilterはtimestampカラムに対して展開 -
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」
対処法:
- JupyterLabが起動しているか確認:
curl -f http://localhost:8888/ && echo "✅ Running"
- トークンが正しいか確認:
grep JUPYTER_TOKEN .env
-
.mcp.jsonのcommandパスを確認:
ls -la /path/to/venv/bin/jupyter-mcp-server
- 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の導入効果
- ✅ 探索的分析:「異常な約定を検出して」→ Claude Codeが自動でデータ探索
- ✅ パラメータ最適化:複数パターンの検証を自動化
- ✅ デバッグ:エラーの原因をAIが自動で特定・修正
Grafanaとの使い分け
- Grafana:リアルタイム監視・アラート
- Jupyter + MCP:深い分析・統計処理・AI活用
両者を併用することで、リアルタイム性と分析の深さを両立できます。
Jupyter + MCPにより、データ分析が「対話型」になり、AIと共同で分析する新しい体験が実現しました。取引ボットや時系列データでの分析を行う方は、ぜひ試してみてください。