「Googleアナリティクスを見ても、結局どのページを改善すればいいかわからない」
そんな悩みを抱えているWordPress運営者は多いはずです。
データはあるのに、次のアクションに結びつかない。
その原因のひとつは、データの読み取りと分析をすべて人間がやっていることにあります。
この記事では、Claude(AI)にGA4とSearch Consoleを直接つなぐ方法を解説します。
- 「先月のアクセスを分析して改善提案して」と話しかけるだけでレポートが完成
- 「リライトすべき記事を優先度順に教えて」で改善候補を自動抽出
- 複数サイトのデータを一括取得して比較分析
- ChatGPTやGeminiなど、Claude以外のAIとの連携(応用すればある程度可能)
使うのはMCP(Model Context Protocol)という仕組みです。
専門知識がなくても、この記事の手順通りに進めれば構築できます。
クルエイチ今回はこのサイト(Next Clue Lab)の他に、別で運営している平成レトロゲームブログの方も対象にしてみました。
そもそもMCPとは?
MCPを一言で言うと
MCPとは、AIに外部ツールを持たせるための仕組みです。
通常のClaude(AI)は、チャットでやり取りするだけです。
しかしMCPを使うと、ClaudeがGA4やSearch ConsoleのAPIを「道具」として使えるようになります。
従来の方法との違い
GA4からCSVエクスポート
↓
Claudeにファイルをアップロード
↓
「このデータを分析して」と依頼
↓(手動・毎回必要)
Claudeに話しかけるだけ
↓(自動・リアルタイム)
GA4 / Search Console からデータ取得
↓
分析・提案まで一気に完了
WordPress運営者にとって何が嬉しいのか
- 時短: 毎月のレポート作成が会話1回で完了
- 発見: 自分では気づかなかった改善点をAIが指摘
- 複数サイト対応: 管理サイトが多くても一括分析が可能



複数サイト対応が特に重要!
同じデータの”比較”が可能になります。
事前準備
必要なもの一覧
作業を始める前に以下を用意してください。
- Claude Desktop(無料・要インストール)
- Python 3.10以上
- uv(Pythonパッケージ管理ツール)
- Googleアカウント
- GA4プロパティ(計測済みのもの)
- Search Console登録済みサイト



詳しい準備方法は後述するのでご安心ください!
サービスアカウントとは?
本記事では「サービスアカウント」というものを作成します。
既存のGmailアドレスとは全く別物なので混乱しないようにしてください。
| 種類 | 例 | 用途 |
|---|---|---|
| 通常のGoogleアカウント | yourname@gmail.com | 人間が使う |
| サービスアカウント | wordpress-analytics@project-id.iam.gserviceaccount.com | プログラムが使う |
サービスアカウントは、プログラムがGoogleのAPIにアクセスするための「ロボット専用アカウント」です。
パスワードの代わりにJSONキーファイルで認証します。
所要時間の目安
初心者向けの場合の目安時間は以下の通りです。
Google系の各種ツールやClaudeの知識がある方なら、もっと早く対応可能です!
| ステップ | 内容 | 時間 |
|---|---|---|
| STEP1 | Google Cloud設定 | 約20分 |
| STEP2 | MCPサーバー構築 | 約20分 |
| STEP3 | 動作テスト | 約10分 |
| STEP4 | Claude Desktop組み込み | 約5分 |
| 合計 | 約55分 |
STEP1|Google Cloud設定
1-1. サービスアカウントの作成
まずは、プログラムがGoogleのAPIにアクセスするための「ロボット専用アカウント」であるサービスアカウントを作ります。


- Google Cloud Console にアクセス
- 新しいプロジェクトを作成(例:wordpress-analytics)
- 左メニュー「IAMと管理」→「サービスアカウント」
- 「サービスアカウントを作成」をクリック
- 名前を入力(例:wordpress-analytics)して作成



「権限」と「アクセス権を持つプリンシパル」は空欄で省略して構いません!
1-2. 鍵作成とJSONキーのダウンロード


