Skip to main content
ai22 فبراير 20265 دقائق قراءة

خوادم MCP: جعل Google Analytics مفيدًا حقًا للمطورين

كيف تحول خوادم بروتوكول سياق النموذج (MCP) Google Analytics من لوحة تحكم تسويقية إلى مصدر بيانات سهل الاستخدام للمطورين يمكنك الاستعلام عنه بشكل تفاعلي.

mcpanalyticsai
خوادم MCP: جعل Google Analytics مفيدًا حقًا للمطورين

لطالما كان Google Analytics أداة تسويقية يتحملها المطورون. تقوم بإعداد التتبع، وتكوين الأحداث، ثم تسلمها لشخص يستمتع بالفعل بالنقر عبر لوحات المعلومات. عندما تحتاج إلى بيانات بنفسك — معدلات الارتداد لصفحة معينة، مسارات التحويل لميزة جديدة، المستخدمون النشطون في الوقت الفعلي مقسمين حسب البلد — ينتهي بك الأمر بالنقر عبر خمس قوائم متداخلة، ومكافحة منشئ استعلامات GA4، وتتساءل لماذا يتطلب طرح سؤال جهدًا أكبر من الإجابة عليه.

يغير بروتوكول سياق النموذج (Model Context Protocol) هذا بالكامل. من خلال تغليف واجهة برمجة تطبيقات التقارير الخاصة بـ GA4 في خادم MCP، يمكنك الاستعلام عن بيانات التحليلات الخاصة بك بشكل تفاعلي عبر Claude أو أي مساعد ذكاء اصطناعي متوافق مع MCP. لا توجد لوحات معلومات. لا توجد أدوات إنشاء استعلامات. فقط اسأل عما تريد معرفته.

ما هو MCP ولماذا هو مهم

بروتوكول سياق النموذج (Model Context Protocol) هو معيار مفتوح أنشأته Anthropic يحدد كيفية تفاعل مساعدي الذكاء الاصطناعي مع مصادر البيانات والأدوات الخارجية. فكر فيه كمنفذ USB-C للذكاء الاصطناعي — واجهة عالمية تتيح لأي مساعد متوافق الاتصال بأي مصدر بيانات متوافق دون الحاجة إلى رمز تكامل مخصص لكل اقتران.

قبل MCP، كان ربط مساعد ذكاء اصطناعي ببيانات التحليلات الخاصة بك يعني بناء مسار مخصص: تصدير البيانات إلى CSV، ولصقها في محادثة، على أمل أن تكون نافذة السياق كبيرة بما يكفي. أو بناء تكامل API مخصص، وكتابة قوالب المطالبات، والتعامل مع المصادقة بنفسك. كل مصدر بيانات جديد يتطلب تكاملًا جديدًا.

يوحد MCP هذا في ثلاثة مفاهيم:

  • الموارد (Resources) — بيانات منظمة يكشفها الخادم (خصائص GA4 وتقاريرها وأبعادها ومقاييسها)
  • الأدوات (Tools) — الإجراءات التي يمكن للذكاء الاصطناعي استدعاؤها (تشغيل تقرير، الاستعلام عن بيانات في الوقت الفعلي، سرد المقاييس المتاحة)
  • المطالبات (Prompts) — قوالب مطالبات قابلة لإعادة الاستخدام يوفرها الخادم (استعلامات تحليلات شائعة مهيكلة مسبقًا للحصول على نتائج جيدة)

يتعامل الخادم مع المصادقة، وجلب البيانات، وتنسيق الاستجابة. يتعامل مساعد الذكاء الاصطناعي مع فهم اللغة الطبيعية وتفسير النتائج. لا يحتاج أي من الطرفين إلى معرفة تفاصيل تنفيذ الطرف الآخر.

لماذا هذا مهم للتحليلات على وجه التحديد

منصات التحليلات غنية بالمعلومات ولكنها ضعيفة التفاعل. يحتوي GA4 على بيانات قوية بشكل استثنائي — فهو يتتبع كل جلسة مستخدم، وكل مشاهدة صفحة، وكل حدث، وكل تحويل عبر منتجك بالكامل. ولكن الوصول إلى تلك البيانات يتطلب منك التفكير بمفردات GA4: الأبعاد (dimensions)، والمقاييس (metrics)، والشرائح (segments)، والنطاقات الزمنية (date ranges)، والفلاتر (filters)، والمقارنات (comparisons). يجب عليك ترجمة سؤالك إلى نموذج استعلام GA4 قبل أن تتمكن من الحصول على إجابة.

يعكس خادم MCP هذا. تسأل سؤالك بلغة بسيطة. يقوم الذكاء الاصطناعي بترجمته إلى استدعاءات API الصحيحة، وينفذها، ويفسر النتائج. ينخفض الاحتكاك بين "لدي سؤال" و "لدي إجابة" من دقائق إلى ثوانٍ.

بناء خادم MCP لـ GA4

يتضمن التنفيذ ثلاث طبقات: إطار عمل خادم MCP، وعميل Google Analytics Data API، ومنطق الربط الذي يربط نية اللغة الطبيعية باستدعاءات API.

