@yoryoboy/bi-mcp 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +346 -0
- package/bin/bi-mcp.js +2 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/index.js +768 -0
- package/dist/index.js.map +7 -0
- package/dist/mcp-use.json +7 -0
- package/dist/public/favicon.ico +0 -0
- package/dist/public/icon.svg +6 -0
- package/dist/src/analytics/ga4-channel-groups.js +20 -0
- package/dist/src/analytics/ga4-channel-groups.js.map +7 -0
- package/dist/src/analytics/ga4-report-utils.js +117 -0
- package/dist/src/analytics/ga4-report-utils.js.map +7 -0
- package/dist/src/config/benchmarks.js +128 -0
- package/dist/src/config/benchmarks.js.map +7 -0
- package/dist/src/config/google.js +41 -0
- package/dist/src/config/google.js.map +7 -0
- package/dist/src/config/vtex.js +26 -0
- package/dist/src/config/vtex.js.map +7 -0
- package/dist/src/google-ads/report-utils.js +78 -0
- package/dist/src/google-ads/report-utils.js.map +7 -0
- package/dist/src/prompts/reporte-ventas.js +75 -0
- package/dist/src/prompts/reporte-ventas.js.map +7 -0
- package/dist/src/search-console/search-console-utils.js +275 -0
- package/dist/src/search-console/search-console-utils.js.map +7 -0
- package/dist/src/services/analytics/ga4-client.js +69 -0
- package/dist/src/services/analytics/ga4-client.js.map +7 -0
- package/dist/src/services/analytics/oauth.js +30 -0
- package/dist/src/services/analytics/oauth.js.map +7 -0
- package/dist/src/services/google-ads/google-ads-client.js +54 -0
- package/dist/src/services/google-ads/google-ads-client.js.map +7 -0
- package/dist/src/services/search-console/search-console-client.js +45 -0
- package/dist/src/services/search-console/search-console-client.js.map +7 -0
- package/dist/src/services/vtex/vtex-api.js +51 -0
- package/dist/src/services/vtex/vtex-api.js.map +7 -0
- package/dist/src/services/vtex/vtex-catalog.js +18 -0
- package/dist/src/services/vtex/vtex-catalog.js.map +7 -0
- package/dist/src/services/vtex/vtex-logistics.js +151 -0
- package/dist/src/services/vtex/vtex-logistics.js.map +7 -0
- package/dist/src/services/vtex/vtex-orders.js +143 -0
- package/dist/src/services/vtex/vtex-orders.js.map +7 -0
- package/dist/src/services/vtex/vtex-pricing.js +17 -0
- package/dist/src/services/vtex/vtex-pricing.js.map +7 -0
- package/dist/src/tools/analytics/attribution-gaps.js +109 -0
- package/dist/src/tools/analytics/attribution-gaps.js.map +7 -0
- package/dist/src/tools/analytics/channel-mix.js +74 -0
- package/dist/src/tools/analytics/channel-mix.js.map +7 -0
- package/dist/src/tools/analytics/ecommerce-tracking-health.js +89 -0
- package/dist/src/tools/analytics/ecommerce-tracking-health.js.map +7 -0
- package/dist/src/tools/analytics/engagement-overview.js +71 -0
- package/dist/src/tools/analytics/engagement-overview.js.map +7 -0
- package/dist/src/tools/analytics/index.js +12 -0
- package/dist/src/tools/analytics/index.js.map +7 -0
- package/dist/src/tools/analytics/list-accessible-properties.js +46 -0
- package/dist/src/tools/analytics/list-accessible-properties.js.map +7 -0
- package/dist/src/tools/analytics/property-info.js +54 -0
- package/dist/src/tools/analytics/property-info.js.map +7 -0
- package/dist/src/tools/analytics/revenue-by-channel.js +70 -0
- package/dist/src/tools/analytics/revenue-by-channel.js.map +7 -0
- package/dist/src/tools/analytics/revenue-overview.js +77 -0
- package/dist/src/tools/analytics/revenue-overview.js.map +7 -0
- package/dist/src/tools/analytics/revenue-trend.js +69 -0
- package/dist/src/tools/analytics/revenue-trend.js.map +7 -0
- package/dist/src/tools/analytics/source-medium-breakdown.js +86 -0
- package/dist/src/tools/analytics/source-medium-breakdown.js.map +7 -0
- package/dist/src/tools/analytics/top-landing-pages.js +79 -0
- package/dist/src/tools/analytics/top-landing-pages.js.map +7 -0
- package/dist/src/tools/google-ads/account-overview.js +103 -0
- package/dist/src/tools/google-ads/account-overview.js.map +7 -0
- package/dist/src/tools/google-ads/account-risks.js +267 -0
- package/dist/src/tools/google-ads/account-risks.js.map +7 -0
- package/dist/src/tools/google-ads/break-even-analysis.js +107 -0
- package/dist/src/tools/google-ads/break-even-analysis.js.map +7 -0
- package/dist/src/tools/google-ads/campaign-performance.js +157 -0
- package/dist/src/tools/google-ads/campaign-performance.js.map +7 -0
- package/dist/src/tools/google-ads/channel-mix.js +129 -0
- package/dist/src/tools/google-ads/channel-mix.js.map +7 -0
- package/dist/src/tools/google-ads/compare-accounts.js +122 -0
- package/dist/src/tools/google-ads/compare-accounts.js.map +7 -0
- package/dist/src/tools/google-ads/customer-clients.js +77 -0
- package/dist/src/tools/google-ads/customer-clients.js.map +7 -0
- package/dist/src/tools/google-ads/customer-info.js +64 -0
- package/dist/src/tools/google-ads/customer-info.js.map +7 -0
- package/dist/src/tools/google-ads/index.js +12 -0
- package/dist/src/tools/google-ads/index.js.map +7 -0
- package/dist/src/tools/google-ads/scaling-health.js +174 -0
- package/dist/src/tools/google-ads/scaling-health.js.map +7 -0
- package/dist/src/tools/google-ads/search-terms-summary.js +131 -0
- package/dist/src/tools/google-ads/search-terms-summary.js.map +7 -0
- package/dist/src/tools/google-ads/time-series.js +126 -0
- package/dist/src/tools/google-ads/time-series.js.map +7 -0
- package/dist/src/tools/index.js +5 -0
- package/dist/src/tools/index.js.map +7 -0
- package/dist/src/tools/search-console/country-breakdown.js +85 -0
- package/dist/src/tools/search-console/country-breakdown.js.map +7 -0
- package/dist/src/tools/search-console/device-breakdown.js +85 -0
- package/dist/src/tools/search-console/device-breakdown.js.map +7 -0
- package/dist/src/tools/search-console/high-impression-low-click-queries.js +95 -0
- package/dist/src/tools/search-console/high-impression-low-click-queries.js.map +7 -0
- package/dist/src/tools/search-console/index.js +15 -0
- package/dist/src/tools/search-console/index.js.map +7 -0
- package/dist/src/tools/search-console/list-accessible-sites.js +42 -0
- package/dist/src/tools/search-console/list-accessible-sites.js.map +7 -0
- package/dist/src/tools/search-console/low-ctr-opportunities.js +98 -0
- package/dist/src/tools/search-console/low-ctr-opportunities.js.map +7 -0
- package/dist/src/tools/search-console/page-performance.js +104 -0
- package/dist/src/tools/search-console/page-performance.js.map +7 -0
- package/dist/src/tools/search-console/product-demand-low-capture-queries.js +93 -0
- package/dist/src/tools/search-console/product-demand-low-capture-queries.js.map +7 -0
- package/dist/src/tools/search-console/query-page-matrix.js +99 -0
- package/dist/src/tools/search-console/query-page-matrix.js.map +7 -0
- package/dist/src/tools/search-console/query-performance.js +109 -0
- package/dist/src/tools/search-console/query-performance.js.map +7 -0
- package/dist/src/tools/search-console/quick-win-opportunities.js +93 -0
- package/dist/src/tools/search-console/quick-win-opportunities.js.map +7 -0
- package/dist/src/tools/search-console/rising-non-brand-queries.js +121 -0
- package/dist/src/tools/search-console/rising-non-brand-queries.js.map +7 -0
- package/dist/src/tools/search-console/search-performance.js +89 -0
- package/dist/src/tools/search-console/search-performance.js.map +7 -0
- package/dist/src/tools/search-console/site-context.js +43 -0
- package/dist/src/tools/search-console/site-context.js.map +7 -0
- package/dist/src/tools/search-console/visibility-declines.js +146 -0
- package/dist/src/tools/search-console/visibility-declines.js.map +7 -0
- package/dist/src/tools/vtex/computed-price.js +48 -0
- package/dist/src/tools/vtex/computed-price.js.map +7 -0
- package/dist/src/tools/vtex/index.js +11 -0
- package/dist/src/tools/vtex/index.js.map +7 -0
- package/dist/src/tools/vtex/inventory-check.js +148 -0
- package/dist/src/tools/vtex/inventory-check.js.map +7 -0
- package/dist/src/tools/vtex/order-details.js +56 -0
- package/dist/src/tools/vtex/order-details.js.map +7 -0
- package/dist/src/tools/vtex/orders-summary.js +83 -0
- package/dist/src/tools/vtex/orders-summary.js.map +7 -0
- package/dist/src/tools/vtex/product-offers.js +28 -0
- package/dist/src/tools/vtex/product-offers.js.map +7 -0
- package/dist/src/tools/vtex/sku-offers.js +30 -0
- package/dist/src/tools/vtex/sku-offers.js.map +7 -0
- package/dist/src/tools/vtex/sku-price.js +42 -0
- package/dist/src/tools/vtex/sku-price.js.map +7 -0
- package/dist/src/tools/vtex/update-inventory.js +43 -0
- package/dist/src/tools/vtex/update-inventory.js.map +7 -0
- package/dist/src/tools/vtex/update-lead-time.js +32 -0
- package/dist/src/tools/vtex/update-lead-time.js.map +7 -0
- package/dist/src/tools/vtex/warehouse-inventory.js +42 -0
- package/dist/src/tools/vtex/warehouse-inventory.js.map +7 -0
- package/dist/src/utils/case-conversion.js +21 -0
- package/dist/src/utils/case-conversion.js.map +7 -0
- package/dist/src/utils/currency.js +52 -0
- package/dist/src/utils/currency.js.map +7 -0
- package/dist/src/utils/format-order-details.js +137 -0
- package/dist/src/utils/format-order-details.js.map +7 -0
- package/dist/src/utils/google-ads.js +78 -0
- package/dist/src/utils/google-ads.js.map +7 -0
- package/dist/src/utils/money.js +83 -0
- package/dist/src/utils/money.js.map +7 -0
- package/dist/src/utils/order-status.js +11 -0
- package/dist/src/utils/order-status.js.map +7 -0
- package/dist/src/utils/pagination.js +45 -0
- package/dist/src/utils/pagination.js.map +7 -0
- package/dist/src/utils/strip-payload.js +40 -0
- package/dist/src/utils/strip-payload.js.map +7 -0
- package/dist/src/utils/type-guards.js +7 -0
- package/dist/src/utils/type-guards.js.map +7 -0
- package/package.json +66 -0
- package/public/favicon.ico +0 -0
- package/public/icon.svg +6 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/tools/analytics/revenue-overview.ts"],
|
|
4
|
+
"sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport {\n extractQuotaSnapshot,\n getMetricValueByName,\n resolveGa4PropertyId,\n round,\n toPercent,\n} from \"../../analytics/ga4-report-utils.js\";\nimport { runReport } from \"../../services/analytics/ga4-client.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nconst dateRegex = /^\\d{4}-\\d{2}-\\d{2}$/;\n\nexport const revenueOverviewSchema = z.object({\n startDate: z.string().regex(dateRegex).describe(\"Start date in YYYY-MM-DD format\"),\n endDate: z.string().regex(dateRegex).describe(\"End date in YYYY-MM-DD format\"),\n propertyId: z.string().optional().describe(\"GA4 property ID. If omitted, uses GA4_PROPERTY_ID\"),\n});\n\nexport async function revenueOverviewHandler(params: z.infer<typeof revenueOverviewSchema>) {\n try {\n const propertyId = resolveGa4PropertyId(params.propertyId);\n const report = await runReport(propertyId, {\n dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],\n metrics: [\n { name: \"sessions\" },\n { name: \"totalUsers\" },\n { name: \"transactions\" },\n { name: \"purchaseRevenue\" },\n { name: \"averagePurchaseRevenue\" },\n { name: \"totalPurchasers\" },\n { name: \"purchaserRate\" },\n ],\n returnPropertyQuota: true,\n });\n\n const row = report.rows?.[0] ?? {};\n const sessions = getMetricValueByName(row, report.metricHeaders, \"sessions\");\n const totalUsers = getMetricValueByName(row, report.metricHeaders, \"totalUsers\");\n const transactions = getMetricValueByName(row, report.metricHeaders, \"transactions\");\n const purchaseRevenue = getMetricValueByName(row, report.metricHeaders, \"purchaseRevenue\");\n const averagePurchaseRevenue = getMetricValueByName(\n row,\n report.metricHeaders,\n \"averagePurchaseRevenue\"\n );\n const totalPurchasers = getMetricValueByName(row, report.metricHeaders, \"totalPurchasers\");\n const purchaserRate = getMetricValueByName(row, report.metricHeaders, \"purchaserRate\");\n\n return object(\n stripNulls({\n property_id: propertyId,\n date_range: {\n start_date: params.startDate,\n end_date: params.endDate,\n },\n currency_code: report.metadata?.currencyCode,\n overview: {\n sessions,\n total_users: totalUsers,\n transactions,\n total_purchasers: totalPurchasers,\n purchase_revenue: round(purchaseRevenue),\n average_purchase_revenue: round(averagePurchaseRevenue),\n purchaser_rate_percent: round(purchaserRate * 100),\n transactions_per_session_percent: round(toPercent(transactions, sessions)),\n transactions_per_user_percent: round(toPercent(transactions, totalUsers)),\n revenue_per_session: round(sessions > 0 ? purchaseRevenue / sessions : 0),\n },\n quota: extractQuotaSnapshot(report),\n })\n );\n } catch (err) {\n return error(err instanceof Error ? err.message : \"Failed to fetch GA4 revenue overview\");\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,iBAAiB;AAC1B,SAAS,kBAAkB;AAE3B,MAAM,YAAY;AAEX,MAAM,wBAAwB,EAAE,OAAO;AAAA,EAC5C,WAAW,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,iCAAiC;AAAA,EACjF,SAAS,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,+BAA+B;AAAA,EAC7E,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,mDAAmD;AAChG,CAAC;AAED,eAAsB,uBAAuB,QAA+C;AAC1F,MAAI;AACF,UAAM,aAAa,qBAAqB,OAAO,UAAU;AACzD,UAAM,SAAS,MAAM,UAAU,YAAY;AAAA,MACzC,YAAY,CAAC,EAAE,WAAW,OAAO,WAAW,SAAS,OAAO,QAAQ,CAAC;AAAA,MACrE,SAAS;AAAA,QACP,EAAE,MAAM,WAAW;AAAA,QACnB,EAAE,MAAM,aAAa;AAAA,QACrB,EAAE,MAAM,eAAe;AAAA,QACvB,EAAE,MAAM,kBAAkB;AAAA,QAC1B,EAAE,MAAM,yBAAyB;AAAA,QACjC,EAAE,MAAM,kBAAkB;AAAA,QAC1B,EAAE,MAAM,gBAAgB;AAAA,MAC1B;AAAA,MACA,qBAAqB;AAAA,IACvB,CAAC;AAED,UAAM,MAAM,OAAO,OAAO,CAAC,KAAK,CAAC;AACjC,UAAM,WAAW,qBAAqB,KAAK,OAAO,eAAe,UAAU;AAC3E,UAAM,aAAa,qBAAqB,KAAK,OAAO,eAAe,YAAY;AAC/E,UAAM,eAAe,qBAAqB,KAAK,OAAO,eAAe,cAAc;AACnF,UAAM,kBAAkB,qBAAqB,KAAK,OAAO,eAAe,iBAAiB;AACzF,UAAM,yBAAyB;AAAA,MAC7B;AAAA,MACA,OAAO;AAAA,MACP;AAAA,IACF;AACA,UAAM,kBAAkB,qBAAqB,KAAK,OAAO,eAAe,iBAAiB;AACzF,UAAM,gBAAgB,qBAAqB,KAAK,OAAO,eAAe,eAAe;AAErF,WAAO;AAAA,MACL,WAAW;AAAA,QACT,aAAa;AAAA,QACb,YAAY;AAAA,UACV,YAAY,OAAO;AAAA,UACnB,UAAU,OAAO;AAAA,QACnB;AAAA,QACA,eAAe,OAAO,UAAU;AAAA,QAChC,UAAU;AAAA,UACR;AAAA,UACA,aAAa;AAAA,UACb;AAAA,UACA,kBAAkB;AAAA,UAClB,kBAAkB,MAAM,eAAe;AAAA,UACvC,0BAA0B,MAAM,sBAAsB;AAAA,UACtD,wBAAwB,MAAM,gBAAgB,GAAG;AAAA,UACjD,kCAAkC,MAAM,UAAU,cAAc,QAAQ,CAAC;AAAA,UACzE,+BAA+B,MAAM,UAAU,cAAc,UAAU,CAAC;AAAA,UACxE,qBAAqB,MAAM,WAAW,IAAI,kBAAkB,WAAW,CAAC;AAAA,QAC1E;AAAA,QACA,OAAO,qBAAqB,MAAM;AAAA,MACpC,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,MAAM,eAAe,QAAQ,IAAI,UAAU,sCAAsC;AAAA,EAC1F;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { error, object } from "mcp-use/server";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import {
|
|
4
|
+
extractQuotaSnapshot,
|
|
5
|
+
formatGa4Date,
|
|
6
|
+
getDimensionValue,
|
|
7
|
+
getMetricValueByName,
|
|
8
|
+
resolveGa4PropertyId,
|
|
9
|
+
round
|
|
10
|
+
} from "../../analytics/ga4-report-utils.js";
|
|
11
|
+
import { runReport } from "../../services/analytics/ga4-client.js";
|
|
12
|
+
import { stripNulls } from "../../utils/strip-payload.js";
|
|
13
|
+
const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
|
|
14
|
+
const revenueTrendSchema = z.object({
|
|
15
|
+
startDate: z.string().regex(dateRegex).describe("Start date in YYYY-MM-DD format"),
|
|
16
|
+
endDate: z.string().regex(dateRegex).describe("End date in YYYY-MM-DD format"),
|
|
17
|
+
propertyId: z.string().optional().describe("GA4 property ID. If omitted, uses GA4_PROPERTY_ID")
|
|
18
|
+
});
|
|
19
|
+
async function revenueTrendHandler(params) {
|
|
20
|
+
try {
|
|
21
|
+
const propertyId = resolveGa4PropertyId(params.propertyId);
|
|
22
|
+
const report = await runReport(propertyId, {
|
|
23
|
+
dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],
|
|
24
|
+
dimensions: [{ name: "date" }],
|
|
25
|
+
metrics: [{ name: "transactions" }, { name: "purchaseRevenue" }],
|
|
26
|
+
orderBys: [{ dimension: { dimensionName: "date" } }],
|
|
27
|
+
returnPropertyQuota: true
|
|
28
|
+
});
|
|
29
|
+
const daily = (report.rows ?? []).map((row) => ({
|
|
30
|
+
date: formatGa4Date(getDimensionValue(row)),
|
|
31
|
+
transactions: getMetricValueByName(row, report.metricHeaders, "transactions"),
|
|
32
|
+
purchase_revenue: round(getMetricValueByName(row, report.metricHeaders, "purchaseRevenue"))
|
|
33
|
+
}));
|
|
34
|
+
const totalRevenue = daily.reduce((total, day) => total + day.purchase_revenue, 0);
|
|
35
|
+
const totalTransactions = daily.reduce((total, day) => total + day.transactions, 0);
|
|
36
|
+
const topRevenueDay = daily.reduce((currentTop, day) => {
|
|
37
|
+
if (!currentTop || day.purchase_revenue > currentTop.purchase_revenue) {
|
|
38
|
+
return day;
|
|
39
|
+
}
|
|
40
|
+
return currentTop;
|
|
41
|
+
}, void 0);
|
|
42
|
+
return object(
|
|
43
|
+
stripNulls({
|
|
44
|
+
property_id: propertyId,
|
|
45
|
+
date_range: {
|
|
46
|
+
start_date: params.startDate,
|
|
47
|
+
end_date: params.endDate
|
|
48
|
+
},
|
|
49
|
+
currency_code: report.metadata?.currencyCode,
|
|
50
|
+
overview: {
|
|
51
|
+
days: daily.length,
|
|
52
|
+
total_transactions: totalTransactions,
|
|
53
|
+
total_purchase_revenue: round(totalRevenue),
|
|
54
|
+
average_daily_revenue: round(daily.length > 0 ? totalRevenue / daily.length : 0),
|
|
55
|
+
top_revenue_day: topRevenueDay
|
|
56
|
+
},
|
|
57
|
+
daily,
|
|
58
|
+
quota: extractQuotaSnapshot(report)
|
|
59
|
+
})
|
|
60
|
+
);
|
|
61
|
+
} catch (err) {
|
|
62
|
+
return error(err instanceof Error ? err.message : "Failed to fetch GA4 revenue trend");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export {
|
|
66
|
+
revenueTrendHandler,
|
|
67
|
+
revenueTrendSchema
|
|
68
|
+
};
|
|
69
|
+
//# sourceMappingURL=revenue-trend.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/tools/analytics/revenue-trend.ts"],
|
|
4
|
+
"sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport {\n extractQuotaSnapshot,\n formatGa4Date,\n getDimensionValue,\n getMetricValueByName,\n resolveGa4PropertyId,\n round,\n} from \"../../analytics/ga4-report-utils.js\";\nimport { runReport } from \"../../services/analytics/ga4-client.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nconst dateRegex = /^\\d{4}-\\d{2}-\\d{2}$/;\n\nexport const revenueTrendSchema = z.object({\n startDate: z.string().regex(dateRegex).describe(\"Start date in YYYY-MM-DD format\"),\n endDate: z.string().regex(dateRegex).describe(\"End date in YYYY-MM-DD format\"),\n propertyId: z.string().optional().describe(\"GA4 property ID. If omitted, uses GA4_PROPERTY_ID\"),\n});\n\nexport async function revenueTrendHandler(params: z.infer<typeof revenueTrendSchema>) {\n try {\n const propertyId = resolveGa4PropertyId(params.propertyId);\n const report = await runReport(propertyId, {\n dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],\n dimensions: [{ name: \"date\" }],\n metrics: [{ name: \"transactions\" }, { name: \"purchaseRevenue\" }],\n orderBys: [{ dimension: { dimensionName: \"date\" } }],\n returnPropertyQuota: true,\n });\n\n const daily = (report.rows ?? []).map((row) => ({\n date: formatGa4Date(getDimensionValue(row)),\n transactions: getMetricValueByName(row, report.metricHeaders, \"transactions\"),\n purchase_revenue: round(getMetricValueByName(row, report.metricHeaders, \"purchaseRevenue\")),\n }));\n\n const totalRevenue = daily.reduce((total, day) => total + day.purchase_revenue, 0);\n const totalTransactions = daily.reduce((total, day) => total + day.transactions, 0);\n const topRevenueDay = daily.reduce<(typeof daily)[number] | undefined>((currentTop, day) => {\n if (!currentTop || day.purchase_revenue > currentTop.purchase_revenue) {\n return day;\n }\n\n return currentTop;\n }, undefined);\n\n return object(\n stripNulls({\n property_id: propertyId,\n date_range: {\n start_date: params.startDate,\n end_date: params.endDate,\n },\n currency_code: report.metadata?.currencyCode,\n overview: {\n days: daily.length,\n total_transactions: totalTransactions,\n total_purchase_revenue: round(totalRevenue),\n average_daily_revenue: round(daily.length > 0 ? totalRevenue / daily.length : 0),\n top_revenue_day: topRevenueDay,\n },\n daily,\n quota: extractQuotaSnapshot(report),\n })\n );\n } catch (err) {\n return error(err instanceof Error ? err.message : \"Failed to fetch GA4 revenue trend\");\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,iBAAiB;AAC1B,SAAS,kBAAkB;AAE3B,MAAM,YAAY;AAEX,MAAM,qBAAqB,EAAE,OAAO;AAAA,EACzC,WAAW,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,iCAAiC;AAAA,EACjF,SAAS,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,+BAA+B;AAAA,EAC7E,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,mDAAmD;AAChG,CAAC;AAED,eAAsB,oBAAoB,QAA4C;AACpF,MAAI;AACF,UAAM,aAAa,qBAAqB,OAAO,UAAU;AACzD,UAAM,SAAS,MAAM,UAAU,YAAY;AAAA,MACzC,YAAY,CAAC,EAAE,WAAW,OAAO,WAAW,SAAS,OAAO,QAAQ,CAAC;AAAA,MACrE,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC;AAAA,MAC7B,SAAS,CAAC,EAAE,MAAM,eAAe,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAAA,MAC/D,UAAU,CAAC,EAAE,WAAW,EAAE,eAAe,OAAO,EAAE,CAAC;AAAA,MACnD,qBAAqB;AAAA,IACvB,CAAC;AAED,UAAM,SAAS,OAAO,QAAQ,CAAC,GAAG,IAAI,CAAC,SAAS;AAAA,MAC9C,MAAM,cAAc,kBAAkB,GAAG,CAAC;AAAA,MAC1C,cAAc,qBAAqB,KAAK,OAAO,eAAe,cAAc;AAAA,MAC5E,kBAAkB,MAAM,qBAAqB,KAAK,OAAO,eAAe,iBAAiB,CAAC;AAAA,IAC5F,EAAE;AAEF,UAAM,eAAe,MAAM,OAAO,CAAC,OAAO,QAAQ,QAAQ,IAAI,kBAAkB,CAAC;AACjF,UAAM,oBAAoB,MAAM,OAAO,CAAC,OAAO,QAAQ,QAAQ,IAAI,cAAc,CAAC;AAClF,UAAM,gBAAgB,MAAM,OAA2C,CAAC,YAAY,QAAQ;AAC1F,UAAI,CAAC,cAAc,IAAI,mBAAmB,WAAW,kBAAkB;AACrE,eAAO;AAAA,MACT;AAEA,aAAO;AAAA,IACT,GAAG,MAAS;AAEZ,WAAO;AAAA,MACL,WAAW;AAAA,QACT,aAAa;AAAA,QACb,YAAY;AAAA,UACV,YAAY,OAAO;AAAA,UACnB,UAAU,OAAO;AAAA,QACnB;AAAA,QACA,eAAe,OAAO,UAAU;AAAA,QAChC,UAAU;AAAA,UACR,MAAM,MAAM;AAAA,UACZ,oBAAoB;AAAA,UACpB,wBAAwB,MAAM,YAAY;AAAA,UAC1C,uBAAuB,MAAM,MAAM,SAAS,IAAI,eAAe,MAAM,SAAS,CAAC;AAAA,UAC/E,iBAAiB;AAAA,QACnB;AAAA,QACA;AAAA,QACA,OAAO,qBAAqB,MAAM;AAAA,MACpC,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,MAAM,eAAe,QAAQ,IAAI,UAAU,mCAAmC;AAAA,EACvF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { error, object } from "mcp-use/server";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import {
|
|
4
|
+
extractQuotaSnapshot,
|
|
5
|
+
getDimensionValue,
|
|
6
|
+
getMetricValueByName,
|
|
7
|
+
resolveGa4PropertyId,
|
|
8
|
+
round,
|
|
9
|
+
toPercent
|
|
10
|
+
} from "../../analytics/ga4-report-utils.js";
|
|
11
|
+
import { runReport } from "../../services/analytics/ga4-client.js";
|
|
12
|
+
import { stripNulls } from "../../utils/strip-payload.js";
|
|
13
|
+
const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
|
|
14
|
+
const sourceMediumBreakdownSchema = z.object({
|
|
15
|
+
startDate: z.string().regex(dateRegex).describe("Start date in YYYY-MM-DD format"),
|
|
16
|
+
endDate: z.string().regex(dateRegex).describe("End date in YYYY-MM-DD format"),
|
|
17
|
+
propertyId: z.string().optional().describe("GA4 property ID. If omitted, uses GA4_PROPERTY_ID"),
|
|
18
|
+
limit: z.number().int().min(1).max(100).optional().describe("Maximum rows to return")
|
|
19
|
+
});
|
|
20
|
+
async function sourceMediumBreakdownHandler(params) {
|
|
21
|
+
try {
|
|
22
|
+
const propertyId = resolveGa4PropertyId(params.propertyId);
|
|
23
|
+
const limit = params.limit ?? 20;
|
|
24
|
+
const [breakdownReport, totalReport] = await Promise.all([
|
|
25
|
+
runReport(propertyId, {
|
|
26
|
+
dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],
|
|
27
|
+
dimensions: [{ name: "sessionSourceMedium" }],
|
|
28
|
+
metrics: [{ name: "sessions" }, { name: "totalUsers" }],
|
|
29
|
+
orderBys: [{ metric: { metricName: "sessions" }, desc: true }],
|
|
30
|
+
limit,
|
|
31
|
+
returnPropertyQuota: true
|
|
32
|
+
}),
|
|
33
|
+
runReport(propertyId, {
|
|
34
|
+
dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],
|
|
35
|
+
metrics: [{ name: "sessions" }, { name: "totalUsers" }]
|
|
36
|
+
})
|
|
37
|
+
]);
|
|
38
|
+
const totalSessions = getMetricValueByName(
|
|
39
|
+
totalReport.rows?.[0] ?? {},
|
|
40
|
+
totalReport.metricHeaders,
|
|
41
|
+
"sessions"
|
|
42
|
+
);
|
|
43
|
+
const totalUsers = getMetricValueByName(
|
|
44
|
+
totalReport.rows?.[0] ?? {},
|
|
45
|
+
totalReport.metricHeaders,
|
|
46
|
+
"totalUsers"
|
|
47
|
+
);
|
|
48
|
+
const rows = (breakdownReport.rows ?? []).map((row) => {
|
|
49
|
+
const sessions = getMetricValueByName(row, breakdownReport.metricHeaders, "sessions");
|
|
50
|
+
const users = getMetricValueByName(row, breakdownReport.metricHeaders, "totalUsers");
|
|
51
|
+
return {
|
|
52
|
+
source_medium: getDimensionValue(row),
|
|
53
|
+
sessions,
|
|
54
|
+
users,
|
|
55
|
+
session_share_percent: round(toPercent(sessions, totalSessions)),
|
|
56
|
+
user_share_percent: round(toPercent(users, totalUsers))
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
return object(
|
|
60
|
+
stripNulls({
|
|
61
|
+
property_id: propertyId,
|
|
62
|
+
date_range: {
|
|
63
|
+
start_date: params.startDate,
|
|
64
|
+
end_date: params.endDate
|
|
65
|
+
},
|
|
66
|
+
overview: {
|
|
67
|
+
total_sessions: totalSessions,
|
|
68
|
+
total_users: totalUsers,
|
|
69
|
+
returned_rows: rows.length,
|
|
70
|
+
available_rows: breakdownReport.rowCount
|
|
71
|
+
},
|
|
72
|
+
source_mediums: rows,
|
|
73
|
+
quota: extractQuotaSnapshot(breakdownReport)
|
|
74
|
+
})
|
|
75
|
+
);
|
|
76
|
+
} catch (err) {
|
|
77
|
+
return error(
|
|
78
|
+
err instanceof Error ? err.message : "Failed to fetch GA4 source / medium breakdown"
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
export {
|
|
83
|
+
sourceMediumBreakdownHandler,
|
|
84
|
+
sourceMediumBreakdownSchema
|
|
85
|
+
};
|
|
86
|
+
//# sourceMappingURL=source-medium-breakdown.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/tools/analytics/source-medium-breakdown.ts"],
|
|
4
|
+
"sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport {\n extractQuotaSnapshot,\n getDimensionValue,\n getMetricValueByName,\n resolveGa4PropertyId,\n round,\n toPercent,\n} from \"../../analytics/ga4-report-utils.js\";\nimport { runReport } from \"../../services/analytics/ga4-client.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nconst dateRegex = /^\\d{4}-\\d{2}-\\d{2}$/;\n\nexport const sourceMediumBreakdownSchema = z.object({\n startDate: z.string().regex(dateRegex).describe(\"Start date in YYYY-MM-DD format\"),\n endDate: z.string().regex(dateRegex).describe(\"End date in YYYY-MM-DD format\"),\n propertyId: z.string().optional().describe(\"GA4 property ID. If omitted, uses GA4_PROPERTY_ID\"),\n limit: z.number().int().min(1).max(100).optional().describe(\"Maximum rows to return\"),\n});\n\nexport async function sourceMediumBreakdownHandler(\n params: z.infer<typeof sourceMediumBreakdownSchema>\n) {\n try {\n const propertyId = resolveGa4PropertyId(params.propertyId);\n const limit = params.limit ?? 20;\n\n const [breakdownReport, totalReport] = await Promise.all([\n runReport(propertyId, {\n dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],\n dimensions: [{ name: \"sessionSourceMedium\" }],\n metrics: [{ name: \"sessions\" }, { name: \"totalUsers\" }],\n orderBys: [{ metric: { metricName: \"sessions\" }, desc: true }],\n limit,\n returnPropertyQuota: true,\n }),\n runReport(propertyId, {\n dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],\n metrics: [{ name: \"sessions\" }, { name: \"totalUsers\" }],\n }),\n ]);\n\n const totalSessions = getMetricValueByName(\n totalReport.rows?.[0] ?? {},\n totalReport.metricHeaders,\n \"sessions\"\n );\n const totalUsers = getMetricValueByName(\n totalReport.rows?.[0] ?? {},\n totalReport.metricHeaders,\n \"totalUsers\"\n );\n\n const rows = (breakdownReport.rows ?? []).map((row) => {\n const sessions = getMetricValueByName(row, breakdownReport.metricHeaders, \"sessions\");\n const users = getMetricValueByName(row, breakdownReport.metricHeaders, \"totalUsers\");\n\n return {\n source_medium: getDimensionValue(row),\n sessions,\n users,\n session_share_percent: round(toPercent(sessions, totalSessions)),\n user_share_percent: round(toPercent(users, totalUsers)),\n };\n });\n\n return object(\n stripNulls({\n property_id: propertyId,\n date_range: {\n start_date: params.startDate,\n end_date: params.endDate,\n },\n overview: {\n total_sessions: totalSessions,\n total_users: totalUsers,\n returned_rows: rows.length,\n available_rows: breakdownReport.rowCount,\n },\n source_mediums: rows,\n quota: extractQuotaSnapshot(breakdownReport),\n })\n );\n } catch (err) {\n return error(\n err instanceof Error ? err.message : \"Failed to fetch GA4 source / medium breakdown\"\n );\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,iBAAiB;AAC1B,SAAS,kBAAkB;AAE3B,MAAM,YAAY;AAEX,MAAM,8BAA8B,EAAE,OAAO;AAAA,EAClD,WAAW,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,iCAAiC;AAAA,EACjF,SAAS,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,+BAA+B;AAAA,EAC7E,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,mDAAmD;AAAA,EAC9F,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS,EAAE,SAAS,wBAAwB;AACtF,CAAC;AAED,eAAsB,6BACpB,QACA;AACA,MAAI;AACF,UAAM,aAAa,qBAAqB,OAAO,UAAU;AACzD,UAAM,QAAQ,OAAO,SAAS;AAE9B,UAAM,CAAC,iBAAiB,WAAW,IAAI,MAAM,QAAQ,IAAI;AAAA,MACvD,UAAU,YAAY;AAAA,QACpB,YAAY,CAAC,EAAE,WAAW,OAAO,WAAW,SAAS,OAAO,QAAQ,CAAC;AAAA,QACrE,YAAY,CAAC,EAAE,MAAM,sBAAsB,CAAC;AAAA,QAC5C,SAAS,CAAC,EAAE,MAAM,WAAW,GAAG,EAAE,MAAM,aAAa,CAAC;AAAA,QACtD,UAAU,CAAC,EAAE,QAAQ,EAAE,YAAY,WAAW,GAAG,MAAM,KAAK,CAAC;AAAA,QAC7D;AAAA,QACA,qBAAqB;AAAA,MACvB,CAAC;AAAA,MACD,UAAU,YAAY;AAAA,QACpB,YAAY,CAAC,EAAE,WAAW,OAAO,WAAW,SAAS,OAAO,QAAQ,CAAC;AAAA,QACrE,SAAS,CAAC,EAAE,MAAM,WAAW,GAAG,EAAE,MAAM,aAAa,CAAC;AAAA,MACxD,CAAC;AAAA,IACH,CAAC;AAED,UAAM,gBAAgB;AAAA,MACpB,YAAY,OAAO,CAAC,KAAK,CAAC;AAAA,MAC1B,YAAY;AAAA,MACZ;AAAA,IACF;AACA,UAAM,aAAa;AAAA,MACjB,YAAY,OAAO,CAAC,KAAK,CAAC;AAAA,MAC1B,YAAY;AAAA,MACZ;AAAA,IACF;AAEA,UAAM,QAAQ,gBAAgB,QAAQ,CAAC,GAAG,IAAI,CAAC,QAAQ;AACrD,YAAM,WAAW,qBAAqB,KAAK,gBAAgB,eAAe,UAAU;AACpF,YAAM,QAAQ,qBAAqB,KAAK,gBAAgB,eAAe,YAAY;AAEnF,aAAO;AAAA,QACL,eAAe,kBAAkB,GAAG;AAAA,QACpC;AAAA,QACA;AAAA,QACA,uBAAuB,MAAM,UAAU,UAAU,aAAa,CAAC;AAAA,QAC/D,oBAAoB,MAAM,UAAU,OAAO,UAAU,CAAC;AAAA,MACxD;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,WAAW;AAAA,QACT,aAAa;AAAA,QACb,YAAY;AAAA,UACV,YAAY,OAAO;AAAA,UACnB,UAAU,OAAO;AAAA,QACnB;AAAA,QACA,UAAU;AAAA,UACR,gBAAgB;AAAA,UAChB,aAAa;AAAA,UACb,eAAe,KAAK;AAAA,UACpB,gBAAgB,gBAAgB;AAAA,QAClC;AAAA,QACA,gBAAgB;AAAA,QAChB,OAAO,qBAAqB,eAAe;AAAA,MAC7C,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO;AAAA,MACL,eAAe,QAAQ,IAAI,UAAU;AAAA,IACvC;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { error, object } from "mcp-use/server";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import {
|
|
4
|
+
extractQuotaSnapshot,
|
|
5
|
+
getDimensionValue,
|
|
6
|
+
getMetricValueByName,
|
|
7
|
+
resolveGa4PropertyId,
|
|
8
|
+
round,
|
|
9
|
+
toPercent
|
|
10
|
+
} from "../../analytics/ga4-report-utils.js";
|
|
11
|
+
import { runReport } from "../../services/analytics/ga4-client.js";
|
|
12
|
+
import { stripNulls } from "../../utils/strip-payload.js";
|
|
13
|
+
const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
|
|
14
|
+
const topLandingPagesSchema = z.object({
|
|
15
|
+
startDate: z.string().regex(dateRegex).describe("Start date in YYYY-MM-DD format"),
|
|
16
|
+
endDate: z.string().regex(dateRegex).describe("End date in YYYY-MM-DD format"),
|
|
17
|
+
propertyId: z.string().optional().describe("GA4 property ID. If omitted, uses GA4_PROPERTY_ID"),
|
|
18
|
+
limit: z.number().int().min(1).max(100).optional().describe("Maximum rows to return")
|
|
19
|
+
});
|
|
20
|
+
async function topLandingPagesHandler(params) {
|
|
21
|
+
try {
|
|
22
|
+
const propertyId = resolveGa4PropertyId(params.propertyId);
|
|
23
|
+
const limit = params.limit ?? 20;
|
|
24
|
+
const [landingReport, totalReport] = await Promise.all([
|
|
25
|
+
runReport(propertyId, {
|
|
26
|
+
dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],
|
|
27
|
+
dimensions: [{ name: "landingPage" }],
|
|
28
|
+
metrics: [{ name: "sessions" }, { name: "totalUsers" }],
|
|
29
|
+
orderBys: [{ metric: { metricName: "sessions" }, desc: true }],
|
|
30
|
+
limit,
|
|
31
|
+
returnPropertyQuota: true
|
|
32
|
+
}),
|
|
33
|
+
runReport(propertyId, {
|
|
34
|
+
dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],
|
|
35
|
+
metrics: [{ name: "sessions" }, { name: "totalUsers" }]
|
|
36
|
+
})
|
|
37
|
+
]);
|
|
38
|
+
const totalSessions = getMetricValueByName(
|
|
39
|
+
totalReport.rows?.[0] ?? {},
|
|
40
|
+
totalReport.metricHeaders,
|
|
41
|
+
"sessions"
|
|
42
|
+
);
|
|
43
|
+
const landingPages = (landingReport.rows ?? []).map((row) => {
|
|
44
|
+
const sessions = getMetricValueByName(row, landingReport.metricHeaders, "sessions");
|
|
45
|
+
const users = getMetricValueByName(row, landingReport.metricHeaders, "totalUsers");
|
|
46
|
+
return {
|
|
47
|
+
landing_page: getDimensionValue(row),
|
|
48
|
+
sessions,
|
|
49
|
+
users,
|
|
50
|
+
session_share_percent: round(toPercent(sessions, totalSessions)),
|
|
51
|
+
is_not_set: getDimensionValue(row) === "(not set)"
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
return object(
|
|
55
|
+
stripNulls({
|
|
56
|
+
property_id: propertyId,
|
|
57
|
+
date_range: {
|
|
58
|
+
start_date: params.startDate,
|
|
59
|
+
end_date: params.endDate
|
|
60
|
+
},
|
|
61
|
+
overview: {
|
|
62
|
+
total_sessions: totalSessions,
|
|
63
|
+
returned_rows: landingPages.length,
|
|
64
|
+
available_rows: landingReport.rowCount,
|
|
65
|
+
top_landing_page: landingPages[0]?.landing_page
|
|
66
|
+
},
|
|
67
|
+
landing_pages: landingPages,
|
|
68
|
+
quota: extractQuotaSnapshot(landingReport)
|
|
69
|
+
})
|
|
70
|
+
);
|
|
71
|
+
} catch (err) {
|
|
72
|
+
return error(err instanceof Error ? err.message : "Failed to fetch GA4 top landing pages");
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export {
|
|
76
|
+
topLandingPagesHandler,
|
|
77
|
+
topLandingPagesSchema
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=top-landing-pages.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/tools/analytics/top-landing-pages.ts"],
|
|
4
|
+
"sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport {\n extractQuotaSnapshot,\n getDimensionValue,\n getMetricValueByName,\n resolveGa4PropertyId,\n round,\n toPercent,\n} from \"../../analytics/ga4-report-utils.js\";\nimport { runReport } from \"../../services/analytics/ga4-client.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nconst dateRegex = /^\\d{4}-\\d{2}-\\d{2}$/;\n\nexport const topLandingPagesSchema = z.object({\n startDate: z.string().regex(dateRegex).describe(\"Start date in YYYY-MM-DD format\"),\n endDate: z.string().regex(dateRegex).describe(\"End date in YYYY-MM-DD format\"),\n propertyId: z.string().optional().describe(\"GA4 property ID. If omitted, uses GA4_PROPERTY_ID\"),\n limit: z.number().int().min(1).max(100).optional().describe(\"Maximum rows to return\"),\n});\n\nexport async function topLandingPagesHandler(params: z.infer<typeof topLandingPagesSchema>) {\n try {\n const propertyId = resolveGa4PropertyId(params.propertyId);\n const limit = params.limit ?? 20;\n\n const [landingReport, totalReport] = await Promise.all([\n runReport(propertyId, {\n dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],\n dimensions: [{ name: \"landingPage\" }],\n metrics: [{ name: \"sessions\" }, { name: \"totalUsers\" }],\n orderBys: [{ metric: { metricName: \"sessions\" }, desc: true }],\n limit,\n returnPropertyQuota: true,\n }),\n runReport(propertyId, {\n dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],\n metrics: [{ name: \"sessions\" }, { name: \"totalUsers\" }],\n }),\n ]);\n\n const totalSessions = getMetricValueByName(\n totalReport.rows?.[0] ?? {},\n totalReport.metricHeaders,\n \"sessions\"\n );\n\n const landingPages = (landingReport.rows ?? []).map((row) => {\n const sessions = getMetricValueByName(row, landingReport.metricHeaders, \"sessions\");\n const users = getMetricValueByName(row, landingReport.metricHeaders, \"totalUsers\");\n\n return {\n landing_page: getDimensionValue(row),\n sessions,\n users,\n session_share_percent: round(toPercent(sessions, totalSessions)),\n is_not_set: getDimensionValue(row) === \"(not set)\",\n };\n });\n\n return object(\n stripNulls({\n property_id: propertyId,\n date_range: {\n start_date: params.startDate,\n end_date: params.endDate,\n },\n overview: {\n total_sessions: totalSessions,\n returned_rows: landingPages.length,\n available_rows: landingReport.rowCount,\n top_landing_page: landingPages[0]?.landing_page,\n },\n landing_pages: landingPages,\n quota: extractQuotaSnapshot(landingReport),\n })\n );\n } catch (err) {\n return error(err instanceof Error ? err.message : \"Failed to fetch GA4 top landing pages\");\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,iBAAiB;AAC1B,SAAS,kBAAkB;AAE3B,MAAM,YAAY;AAEX,MAAM,wBAAwB,EAAE,OAAO;AAAA,EAC5C,WAAW,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,iCAAiC;AAAA,EACjF,SAAS,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,+BAA+B;AAAA,EAC7E,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,mDAAmD;AAAA,EAC9F,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS,EAAE,SAAS,wBAAwB;AACtF,CAAC;AAED,eAAsB,uBAAuB,QAA+C;AAC1F,MAAI;AACF,UAAM,aAAa,qBAAqB,OAAO,UAAU;AACzD,UAAM,QAAQ,OAAO,SAAS;AAE9B,UAAM,CAAC,eAAe,WAAW,IAAI,MAAM,QAAQ,IAAI;AAAA,MACrD,UAAU,YAAY;AAAA,QACpB,YAAY,CAAC,EAAE,WAAW,OAAO,WAAW,SAAS,OAAO,QAAQ,CAAC;AAAA,QACrE,YAAY,CAAC,EAAE,MAAM,cAAc,CAAC;AAAA,QACpC,SAAS,CAAC,EAAE,MAAM,WAAW,GAAG,EAAE,MAAM,aAAa,CAAC;AAAA,QACtD,UAAU,CAAC,EAAE,QAAQ,EAAE,YAAY,WAAW,GAAG,MAAM,KAAK,CAAC;AAAA,QAC7D;AAAA,QACA,qBAAqB;AAAA,MACvB,CAAC;AAAA,MACD,UAAU,YAAY;AAAA,QACpB,YAAY,CAAC,EAAE,WAAW,OAAO,WAAW,SAAS,OAAO,QAAQ,CAAC;AAAA,QACrE,SAAS,CAAC,EAAE,MAAM,WAAW,GAAG,EAAE,MAAM,aAAa,CAAC;AAAA,MACxD,CAAC;AAAA,IACH,CAAC;AAED,UAAM,gBAAgB;AAAA,MACpB,YAAY,OAAO,CAAC,KAAK,CAAC;AAAA,MAC1B,YAAY;AAAA,MACZ;AAAA,IACF;AAEA,UAAM,gBAAgB,cAAc,QAAQ,CAAC,GAAG,IAAI,CAAC,QAAQ;AAC3D,YAAM,WAAW,qBAAqB,KAAK,cAAc,eAAe,UAAU;AAClF,YAAM,QAAQ,qBAAqB,KAAK,cAAc,eAAe,YAAY;AAEjF,aAAO;AAAA,QACL,cAAc,kBAAkB,GAAG;AAAA,QACnC;AAAA,QACA;AAAA,QACA,uBAAuB,MAAM,UAAU,UAAU,aAAa,CAAC;AAAA,QAC/D,YAAY,kBAAkB,GAAG,MAAM;AAAA,MACzC;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,WAAW;AAAA,QACT,aAAa;AAAA,QACb,YAAY;AAAA,UACV,YAAY,OAAO;AAAA,UACnB,UAAU,OAAO;AAAA,QACnB;AAAA,QACA,UAAU;AAAA,UACR,gBAAgB;AAAA,UAChB,eAAe,aAAa;AAAA,UAC5B,gBAAgB,cAAc;AAAA,UAC9B,kBAAkB,aAAa,CAAC,GAAG;AAAA,QACrC;AAAA,QACA,eAAe;AAAA,QACf,OAAO,qBAAqB,aAAa;AAAA,MAC3C,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,MAAM,eAAe,QAAQ,IAAI,UAAU,uCAAuC;AAAA,EAC3F;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { error, object } from "mcp-use/server";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import {
|
|
4
|
+
dateRegex,
|
|
5
|
+
getFieldValue,
|
|
6
|
+
microsToCurrency,
|
|
7
|
+
parseGoogleAdsMetricValue,
|
|
8
|
+
resolveGoogleAdsCustomerId,
|
|
9
|
+
resolveGoogleAdsDeveloperToken,
|
|
10
|
+
resolveGoogleAdsLoginCustomerId,
|
|
11
|
+
round,
|
|
12
|
+
toPercent
|
|
13
|
+
} from "../../utils/google-ads.js";
|
|
14
|
+
import { searchGoogleAds } from "../../services/google-ads/google-ads-client.js";
|
|
15
|
+
import { stripNulls } from "../../utils/strip-payload.js";
|
|
16
|
+
const googleAdsAccountOverviewSchema = z.object({
|
|
17
|
+
startDate: z.string().regex(dateRegex).describe("Start date in YYYY-MM-DD format."),
|
|
18
|
+
endDate: z.string().regex(dateRegex).describe("End date in YYYY-MM-DD format."),
|
|
19
|
+
customerId: z.string().describe("Google Ads customer ID to query. Accepts digits with or without hyphens."),
|
|
20
|
+
loginCustomerId: z.string().optional().describe(
|
|
21
|
+
"Optional manager account ID used as login customer. If omitted, uses GOOGLE_ADS_LOGIN_CUSTOMER_ID when configured."
|
|
22
|
+
)
|
|
23
|
+
});
|
|
24
|
+
async function googleAdsAccountOverviewHandler(params) {
|
|
25
|
+
try {
|
|
26
|
+
const customerId = resolveGoogleAdsCustomerId(params.customerId);
|
|
27
|
+
const loginCustomerId = resolveGoogleAdsLoginCustomerId(params.loginCustomerId);
|
|
28
|
+
const developerToken = resolveGoogleAdsDeveloperToken();
|
|
29
|
+
const result = await searchGoogleAds(
|
|
30
|
+
customerId,
|
|
31
|
+
[
|
|
32
|
+
"SELECT",
|
|
33
|
+
"customer.id,",
|
|
34
|
+
"customer.descriptive_name,",
|
|
35
|
+
"customer.currency_code,",
|
|
36
|
+
"customer.time_zone,",
|
|
37
|
+
"metrics.impressions,",
|
|
38
|
+
"metrics.clicks,",
|
|
39
|
+
"metrics.cost_micros,",
|
|
40
|
+
"metrics.conversions,",
|
|
41
|
+
"metrics.conversions_value,",
|
|
42
|
+
"metrics.ctr,",
|
|
43
|
+
"metrics.average_cpc",
|
|
44
|
+
"FROM customer",
|
|
45
|
+
`WHERE segments.date BETWEEN '${params.startDate}' AND '${params.endDate}'`
|
|
46
|
+
].join(" "),
|
|
47
|
+
developerToken,
|
|
48
|
+
loginCustomerId
|
|
49
|
+
);
|
|
50
|
+
const row = result.rows[0] ?? {};
|
|
51
|
+
const impressions = parseGoogleAdsMetricValue(getFieldValue(row, "metrics.impressions"));
|
|
52
|
+
const clicks = parseGoogleAdsMetricValue(getFieldValue(row, "metrics.clicks"));
|
|
53
|
+
const cost = microsToCurrency(getFieldValue(row, "metrics.costMicros"));
|
|
54
|
+
const conversions = round(
|
|
55
|
+
parseGoogleAdsMetricValue(getFieldValue(row, "metrics.conversions"))
|
|
56
|
+
);
|
|
57
|
+
const conversionValue = round(
|
|
58
|
+
parseGoogleAdsMetricValue(getFieldValue(row, "metrics.conversionsValue"))
|
|
59
|
+
);
|
|
60
|
+
const ctrPercent = round(
|
|
61
|
+
parseGoogleAdsMetricValue(getFieldValue(row, "metrics.ctr")) * 100
|
|
62
|
+
);
|
|
63
|
+
const averageCpc = microsToCurrency(getFieldValue(row, "metrics.averageCpc"));
|
|
64
|
+
return object(
|
|
65
|
+
stripNulls({
|
|
66
|
+
customer_id: customerId,
|
|
67
|
+
login_customer_id: loginCustomerId,
|
|
68
|
+
date_range: {
|
|
69
|
+
start_date: params.startDate,
|
|
70
|
+
end_date: params.endDate
|
|
71
|
+
},
|
|
72
|
+
currency_code: getFieldValue(row, "customer.currencyCode"),
|
|
73
|
+
customer_name: getFieldValue(row, "customer.descriptiveName"),
|
|
74
|
+
time_zone: getFieldValue(row, "customer.timeZone"),
|
|
75
|
+
overview: {
|
|
76
|
+
impressions,
|
|
77
|
+
clicks,
|
|
78
|
+
cost,
|
|
79
|
+
conversions,
|
|
80
|
+
conversion_value: conversionValue,
|
|
81
|
+
ctr_percent: ctrPercent,
|
|
82
|
+
average_cpc: averageCpc,
|
|
83
|
+
cpa: round(cost / conversions),
|
|
84
|
+
roas: round(conversionValue / cost),
|
|
85
|
+
conversion_rate_percent: round(toPercent(conversions, clicks))
|
|
86
|
+
},
|
|
87
|
+
metadata: {
|
|
88
|
+
row_count: result.rows.length,
|
|
89
|
+
request_id: result.requestId
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
);
|
|
93
|
+
} catch (err) {
|
|
94
|
+
return error(
|
|
95
|
+
err instanceof Error ? err.message : "Failed to fetch Google Ads account overview"
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
export {
|
|
100
|
+
googleAdsAccountOverviewHandler,
|
|
101
|
+
googleAdsAccountOverviewSchema
|
|
102
|
+
};
|
|
103
|
+
//# sourceMappingURL=account-overview.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/tools/google-ads/account-overview.ts"],
|
|
4
|
+
"sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport {\n dateRegex,\n getFieldValue,\n microsToCurrency,\n parseGoogleAdsMetricValue,\n resolveGoogleAdsCustomerId,\n resolveGoogleAdsDeveloperToken,\n resolveGoogleAdsLoginCustomerId,\n round,\n toPercent,\n} from \"../../utils/google-ads.js\";\nimport { searchGoogleAds } from \"../../services/google-ads/google-ads-client.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const googleAdsAccountOverviewSchema = z.object({\n startDate: z.string().regex(dateRegex).describe(\"Start date in YYYY-MM-DD format.\"),\n endDate: z.string().regex(dateRegex).describe(\"End date in YYYY-MM-DD format.\"),\n customerId: z.string().describe(\"Google Ads customer ID to query. Accepts digits with or without hyphens.\"),\n loginCustomerId: z\n .string()\n .optional()\n .describe(\n \"Optional manager account ID used as login customer. If omitted, uses GOOGLE_ADS_LOGIN_CUSTOMER_ID when configured.\"\n ),\n});\n\nexport async function googleAdsAccountOverviewHandler(\n params: z.infer<typeof googleAdsAccountOverviewSchema>\n) {\n try {\n const customerId = resolveGoogleAdsCustomerId(params.customerId);\n const loginCustomerId = resolveGoogleAdsLoginCustomerId(params.loginCustomerId);\n const developerToken = resolveGoogleAdsDeveloperToken();\n\n const result = await searchGoogleAds(\n customerId,\n [\n \"SELECT\",\n \"customer.id,\",\n \"customer.descriptive_name,\",\n \"customer.currency_code,\",\n \"customer.time_zone,\",\n \"metrics.impressions,\",\n \"metrics.clicks,\",\n \"metrics.cost_micros,\",\n \"metrics.conversions,\",\n \"metrics.conversions_value,\",\n \"metrics.ctr,\",\n \"metrics.average_cpc\",\n \"FROM customer\",\n `WHERE segments.date BETWEEN '${params.startDate}' AND '${params.endDate}'`,\n ].join(\" \"),\n developerToken,\n loginCustomerId\n );\n\n const row = result.rows[0] ?? {};\n const impressions = parseGoogleAdsMetricValue(getFieldValue(row, \"metrics.impressions\"));\n const clicks = parseGoogleAdsMetricValue(getFieldValue(row, \"metrics.clicks\"));\n const cost = microsToCurrency(getFieldValue(row, \"metrics.costMicros\"));\n const conversions = round(\n parseGoogleAdsMetricValue(getFieldValue(row, \"metrics.conversions\"))\n );\n const conversionValue = round(\n parseGoogleAdsMetricValue(getFieldValue(row, \"metrics.conversionsValue\"))\n );\n const ctrPercent = round(\n parseGoogleAdsMetricValue(getFieldValue(row, \"metrics.ctr\")) * 100\n );\n const averageCpc = microsToCurrency(getFieldValue(row, \"metrics.averageCpc\"));\n\n return object(\n stripNulls({\n customer_id: customerId,\n login_customer_id: loginCustomerId,\n date_range: {\n start_date: params.startDate,\n end_date: params.endDate,\n },\n currency_code: getFieldValue(row, \"customer.currencyCode\"),\n customer_name: getFieldValue(row, \"customer.descriptiveName\"),\n time_zone: getFieldValue(row, \"customer.timeZone\"),\n overview: {\n impressions,\n clicks,\n cost,\n conversions,\n conversion_value: conversionValue,\n ctr_percent: ctrPercent,\n average_cpc: averageCpc,\n cpa: round(cost / conversions),\n roas: round(conversionValue / cost),\n conversion_rate_percent: round(toPercent(conversions, clicks)),\n },\n metadata: {\n row_count: result.rows.length,\n request_id: result.requestId,\n },\n })\n );\n } catch (err) {\n return error(\n err instanceof Error ? err.message : \"Failed to fetch Google Ads account overview\"\n );\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,uBAAuB;AAChC,SAAS,kBAAkB;AAEpB,MAAM,iCAAiC,EAAE,OAAO;AAAA,EACrD,WAAW,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,kCAAkC;AAAA,EAClF,SAAS,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,gCAAgC;AAAA,EAC9E,YAAY,EAAE,OAAO,EAAE,SAAS,0EAA0E;AAAA,EAC1G,iBAAiB,EACd,OAAO,EACP,SAAS,EACT;AAAA,IACC;AAAA,EACF;AACJ,CAAC;AAED,eAAsB,gCACpB,QACA;AACA,MAAI;AACF,UAAM,aAAa,2BAA2B,OAAO,UAAU;AAC/D,UAAM,kBAAkB,gCAAgC,OAAO,eAAe;AAC9E,UAAM,iBAAiB,+BAA+B;AAEtD,UAAM,SAAS,MAAM;AAAA,MACnB;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,gCAAgC,OAAO,SAAS,UAAU,OAAO,OAAO;AAAA,MAC1E,EAAE,KAAK,GAAG;AAAA,MACV;AAAA,MACA;AAAA,IACF;AAEA,UAAM,MAAM,OAAO,KAAK,CAAC,KAAK,CAAC;AAC/B,UAAM,cAAc,0BAA0B,cAAc,KAAK,qBAAqB,CAAC;AACvF,UAAM,SAAS,0BAA0B,cAAc,KAAK,gBAAgB,CAAC;AAC7E,UAAM,OAAO,iBAAiB,cAAc,KAAK,oBAAoB,CAAC;AACtE,UAAM,cAAc;AAAA,MAClB,0BAA0B,cAAc,KAAK,qBAAqB,CAAC;AAAA,IACrE;AACA,UAAM,kBAAkB;AAAA,MACtB,0BAA0B,cAAc,KAAK,0BAA0B,CAAC;AAAA,IAC1E;AACA,UAAM,aAAa;AAAA,MACjB,0BAA0B,cAAc,KAAK,aAAa,CAAC,IAAI;AAAA,IACjE;AACA,UAAM,aAAa,iBAAiB,cAAc,KAAK,oBAAoB,CAAC;AAE5E,WAAO;AAAA,MACL,WAAW;AAAA,QACT,aAAa;AAAA,QACb,mBAAmB;AAAA,QACnB,YAAY;AAAA,UACV,YAAY,OAAO;AAAA,UACnB,UAAU,OAAO;AAAA,QACnB;AAAA,QACA,eAAe,cAAc,KAAK,uBAAuB;AAAA,QACzD,eAAe,cAAc,KAAK,0BAA0B;AAAA,QAC5D,WAAW,cAAc,KAAK,mBAAmB;AAAA,QACjD,UAAU;AAAA,UACR;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,kBAAkB;AAAA,UAClB,aAAa;AAAA,UACb,aAAa;AAAA,UACb,KAAK,MAAM,OAAO,WAAW;AAAA,UAC7B,MAAM,MAAM,kBAAkB,IAAI;AAAA,UAClC,yBAAyB,MAAM,UAAU,aAAa,MAAM,CAAC;AAAA,QAC/D;AAAA,QACA,UAAU;AAAA,UACR,WAAW,OAAO,KAAK;AAAA,UACvB,YAAY,OAAO;AAAA,QACrB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO;AAAA,MACL,eAAe,QAAQ,IAAI,UAAU;AAAA,IACvC;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|