- 作成したサービスアカウントの右側にある操作の縦三点リーダーをクリック
- 「鍵を管理」→「鍵」タブ→「鍵を追加」→「新しい鍵を作成」
- 形式「JSON」を選択してダウンロード
- ダウンロードしたファイルを
service-account.jsonにリネーム
1-3. APIの有効化


Google Cloud ConsoleでAPIを2つ有効化します。
- 「APIとサービス」→「ライブラリ」
- 「Google Analytics Data API」を検索して有効化
- 「Google Search Console API」を検索して有効化
1-4. GA4への権限付与
JSONファイルの中の client_email の値をコピーして、GA4に追加します。
この章はGoogle Analyticsで作業します!
ロール(直接の役割とデータ制限)はセキュリティ観点などもあり、基本的に閲覧者としてください。


GA4管理画面
└── 左下「管理(歯車アイコン)」
└──「プロパティのアクセス管理」
└── 右上「+」→「ユーザーを追加」
├── メール:client_emailの値を貼り付け
└── ロール:「閲覧者」を選択
念のため、「アカウントのアクセス管理」ではなく「プロパティのアクセス管理」から追加してください。
1-5. Search Consoleへの権限付与
この章はGoogle Search Consoleで作業します!


Search Console
└── 左サイドバー下部「設定」
└──「ユーザーと権限」
└──「ユーザーを追加」
├── メール:client_emailの値を貼り付け
└── 権限:「制限付き」を選択
ロールは「閲覧者」「制限付き」で十分です。
知識があって高度なことを使用としていない限り、より強い権限は不要です。
ここまでのチェックリスト
ここまでの作業が出来ているかを振り返ってみましょう!
ここが何気に一番大変だったりします…普段触らない部分だからね…


STEP2|MCPサーバー構築
2-1. プロジェクトフォルダの作成
この章はコマンドプロンプトでなくても良いですが…
次項でどうせコマンドプロンプトを使うので…
mkdir D:\wordpress-analytics-mcp
cd D:\wordpress-analytics-mcp



ファイル作成場所は任意です。
今回はDドライブ直下に作る例にしています。
Cドライブ以外に移動するときは、cdコマンドを付けずに
C:\Users>D:
としないといけません。
2-2. uvのインストールと初期化
uvのインストールと初期化、必要ライブラリをインストールします。
pip install uv
uv init .
uv add "mcp[cli]" google-analytics-data google-api-python-client google-auth
2-3. ファイルの配置
以下の構成になるように、ファイルを作成・配置します。
自動生成されていないファイルは、中身を空のままでファイルだけ手動で作ります。
D:\wordpress-analytics-mcp\ ← 2-1で作成した場所に読み替えてください
├── .venv\ ← 自動生成(触らない)
├── service-account.json ← STEP1でダウンロード
├── sites_config.json ← サイト設定ファイル
├── server.py ← MCPサーバー本体
└── manifest.json ← Claude Desktop用設定
2-4. sites_config.json の作成
管理するサイトを登録します。
sites_config.jsonに、以下の内容を一旦コピペし、その後内容を適宜変更してください。
サイトを追加するときはブロックを追記するだけです。
{
"sites": {
"mysite1": {
"ga4_property_id": "properties/あなたのプロパティID",
"search_console_url": "https://yoursite1.com/",
"display_name": "サイト1の名前"
},
"mysite2": {
"ga4_property_id": "properties/あなたのプロパティID",
"search_console_url": "https://yoursite2.com/",
"display_name": "サイト2の名前"
}
}
}


GA4管理画面
→「プロパティ設定」
→「プロパティの詳細」
→「プロパティID」に表示される数字。
設定ファイルには properties/ を先頭につけて記入します。