إعداد المشروع

mkdir ga4-mcp-server
cd ga4-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk @google-analytics/data zod dotenv
npm install -D typescript @types/node

توفر حزمة @modelcontextprotocol/sdk إطار عمل الخادم. @google-analytics/data هي مكتبة العميل الرسمية من Google لـ GA4 Data API (واجهة برمجة تطبيقات التقارير، وليست واجهة برمجة تطبيقات الإدارة). يتعامل zod مع التحقق من صحة المدخلات لمعلمات الأداة.

المصادقة مع Google

تستخدم مصادقة GA4 API حساب خدمة Google Cloud. أنشئ واحدًا في Google Cloud Console، وقم بتنزيل ملف مفتاح JSON، وامنحه حق الوصول "Viewer" (عارض) إلى خاصية GA4 الخاصة بك.

// src/analytics-client.ts
import { BetaAnalyticsDataClient } from "@google-analytics/data";

const analyticsClient = new BetaAnalyticsDataClient({
  keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS,
});

const propertyId = process.env.GA4_PROPERTY_ID;

export async function runReport(
  dimensions: string[],
  metrics: string[],
  startDate: string,
  endDate: string,
  dimensionFilter?: Record<string, string>
) {
  const request: any = {
    property: `properties/${propertyId}`,
    dimensions: dimensions.map((d) => ({ name: d })),
    metrics: metrics.map((m) => ({ name: m })),
    dateRanges: [{ startDate, endDate }],
  };

  if (dimensionFilter) {
    const filterKey = Object.keys(dimensionFilter)[0];
    request.dimensionFilter = {
      filter: {
        fieldName: filterKey,
        stringFilter: {
          value: dimensionFilter[filterKey],
          matchType: "EXACT",
        },
      },
    };
  }

  const [response] = await analyticsClient.runReport(request);
  return formatReportResponse(response);
}

function formatReportResponse(response: any) {
  if (!response.rows || response.rows.length === 0) {
    return { data: [], summary: "No data found for the specified query." };
  }

  const headers = [
    ...(response.dimensionHeaders?.map((h: any) => h.name) ?? []),
    ...(response.metricHeaders?.map((h: any) => h.name) ?? []),
  ];

  const rows = response.rows.map((row: any) => {
    const values = [
      ...(row.dimensionValues?.map((v: any) => v.value) ?? []),
      ...(row.metricValues?.map((v: any) => v.value) ?? []),
    ];
    return Object.fromEntries(headers.map((h, i) => [h, values[i]]));
  });

  return {
    data: rows,
    rowCount: response.rowCount,
    summary: `Returned ${rows.length} rows.`,
  };
}

خادم MCP

// src/server.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { runReport, getRealtimeData, getAvailableMetrics } from "./analytics-client";

const server = new McpServer({
  name: "ga4-analytics",
  version: "1.0.0",
});

// Tool: Run a custom report
server.tool(
  "run_report",
  "Run a Google Analytics 4 report with specified dimensions, metrics, and date range",
  {
    dimensions: z.array(z.string()).describe("GA4 dimensions like 'pagePath', 'country', 'deviceCategory'"),
    metrics: z.array(z.string()).describe("GA4 metrics like 'activeUsers', 'sessions', 'bounceRate'"),
    startDate: z.string().describe("Start date in YYYY-MM-DD format or relative like '7daysAgo'"),
    endDate: z.string().describe("End date in YYYY-MM-DD format or 'today'"),
    filter: z.record(z.string()).optional().describe("Optional dimension filter as key-value pair"),
  },
  async ({ dimensions, metrics, startDate, endDate, filter }) => {
    const result = await runReport(dimensions, metrics, startDate, endDate, filter);
    return {
      content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
    };
  }
);

// Tool: Get real-time active users
server.tool(
  "realtime_users",
  "Get current real-time active users, optionally segmented by a dimension",
  {
    dimension: z.string().optional().describe("Optional dimension to segment by, like 'country' or 'pagePath'"),
  },
  async ({ dimension }) => {
    const result = await getRealtimeData(dimension);
    return {
      content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
    };
  }
);

// Tool: List available metrics and dimensions
server.tool(
  "list_metrics",
  "List all available GA4 metrics and dimensions for the connected property",
  {},
  async () => {
    const result = await getAvailableMetrics();
    return {
      content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
    };
  }
);

// Resource: Property metadata
server.resource(
  "property-info",
  "ga4://property/info",
  async (uri) => ({
    contents: [{
      uri: uri.href,
      mimeType: "application/json",
      text: JSON.stringify({
        propertyId: process.env.GA4_PROPERTY_ID,
        description: "Connected GA4 property for analytics queries",
      }),
    }],
  })
);

async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
}

main().catch(console.error);

يمنح هذا مساعد الذكاء الاصطناعي ثلاث أدوات: تشغيل تقارير عشوائية، والتحقق من البيانات في

DU

Danil Ulmashev

Full Stack Developer

مهتم بالعمل معًا؟