はじめに
本記事では、Claude Code(Anthropic社のCLIツール)をベースに、GA4(Google Analytics 4)とGSC(Google Search Console)のデータを直接操作できるカスタムMCPサーバーを構築し、アクセス解析とSEO対策を開発フローに統合する方法を紹介します。
こんな人が対象です
- AI駆動開発に興味のあるエンジニア
- アクセス解析データを活用した意思決定を行いたい開発のひと
- Claude CodeやMCP(Model Context Protocol)の実践的な活用事例を知りたいひと
前提条件
環境
- Mac M1(Apple Silicon)
- Node.js >= 18
- npm >= 10
- Claude Code Maxプラン(MCPサーバー登録に必要)
インストール済みツール
- TypeScript 5.9.x(
"target": "ES2022"、strict mode) - GA4設置済み(GA4プロパティIDが必要)
- Google Search Console設置済み(サイト所有権確認済み)
主要パッケージバージョン
| パッケージ | バージョン |
|---|---|
@modelcontextprotocol/sdk | ^1.27.1 |
@google-analytics/data | ^5.2.1 |
googleapis | ^171.4.0 |
zod | ^4.3.6 |
typescript | ^5.9.3 |
tsup | ^8.5.1 |
この記事で得られる幸せポイント
- MCPサーバーの設計・実装パターン
- GA4/GSC APIの統合方法
- Claude Codeとの連携による効率的なデータ分析ワークフロー
- TypeScriptによる型安全なMCPサーバー実装
- 自然言語(チャット形式)で複雑なアクセス解析できるようになる
MCPサーバーとは
Model Context Protocolの概要
MCP(Model Context Protocol)は、Anthropic社が策定したAIモデルと外部ツール・データソースを接続するための標準プロトコルです。Claude Codeは、MCPサーバーを通じて様々な外部システムと連携できます。
MCPサーバーの役割
MCPサーバーは以下の役割を担います:
- ツール登録: Claude Codeが使用できる機能(ツール)の定義
- データアクセス: 外部API(GA4、GSCなど)との通信
- 結果整形: API応答をClaude Codeが理解できる形式に変換
MCPサーバーのアーキテクチャ
1┌─────────────────┐2│ Claude Code │ ← ユーザーの自然言語クエリ3└────────┬────────┘4 │ MCP Protocol (stdio)5 ▼6┌─────────────────┐7│ MCP Server │8│ ├ Tool Handler │ ← ツール実行ロジック9│ ├ API Client │ ← GA4/GSC API呼び出し10│ └ Auth Manager │ ← 認証管理11└────────┬────────┘12 │ API Requests13 ▼14┌─────────────────┐15│ GA4 / GSC API │1 collapsed line
16└─────────────────┘GA4 Analyzer MCPサーバーの設計
プロジェクト構成
本記事で紹介するMCPサーバーは、クリーンアーキテクチャを意識した設計になっています。
1src/2├── mcp/ # MCP関連コード3│ ├── server.ts # MCPサーバーエントリポイント4│ ├── config.ts # 設定管理5│ ├── tools/ # ツール定義6│ │ ├── analyze-comparison.ts # 比較分析ツール7│ │ ├── analyze-exploratory.ts # 探索的分析ツール8│ │ ├── check-config.ts # 設定確認ツール9│ │ └── validate-config.ts # 設定検証ツール10│ └── utils/11│ ├── validator.ts # 入力検証(Zod)12│ └── error-handler.ts13├── application/ # アプリケーション層14│ ├── query-orchestrator.ts15│ └── insight-generator.ts6 collapsed lines
16├── infrastructure/ # インフラ層17│ ├── ga4-client.ts # GA4 API クライアント18│ ├── gsc-client.ts # GSC API クライアント19│ └── auth-manager.ts # 認証管理20└── domain/ # ドメイン層21 └── models/ # ドメインモデル設計のポイント
1. レイヤー分離
- MCP層: Claude Codeとのインターフェース
- Application層: ビジネスロジック(分析オーケストレーション)
- Infrastructure層: 外部API通信
- Domain層: ドメインモデルとビジネスルール
2. 型安全性の確保
すべての入力はZodスキーマでバリデーション:
1import { z } from "zod";2
3export const AnalyzeComparisonInputSchema = z.object({4 query: z.string().min(1),5 options: z.object({6 verbose: z.boolean().default(false),7 compareType: z.string().optional(),8 propertyId: z.string().optional(),9 }).default({ verbose: false }),10});11
12export type AnalyzeComparisonInput = z.infer<typeof AnalyzeComparisonInputSchema>;3. エラーハンドリング
統一的なエラー変換機構を実装:
1export function toMCPError(error: Error): MCPResponse<never> {2 return {3 success: false,4 error: {5 code: "INTERNAL_ERROR",6 message: error.message,7 },8 };9}実装の詳細
MCPサーバーの起動処理
1import { startMCPServer } from "../src/mcp/server.js";2
3process.on("uncaughtException", (error) => {4 console.error("[MCP Server] Uncaught exception:", error);5 process.exit(1);6});7
8process.on("unhandledRejection", (reason, promise) => {9 console.error("[MCP Server] Unhandled rejection at:", promise, "reason:", reason);10 process.exit(1);11});12
13startMCPServer().catch((error: unknown) => {14 console.error("[MCP Server] Failed to start:", error);2 collapsed lines
15 process.exit(1);16});MCPサーバー本体
1import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";2import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";3
4export async function startMCPServer(): Promise<void> {5 const server = new McpServer(6 {7 name: "ga4-analyzer",8 version: "0.1.0",9 },10 {11 capabilities: {12 tools: {},13 },14 },32 collapsed lines
15 );16
17 // ツール登録18 const tools = registerTools();19
20 for (const tool of tools) {21 server.registerTool(22 tool.name,23 {24 description: tool.description,25 inputSchema: tool.inputSchema,26 },27 async (args) => {28 const result = await tool.handler(args);29 return {30 content: [31 {32 type: "text",33 text: JSON.stringify(result, null, 2),34 },35 ],36 };37 },38 );39 }40
41 const transport = new StdioServerTransport();42 await server.connect(transport);43
44 console.error(`[MCP Server] ga4-analyzer v0.1.0 started`);45 console.error(`[MCP Server] Registered ${tools.length} tools: ${tools.map(t => t.name).join(", ")}`);46}ツールの実装例:比較分析
1async function handleAnalyzeComparison(2 input: AnalyzeComparisonInput,3): Promise<MCPResponse<IntegratedAnalysisResult>> {4 try {5 // 環境変数から設定を読み込み6 const envConfig = loadConfigFromEnv();7
8 // オーケストレーターを作成9 const orchestrator = new QueryOrchestrator();10
11 // 比較分析を実行12 const result = await orchestrator.execute(input.query, {13 verbose: input.options.verbose,14 compareType: input.options.compareType,23 collapsed lines
15 propertyId: input.options.propertyId || envConfig.ga4PropertyId,16 forceComparisonMode: true,17 });18
19 return {20 success: true,21 data: result,22 };23 } catch (error) {24 return toMCPError(error as Error);25 }26}27
28export function createAnalyzeComparisonTool(29 inputSchema: typeof AnalyzeComparisonInputSchema,30): ToolDefinition<AnalyzeComparisonInput, IntegratedAnalysisResult> {31 return {32 name: "analyze_comparison",33 description: "GA4データの比較分析を実行します。2つの期間を比較し、トラフィックソース、ページ、デバイス、イベント、検索キーワードの5軸で分析します。",34 inputSchema,35 handler: handleAnalyzeComparison,36 };37}Claude Codeとの連携設定
MCPサーバーの登録
Claude CodeにMCPサーバーを登録するには、.claude/plugins/repos/ga4-analyzer/.mcp.jsonを作成します:
1{2 "ga4-analyzer": {3 "command": "node",4 "args": [5 "/Users/username/path/to/ga4-analyzer/dist/mcp-server.js"6 ],7 "env": {8 "GA4_PROPERTY_ID": "318772207",9 "GA4_SERVICE_ACCOUNT_KEY": "/path/to/serviceaccount.json",10 "GA4_ENABLE_GSC": "true",11 "GA4_GSC_SITE_URL": "https://www.example.com",12 "GA4_MAX_RETRIES": "3",13 "GA4_REQUEST_TIMEOUT": "30000",14 "GA4_DATA_LIMIT": "100"15 }2 collapsed lines
16 }17}メタデータファイル
.claude/plugins/repos/ga4-analyzer/.claude-plugin/metadata.json:
1{2 "name": "ga4-analyzer",3 "version": "0.1.0",4 "description": "GA4 + Google Search Console integrated access analysis MCP server",5 "author": "htada",6 "type": "mcp"7}ビルドとデプロイ
1# 依存関係のインストール2npm install3
4# TypeScriptのビルド5npm run build6
7# MCPサーバーのテスト起動8npm run dev:mcp実践的な使用例
1. 前日比アクセス増の要因分析
インプット(Claude Codeへの入力):
13/3のアクセス増の要因を教えてMCPサーバーの動作:
- クエリを解析 → 対象日: 2026-03-03、比較日: 2026-03-02、分析タイプ: increase_factors
- GA4 APIから5軸(参照元・ページ・デバイス・イベント・検索キーワード)のデータを並列取得
- 前日比変化を計算し、有意な変化を特定
アウトプット(Claude Codeへの返却):
1【対象日: 2026-03-03 vs 比較日: 2026-03-02】2
3総アクセス数: 1,200 セッション(前日比 +20.0%、+200 セッション)4
5【主な増加要因】6■ 参照元/メディア7 1. google/organic: +200 セッション(+33.3%)★★★8
9■ ページ10 1. /blog/typescript-tips: +85 セッション(+42.0%)★★★11 2. /blog/astro-setup: +40 セッション(+18.0%)★★12
13【推察】14・Googleオーガニック検索の急増が主因。特定の記事への検索流入が増加した可能性。15・/blog/typescript-tips への流入が突出しており、SNSシェアまたは検索順位上昇が考えられる。2. SEO効果の測定(GSC連携)
インプット:
1過去30日間で検索順位が上昇したページを表示してアウトプット:
1【検索キーワード分析】期間: 2026-02-04 〜 2026-03-042
3■ 検索順位が改善したページ TOP 54 1. /blog/typescript-tips5 クリック数: 320(+85)、表示回数: 4,200(+1,100)6 平均順位: 4.2 → 2.8(+1.4ポジション改善)★★★7
8 2. /blog/astro-setup9 クリック数: 180(+42)、表示回数: 2,800(+600)10 平均順位: 8.5 → 6.1(+2.4ポジション改善)★★11
12 3. /blog/firebase-deploy13 クリック数: 95(+18)、表示回数: 1,500(+200)14 平均順位: 12.3 → 10.8(+1.5ポジション改善)★15
3 collapsed lines
16【推察】17・/blog/typescript-tips は上位表示が安定してきており、CTRも改善傾向。18・技術系コンテンツ全般で評価が上昇中。内部リンク強化が効いている可能性。3. 設定の確認
インプット:
1GA4の設定を確認してアウトプット:
1{2 "success": true,3 "data": {4 "ga4PropertyId": "318772207",5 "enableGSC": true,6 "gscSiteUrl": "https://45395.jp",7 "maxRetries": 3,8 "requestTimeout": 30000,9 "dataLimit": 100,10 "serviceAccountKeyPath": "/path/to/serviceaccount.json",11 "status": {12 "ga4": "connected",13 "gsc": "connected"14 }15 }1 collapsed line
16}確認できる内容:
- GA4 プロパティIDと接続状態
- GSC連携の有効/無効と対象サイトURL
- データ取得上限(
dataLimit) - リトライ設定とタイムアウト値
技術的な工夫とベストプラクティス
1. 認証管理の抽象化
サービスアカウント認証をAuthenticationManagerで一元管理:
1export class AuthenticationManager {2 loadCredentials(config: {3 serviceAccountKeyPath?: string;4 useApplicationDefaultCredentials?: boolean;5 }): GoogleAuth {6 if (config.serviceAccountKeyPath) {7 // サービスアカウントキーファイルから読み込み8 const keyFile = JSON.parse(fs.readFileSync(config.serviceAccountKeyPath, 'utf-8'));9 return new GoogleAuth({10 credentials: keyFile,11 scopes: [12 'https://www.googleapis.com/auth/analytics.readonly',13 'https://www.googleapis.com/auth/webmasters.readonly',14 ],15 });11 collapsed lines
16 } else {17 // Application Default Credentialsを使用18 return new GoogleAuth({19 scopes: [20 'https://www.googleapis.com/auth/analytics.readonly',21 'https://www.googleapis.com/auth/webmasters.readonly',22 ],23 });24 }25 }26}2. リトライ機構の実装
API呼び出しの信頼性を高めるため、自動リトライを実装:
1async function executeWithRetry<T>(2 fn: () => Promise<T>,3 maxRetries: number = 3,4 timeout: number = 30000,5): Promise<T> {6 let lastError: Error;7
8 for (let attempt = 0; attempt < maxRetries; attempt++) {9 try {10 return await Promise.race([11 fn(),12 new Promise<never>((_, reject) =>13 setTimeout(() => reject(new Error('Timeout')), timeout)14 ),15 ]);10 collapsed lines
16 } catch (error) {17 lastError = error as Error;18 if (attempt < maxRetries - 1) {19 await new Promise(resolve => setTimeout(resolve, 1000 * (attempt + 1)));20 }21 }22 }23
24 throw lastError!;25}3. 環境変数による柔軟な設定
MCP経由の環境変数とローカル設定ファイルを適切にマージ:
1export function loadConfigFromEnv(): Partial<Configuration> {2 return {3 ga4PropertyId: process.env.GA4_PROPERTY_ID || '',4 serviceAccountKeyPath: process.env.GA4_SERVICE_ACCOUNT_KEY,5 enableGSC: process.env.GA4_ENABLE_GSC === 'true',6 gscSiteUrl: process.env.GA4_GSC_SITE_URL,7 maxRetries: parseInt(process.env.GA4_MAX_RETRIES || '3', 10),8 requestTimeout: parseInt(process.env.GA4_REQUEST_TIMEOUT || '30000', 10),9 dataLimit: parseInt(process.env.GA4_DATA_LIMIT || '100', 10),10 };11}4. TypeScriptの型安全性
ジェネリクスを活用した型安全なツール定義:
1export interface ToolDefinition<TInput, TOutput> {2 name: string;3 description: string;4 inputSchema: z.ZodSchema<TInput>;5 handler: (input: TInput) => Promise<MCPResponse<TOutput>>;6}7
8export interface MCPResponse<T> {9 success: boolean;10 data?: T;11 error?: {12 code: string;13 message: string;14 };15}パフォーマンスとスケーラビリティ
データキャッシング戦略
頻繁にアクセスされるデータはメモリキャッシュを活用:
1class DataCache {2 private cache: Map<string, { data: any; timestamp: number }> = new Map();3 private ttl: number = 5 * 60 * 1000; // 5分4
5 get(key: string): any | null {6 const entry = this.cache.get(key);7 if (!entry) return null;8
9 if (Date.now() - entry.timestamp > this.ttl) {10 this.cache.delete(key);11 return null;12 }13
14 return entry.data;15 }8 collapsed lines
16
17 set(key: string, data: any): void {18 this.cache.set(key, {19 data,20 timestamp: Date.now(),21 });22 }23}バッチ処理の最適化
複数のAPIリクエストを並列実行:
1async function fetchMultipleDimensions(2 ga4Client: GA4ApiClient,3 dimensions: string[],4 dateRange: DateRange,5): Promise<Map<string, DimensionData>> {6 const results = await Promise.all(7 dimensions.map(dim =>8 ga4Client.runReport({9 dimensions: [{ name: dim }],10 metrics: [{ name: 'activeUsers' }],11 dateRanges: [dateRange],12 })13 )14 );15
2 collapsed lines
16 return new Map(dimensions.map((dim, i) => [dim, results[i]]));17}セキュリティ考慮事項
1. 認証情報の保護
- サービスアカウントキーは環境変数またはセキュアストレージに保存
- キーファイルは
.gitignoreに追加 - 最小権限の原則(ReadOnlyスコープのみ)
2. 入力バリデーション
すべてのユーザー入力をZodスキーマで検証:
1export const QueryInputSchema = z.object({2 query: z.string().min(1).max(500),3 options: z.object({4 dateRange: z.object({5 start: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),6 end: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),7 }).optional(),8 }).optional(),9});3. レート制限
API呼び出しを制限してコスト管理:
1class RateLimiter {2 private requests: number[] = [];3 private limit: number = 10;4 private window: number = 60000; // 1分5
6 async checkLimit(): Promise<void> {7 const now = Date.now();8 this.requests = this.requests.filter(t => now - t < this.window);9
10 if (this.requests.length >= this.limit) {11 const oldestRequest = this.requests[0];12 const waitTime = this.window - (now - oldestRequest);13 await new Promise(resolve => setTimeout(resolve, waitTime));14 }15
3 collapsed lines
16 this.requests.push(now);17 }18}デバッグとトラブルシューティング
ログ出力の最適化
MCPサーバーではstderrを使用してログ出力:
1// stdout: MCPプロトコル通信用2// stderr: デバッグログ用3
4console.error(`[MCP Server] Tool executed: ${toolName}`);5console.error(`[MCP Server] Input: ${JSON.stringify(input)}`);6console.error(`[MCP Server] Result: ${JSON.stringify(result)}`);よくある問題と解決策
問題1: 認証エラー
1Error: Unable to authenticate with GA4 API解決策:
- サービスアカウントキーのパスを確認
- サービスアカウントにGA4プロパティへのアクセス権限があるか確認
- スコープが正しいか確認(
analytics.readonly)
問題2: タイムアウト
1Error: Request timeout after 30000ms解決策:
GA4_REQUEST_TIMEOUT環境変数を増やす- データ取得期間を短縮
GA4_DATA_LIMITを減らす
問題3: MCPサーバーが起動しない
1Error: Cannot find module './dist/mcp-server.js'解決策:
1# ビルドを実行2npm run build3
4# ビルド成果物を確認5ls -la dist/今後の拡張可能性
1. リアルタイム分析
GA4 Realtime APIを統合してリアルタイムトラフィック監視を実現:
1export class RealtimeAnalyzer {2 async getCurrentVisitors(propertyId: string): Promise<number> {3 const response = await ga4Client.runRealtimeReport({4 property: `properties/${propertyId}`,5 metrics: [{ name: 'activeUsers' }],6 });7
8 return response.rows?.[0]?.metricValues?.[0]?.value || 0;9 }10}2. アラート機能
異常検知とSlack通知:
1export class AlertSystem {2 async checkAnomalies(metrics: Metrics): Promise<void> {3 if (metrics.activeUsers < metrics.baseline * 0.5) {4 await this.sendSlackNotification({5 message: 'Traffic dropped by 50%!',6 severity: 'high',7 });8 }9 }10}3. カスタムダッシュボード
分析結果をMarkdownやHTMLで出力:
1export class ReportGenerator {2 generateMarkdownReport(analysis: AnalysisResult): string {3 return `4# アクセス解析レポート5
6## 期間比較7
8| 指標 | 前期 | 今期 | 変化率 |9| ---------- | -------------------------- | ------------------------- | ----------------------- |10| ユーザー数 | ${analysis.previous.users} | ${analysis.current.users} | ${analysis.changeRate}% |11
12## トップページ13
14${analysis.topPages.map((page, i) => `${i + 1}. ${page.path} (${page.views} views)`).join('\n')}15 `;2 collapsed lines
16 }17}主要なポイント
- MCPプロトコル: AIモデルと外部ツールを標準化された方法で接続
- クリーンアーキテクチャ: レイヤー分離による保守性の向上
- 型安全性: TypeScript + Zodによる堅牢な実装
- 実践的な統合: 自然言語でアクセス解析を実行できるワークフロー
AI駆動開発の未来
MCPサーバーを活用することで、従来は手動で行っていたデータ分析やレポート作成を、自然言語でClaude Codeに依頼できるようになります。
- 開発速度の向上: ダッシュボードを開かずにデータ分析
- 意思決定の高速化: 必要な情報を即座に取得
- SEO最適化の自動化: 検索順位の継続的なモニタリング
次のステップ
本記事のコードをベースに、以下のようなカスタマイズが可能です:
- 他の分析ツール(PageSpeed Insight、 BigQuery MCPなど)との統合
- カスタムメトリクスの定義と追跡
- 定期的な自動レポート生成
- A/Bテスト結果の自動分析
MCPサーバーのエコシステムは急速に成長しており、今後さらに多くの統合が可能になるでしょう。