https://yoursite1.com/
の部分はご自身のサイトのURLに置き換えてください!
2-6. server.py の作成
MCPサーバーの本体です。
以下のコードを、そのままserver.pyの中身として貼り付けてください。
import json
import os
from datetime import datetime, timedelta
from mcp.server.fastmcp import FastMCP
from google.analytics.data_v1beta import BetaAnalyticsDataClient
from google.analytics.data_v1beta.types import (
RunReportRequest, DateRange, Metric, Dimension
)
from googleapiclient.discovery import build
from google.oauth2 import service_account
SERVICE_ACCOUNT_FILE = os.environ.get(
"GOOGLE_APPLICATION_CREDENTIALS", "service-account.json"
)
SITES_CONFIG_FILE = os.environ.get(
"SITES_CONFIG_FILE", "sites_config.json"
)
with open(SITES_CONFIG_FILE, "r", encoding="utf-8") as f:
SITES_CONFIG = json.load(f)["sites"]
SCOPES = [
"https://www.googleapis.com/auth/analytics.readonly",
"https://www.googleapis.com/auth/webmasters.readonly",
]
mcp = FastMCP("wordpress-analytics")
def get_credentials():
return service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES
)
def get_site_config(site_name: str) -> dict:
if site_name not in SITES_CONFIG:
available = list(SITES_CONFIG.keys())
raise ValueError(
f"サイト '{site_name}' が見つかりません。利用可能: {available}"
)
return SITES_CONFIG[site_name]
@mcp.tool()
def list_sites() -> str:
"""登録されているサイト一覧を表示する"""
sites = []
for key, config in SITES_CONFIG.items():
sites.append({
"site_name": key,
"display_name": config.get("display_name", key),
"url": config["search_console_url"],
})
return json.dumps({"sites": sites}, ensure_ascii=False, indent=2)
@mcp.tool()
def get_ga4_overview(site_name: str, days: int = 30) -> str:
"""GA4のサイト概要を取得する"""
try:
config = get_site_config(site_name)
client = BetaAnalyticsDataClient(credentials=get_credentials())
request = RunReportRequest(
property=config["ga4_property_id"],
dimensions=[Dimension(name="date")],
metrics=[
Metric(name="sessions"),
Metric(name="totalUsers"),
Metric(name="newUsers"),
Metric(name="bounceRate"),
Metric(name="averageSessionDuration"),
Metric(name="screenPageViews"),
],
date_ranges=[DateRange(
start_date=f"{days}daysAgo", end_date="today"
)],
)
response = client.run_report(request)
rows = []
for row in response.rows:
rows.append({
"date": row.dimension_values[0].value,
"sessions": int(row.metric_values[0].value),
"users": int(row.metric_values[1].value),
"new_users": int(row.metric_values[2].value),
"bounce_rate": round(float(row.metric_values[3].value) * 100, 1),
"avg_duration_sec": round(float(row.metric_values[4].value), 0),
"pageviews": int(row.metric_values[5].value),
})
return json.dumps({
"site": config.get("display_name", site_name),
"period_days": days, "data": rows
}, ensure_ascii=False, indent=2)
except Exception as e:
return json.dumps({"error": str(e)})
@mcp.tool()
def get_ga4_top_pages(site_name: str, days: int = 30, limit: int = 20) -> str:
"""GA4のページ別パフォーマンスを取得する"""
try:
config = get_site_config(site_name)
client = BetaAnalyticsDataClient(credentials=get_credentials())
request = RunReportRequest(
property=config["ga4_property_id"],
dimensions=[Dimension(name="pagePath"), Dimension(name="pageTitle")],
metrics=[
Metric(name="screenPageViews"),
Metric(name="sessions"),
Metric(name="bounceRate"),
Metric(name="averageSessionDuration"),
],
date_ranges=[DateRange(
start_date=f"{days}daysAgo", end_date="today"
)],
limit=limit,
order_bys=[{"metric": {"metric_name": "screenPageViews"}, "desc": True}],
)
response = client.run_report(request)
pages = []
for row in response.rows:
pages.append({
"path": row.dimension_values[0].value,
"title": row.dimension_values[1].value,
"pageviews": int(row.metric_values[0].value),
"sessions": int(row.metric_values[1].value),
"bounce_rate": round(float(row.metric_values[2].value) * 100, 1),
"avg_duration_sec": round(float(row.metric_values[3].value), 0),
})
return json.dumps({
"site": config.get("display_name", site_name),
"period_days": days, "pages": pages
}, ensure_ascii=False, indent=2)
except Exception as e:
return json.dumps({"error": str(e)})
@mcp.tool()
def get_search_console_queries(
site_name: str, days: int = 28, limit: int = 50
) -> str:
"""Search Consoleの検索クエリデータを取得する"""
try:
config = get_site_config(site_name)
service = build("searchconsole", "v1", credentials=get_credentials())
end_date = datetime.today().strftime("%Y-%m-%d")
start_date = (datetime.today() - timedelta(days=days)).strftime("%Y-%m-%d")
response = service.searchanalytics().query(
siteUrl=config["search_console_url"],
body={
"startDate": start_date,
"endDate": end_date,
"dimensions": ["query"],
"rowLimit": limit,
"orderBy": [{"fieldName": "clicks", "sortOrder": "DESCENDING"}],
}
).execute()
queries = []
for row in response.get("rows", []):
queries.append({
"query": row["keys"][0],
"clicks": row["clicks"],
"impressions": row["impressions"],
"ctr": round(row["ctr"] * 100, 2),
"position": round(row["position"], 1),
})
return json.dumps({
"site": config.get("display_name", site_name),
"period": f"{start_date} ~ {end_date}",
"queries": queries
}, ensure_ascii=False, indent=2)
except Exception as e:
return json.dumps({"error": str(e)})
@mcp.tool()
def get_all_sites_summary(days: int = 30) -> str:
"""全サイトのアクセス概要を一括取得して比較する"""
try:
client = BetaAnalyticsDataClient(credentials=get_credentials())
results = []
for site_name, config in SITES_CONFIG.items():
try:
request = RunReportRequest(
property=config["ga4_property_id"],
metrics=[
Metric(name="sessions"),
Metric(name="totalUsers"),
Metric(name="screenPageViews"),
Metric(name="bounceRate"),
],
date_ranges=[DateRange(
start_date=f"{days}daysAgo", end_date="today"
)],
)
response = client.run_report(request)
if response.rows:
row = response.rows[0]
results.append({
"site_name": site_name,
"display_name": config.get("display_name", site_name),
"sessions": int(row.metric_values[0].value),
"users": int(row.metric_values[1].value),
"pageviews": int(row.metric_values[2].value),
"bounce_rate": round(
float(row.metric_values[3].value) * 100, 1
),
})
except Exception as e:
results.append({"site_name": site_name, "error": str(e)})
return json.dumps({
"period_days": days, "sites": results
}, ensure_ascii=False, indent=2)
except Exception as e:
return json.dumps({"error": str(e)})
@mcp.tool()
def get_rewrite_candidates(site_name: str, days: int = 90) -> str:
"""リライト優先度の高い記事を自動抽出する"""
try:
config = get_site_config(site_name)
service = build("searchconsole", "v1", credentials=get_credentials())
end_date = datetime.today().strftime("%Y-%m-%d")
start_date = (
datetime.today() - timedelta(days=days)
).strftime("%Y-%m-%d")
response = service.searchanalytics().query(
siteUrl=config["search_console_url"],
body={
"startDate": start_date,
"endDate": end_date,
"dimensions": ["page"],
"rowLimit": 100,
"orderBy": [{"fieldName": "impressions", "sortOrder": "DESCENDING"}],
}
).execute()
candidates = []
for row in response.get("rows", []):
page = row["keys"][0]
clicks = row["clicks"]
impressions = row["impressions"]
ctr = row["ctr"] * 100
position = row["position"]
priority_score = 0
reasons = []
if 11 <= position <= 30:
priority_score += 40
reasons.append(f"検索順位{position:.1f}位(1ページ目まであと少し)")
if impressions >= 100 and ctr < 3.0:
priority_score += 30
reasons.append(f"表示回数{impressions}回なのにCTR{ctr:.1f}%")
if clicks == 0 and impressions >= 50:
priority_score += 20
reasons.append(f"表示{impressions}回あるがクリック0")
if priority_score > 0:
candidates.append({
"page": page,
"clicks": clicks,
"impressions": impressions,
"ctr": round(ctr, 2),
"position": round(position, 1),
"priority_score": priority_score,
"reasons": reasons,
})
candidates.sort(key=lambda x: x["priority_score"], reverse=True)
return json.dumps({
"site": config.get("display_name", site_name),
"period": f"{start_date} ~ {end_date}",
"rewrite_candidates": candidates[:30]
}, ensure_ascii=False, indent=2)
except Exception as e:
return json.dumps({"error": str(e)})
@mcp.tool()
def get_new_article_ideas(site_name: str, days: int = 90) -> str:
"""新規記事作成のキーワードアイデアを抽出する"""
try:
config = get_site_config(site_name)
service = build("searchconsole", "v1", credentials=get_credentials())
end_date = datetime.today().strftime("%Y-%m-%d")
start_date = (
datetime.today() - timedelta(days=days)
).strftime("%Y-%m-%d")
response = service.searchanalytics().query(
siteUrl=config["search_console_url"],
body={
"startDate": start_date,
"endDate": end_date,
"dimensions": ["query"],
"rowLimit": 200,
"orderBy": [{"fieldName": "impressions", "sortOrder": "DESCENDING"}],
}
).execute()
question_patterns = [
"とは", "方法", "やり方", "おすすめ", "比較",
"違い", "使い方", "設定", "原因", "解決",
"できない", "料金", "無料", "how", "best",
]
high_impression = []
question_queries = []
untapped = []
for row in response.get("rows", []):
query = row["keys"][0]
clicks = row["clicks"]
impressions = row["impressions"]
ctr = row["ctr"] * 100
position = row["position"]
if impressions >= 100 and clicks <= 5 and position > 10:
high_impression.append({
"query": query,
"impressions": impressions,
"clicks": clicks,
"position": round(position, 1),
})
if any(p in query for p in question_patterns) and impressions >= 50:
question_queries.append({
"query": query,
"impressions": impressions,
"ctr": round(ctr, 2),
"position": round(position, 1),
})
if position >= 50 and impressions >= 100:
untapped.append({
"query": query,
"impressions": impressions,
"position": round(position, 1),
})
return json.dumps({
"site": config.get("display_name", site_name),
"new_article_ideas": {
"high_impression_low_click": sorted(
high_impression,
key=lambda x: x["impressions"], reverse=True
)[:20],
"question_format_queries": sorted(
question_queries,
key=lambda x: x["impressions"], reverse=True
)[:20],
"untapped_queries": sorted(
untapped,
key=lambda x: x["impressions"], reverse=True
)[:20],
}
}, ensure_ascii=False, indent=2)
except Exception as e:
return json.dumps({"error": str(e)})
if __name__ == "__main__":
mcp.run(transport="stdio")
STEP3|動作テスト
3-1. MCP Inspectorでテスト
コンソールで以下を1行ずつ実行します。



D:\wordpress-analytics-mcp
の部分は2-1で作成した場所に読み替えてください。
cd D:\wordpress-analytics-mcp
uv run mcp dev server.py
Cドライブ以外に移動するときは、cdコマンドを付けずに
C:\Users>D:
としないといけません。
ブラウザが自動で開き、MCP Inspectorの画面が表示されます。


「Connect」ボタンを押下
→「Tools」タブをクリック
→「List Tools」ボタンをクリック してツール一覧が表示されれば成功です。
3-2. 実際にツールを実行してみる
list_sitesをクリック- 「Run Tool」ボタンを押す
sites_config.jsonに登録したサイト一覧が返ってくればOK
3-3. よくあるエラーと対処法
| エラー文 | 原因 | 対処法 |
|---|---|---|
uv: command not found | uvが未インストール | pip install uv を実行 |
JSONDecodeError | sites_config.jsonの末尾カンマ | 最後の }, を } に修正 |
FileNotFoundError | service-account.jsonの場所が違う | フォルダ直下に配置されているか確認 |
403 Permission denied | GA4/SCへの権限付与が未完了 | STEP1-4・1-5を再確認 |
ここまでのチェックリスト


STEP4|Claude Desktopへの組み込み
最後に、Claude Desktopへデータを渡す部分を作成します。
4-1. manifest.json の作成
manifest.json の中身を作成します。
基本的には以下をコピペするだけで良いです。
{
"dxt_version": "0.1",
"name": "wordpress-analytics",
"version": "1.0.0",
"description": "WordPress Analytics MCP Server",
"author": {
"name": "Your Name"
},
"server": {
"type": "python",
"entry_point": "server.py",
"mcp_config": {
"command": "D:\\wordpress-analytics-mcp\\.venv\\Scripts\\python.exe",
"args": [
"D:\\wordpress-analytics-mcp\\server.py"
],
"env": {
"GOOGLE_APPLICATION_CREDENTIALS": "D:\\wordpress-analytics-mcp\\service-account.json",
"SITES_CONFIG_FILE": "D:\\wordpress-analytics-mcp\\sites_config.json"
}
}
}
}
4-2. 拡張機能としてインストール
Claude Desktop
└── 設定 → 拡張機能
└──「展開済み拡張機能をインストール」
└── D:\wordpress-analytics-mcp\ を選択
4-3. 動作確認
チャット画面の「+」ボタンをクリックしたときに wordpress-analytics がトグル付きで表示されていれば成功です。
実践活用例
ここからが本番です。
実際にClaudeに話しかけてみましょう。
リライト記事を自動発見する
「mysite1のリライト候補を抽出して、優先度の高い順に理由とともに教えて」
Claudeは検索順位・CTR・表示回数などを総合的に判断し、リライト優先度の高いページを自動でリストアップします。
「検索順位15位でCTRが1.2%しかない」「表示回数500回なのにクリック0」など、具体的な理由とともに提示してくれます。
新規記事アイデアを発掘する
「mysite1で新規記事を書くべきキーワードを教えて。疑問形クエリを優先して」
Search Consoleのデータから「需要はあるのに記事が存在しないキーワード」を抽出します。
すでに検索されているのに攻略できていないテーマが見つかります。
全サイトを一括比較する
「全サイトの先月のアクセスを比較して、最も改善が必要なサイトを教えて」
複数サイトのデータを横断的に取得し、セッション数・直帰率・PV数などを比較したうえで、優先的に手を入れるべきサイトを提案します。
月次レポートを自動生成する
「mysite1の先月の総括レポートを作成して。数字の変化と改善アクション案も含めて」
毎月の定例作業をClaudeに任せることができます。
よくある質問
まとめ
本記事では、ClaudeにGA4とSearch Consoleを直接つなぐMCPサーバーの構築方法を解説しました。
できるようになること
- チャットで話しかけるだけでリアルタイムにデータ取得・分析
- リライト候補と新規記事アイデアをAIが自動抽出
- 複数サイトを一括で比較・管理
手順の振り返り
STEP1:Google Cloudでサービスアカウントを作成し権限を付与
STEP2:Pythonでサーバーを構築しsites_config.jsonにサイトを登録
STEP3:MCP Inspectorで動作確認
STEP4:Claude Desktopに拡張機能としてインストール
まずは手持ちの1サイトで試してみてください。
最初のデータ取得に成功したときの感動は、セットアップの手間を十分に上回るはずです。

コメント・ご指摘などあればこちらへ!