Skip to content

Commit 843251b

Browse files
authored
Merge pull request #517 from decocms/revert-ga-475
Revert "fix(google-analytics): fix input validation and align output schemas with other Google MCPs (#475)"
2 parents 6f3612c + b40c703 commit 843251b

6 files changed

Lines changed: 302 additions & 137 deletions

File tree

google-analytics/server/lib/schemas.ts

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ export const PropertySummarySchema = z.object({
3030
propertyType: z.string().optional(),
3131
/** Parent resource name, e.g. "accounts/123456". */
3232
parent: z.string().optional(),
33-
canEdit: z.boolean().optional(),
3433
});
3534

3635
export const AccountSummarySchema = z.object({
@@ -42,8 +41,10 @@ export const AccountSummarySchema = z.object({
4241
propertySummaries: z.array(PropertySummarySchema).optional(),
4342
});
4443

45-
export const AccountSummariesOutputSchema = z.object({
46-
accountSummaries: z.array(AccountSummarySchema).optional(),
44+
export const AccountSummariesResponseSchema = z.object({
45+
response: z.object({
46+
accountSummaries: z.array(AccountSummarySchema).optional(),
47+
}),
4748
});
4849

4950
// ── Admin API — Property ─────────────────────────────────────────────────────
@@ -68,6 +69,10 @@ export const PropertySchema = z.object({
6869
expireTime: Timestamp.optional(),
6970
});
7071

72+
export const PropertyResponseSchema = z.object({
73+
response: PropertySchema,
74+
});
75+
7176
// ── Admin API — Custom Dimensions & Metrics ──────────────────────────────────
7277

7378
export const CustomDimensionSchema = z.object({
@@ -96,11 +101,21 @@ export const CustomMetricSchema = z.object({
96101
restrictedMetricType: z.array(z.string()).optional(),
97102
});
98103

99-
export const CustomDimensionsAndMetricsOutputSchema = z.object({
104+
export const CustomDimensionsListSchema = z.object({
100105
customDimensions: z.array(CustomDimensionSchema).optional(),
106+
});
107+
108+
export const CustomMetricsListSchema = z.object({
101109
customMetrics: z.array(CustomMetricSchema).optional(),
102110
});
103111

112+
export const CustomDimensionsAndMetricsResponseSchema = z.object({
113+
/** Result of listCustomDimensions — `{ customDimensions: [...] }` */
114+
dimensions: CustomDimensionsListSchema,
115+
/** Result of listCustomMetrics — `{ customMetrics: [...] }` */
116+
metrics: CustomMetricsListSchema,
117+
});
118+
104119
// ── Admin API — Google Ads Links ─────────────────────────────────────────────
105120

106121
export const GoogleAdsLinkSchema = z.object({
@@ -115,8 +130,10 @@ export const GoogleAdsLinkSchema = z.object({
115130
updateTime: Timestamp.optional(),
116131
});
117132

118-
export const GoogleAdsLinksOutputSchema = z.object({
119-
googleAdsLinks: z.array(GoogleAdsLinkSchema).optional(),
133+
export const GoogleAdsLinksResponseSchema = z.object({
134+
response: z.object({
135+
googleAdsLinks: z.array(GoogleAdsLinkSchema).optional(),
136+
}),
120137
});
121138

122139
// ── Admin API — Property Annotations ─────────────────────────────────────────
@@ -125,21 +142,17 @@ export const ReportingDataAnnotationSchema = z.object({
125142
/** Resource name. */
126143
name: z.string().optional(),
127144
annotationDate: DateSchema.optional(),
128-
annotationDateRange: z
129-
.object({
130-
startDate: DateSchema.optional(),
131-
endDate: DateSchema.optional(),
132-
})
133-
.optional(),
134145
title: z.string().optional(),
135146
description: z.string().optional(),
136147
systemGenerated: z.boolean().optional(),
137148
/** "RED" | "ORANGE" | "YELLOW" | "GREEN" | "BLUE" | "PURPLE" | "PINK" */
138149
color: z.string().optional(),
139150
});
140151

141-
export const PropertyAnnotationsOutputSchema = z.object({
142-
reportingDataAnnotations: z.array(ReportingDataAnnotationSchema).optional(),
152+
export const PropertyAnnotationsResponseSchema = z.object({
153+
response: z.object({
154+
reportingDataAnnotations: z.array(ReportingDataAnnotationSchema).optional(),
155+
}),
143156
});
144157

145158
// ── Data API — shared building blocks ────────────────────────────────────────
@@ -168,11 +181,9 @@ export const RowSchema = z.object({
168181
});
169182

170183
export const ResponseMetaDataSchema = z.object({
171-
dataLossFromOtherRow: z.boolean().optional(),
172-
schemaRestrictionResponse: z.unknown().optional(),
173184
currencyCode: z.string().optional(),
174185
timeZone: z.string().optional(),
175-
emptyReason: z.string().optional(),
186+
schemaRestrictionResponse: z.unknown().optional(),
176187
subjectToThresholding: z.boolean().optional(),
177188
samplingMetadatas: z.array(z.unknown()).optional(),
178189
});
@@ -195,15 +206,15 @@ export const PropertyQuotaSchema = z
195206
potentiallyThresholdedRequestsPerHour: z
196207
.object({ consumed: z.number(), remaining: z.number() })
197208
.optional(),
198-
tokensPerProjectPerHour: z
209+
tokensPerProjectPerDay: z
199210
.object({ consumed: z.number(), remaining: z.number() })
200211
.optional(),
201212
})
202213
.optional();
203214

204215
// ── Data API — runReport ──────────────────────────────────────────────────────
205216

206-
export const RunReportOutputSchema = z.object({
217+
export const RunReportResponseSchema = z.object({
207218
dimensionHeaders: z.array(DimensionHeaderSchema).optional(),
208219
metricHeaders: z.array(MetricHeaderSchema).optional(),
209220
rows: z.array(RowSchema).optional(),
@@ -217,9 +228,13 @@ export const RunReportOutputSchema = z.object({
217228
kind: z.string().optional(),
218229
});
219230

231+
export const RunReportOutputSchema = z.object({
232+
response: RunReportResponseSchema,
233+
});
234+
220235
// ── Data API — runRealtimeReport ─────────────────────────────────────────────
221236

222-
export const RunRealtimeReportOutputSchema = z.object({
237+
export const RunRealtimeReportResponseSchema = z.object({
223238
dimensionHeaders: z.array(DimensionHeaderSchema).optional(),
224239
metricHeaders: z.array(MetricHeaderSchema).optional(),
225240
rows: z.array(RowSchema).optional(),
@@ -232,9 +247,13 @@ export const RunRealtimeReportOutputSchema = z.object({
232247
kind: z.string().optional(),
233248
});
234249

250+
export const RunRealtimeReportOutputSchema = z.object({
251+
response: RunRealtimeReportResponseSchema,
252+
});
253+
235254
// ── Data API — runFunnelReport ────────────────────────────────────────────────
236255

237-
const FunnelResponseMetaDataSchema = z.object({
256+
export const FunnelResponseMetaDataSchema = z.object({
238257
samplingMetadatas: z.array(z.unknown()).optional(),
239258
schemaRestrictionResponse: z.unknown().optional(),
240259
});
@@ -243,7 +262,7 @@ const FunnelResponseMetaDataSchema = z.object({
243262
* Funnel response rows share the same Row structure (dimensionValues +
244263
* metricValues), grouped in funnelTable and funnelVisualization sub-objects.
245264
*/
246-
const FunnelSubReportSchema = z.object({
265+
export const FunnelSubReportSchema = z.object({
247266
dimensionHeaders: z.array(DimensionHeaderSchema).optional(),
248267
metricHeaders: z.array(MetricHeaderSchema).optional(),
249268
rows: z.array(RowSchema).optional(),
@@ -254,10 +273,14 @@ const FunnelSubReportSchema = z.object({
254273
metadata: FunnelResponseMetaDataSchema.optional(),
255274
});
256275

257-
export const RunFunnelReportOutputSchema = z.object({
276+
export const RunFunnelReportResponseSchema = z.object({
258277
funnelTable: FunnelSubReportSchema.optional(),
259278
funnelVisualization: FunnelSubReportSchema.optional(),
260279
propertyQuota: PropertyQuotaSchema.optional(),
261280
/** Always "analyticsData#runFunnelReport". */
262281
kind: z.string().optional(),
263282
});
283+
284+
export const RunFunnelReportOutputSchema = z.object({
285+
response: RunFunnelReportResponseSchema,
286+
});

google-analytics/server/tools/accounts.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,21 @@ import { z } from "zod";
22
import { createPrivateTool } from "@decocms/runtime/tools";
33
import type { Env } from "../../shared/deco.gen.ts";
44
import { GaClient } from "../lib/ga-client.ts";
5-
import { AccountSummariesOutputSchema } from "../lib/schemas.ts";
5+
import { AccountSummariesResponseSchema } from "../lib/schemas.ts";
66

77
export const getAccountSummariesTool = (env: Env) =>
88
createPrivateTool({
99
id: "get-account-summaries",
1010
description:
1111
"Retrieves information about the user's Google Analytics accounts and properties.",
1212
inputSchema: z.object({}),
13-
outputSchema: AccountSummariesOutputSchema,
13+
outputSchema: AccountSummariesResponseSchema,
1414
execute: async () => {
1515
const client = GaClient.fromEnv(env);
16+
1617
try {
1718
const result = await client.listAccountSummaries();
18-
return AccountSummariesOutputSchema.parse(result);
19+
return AccountSummariesResponseSchema.parse({ response: result });
1920
} catch (error) {
2021
throw new Error(
2122
`Failed to retrieve account summaries: ${error instanceof Error ? error.message : String(error)}`,

google-analytics/server/tools/ads.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@ import { createPrivateTool } from "@decocms/runtime/tools";
33
import type { Env } from "../../shared/deco.gen.ts";
44
import { GaClient } from "../lib/ga-client.ts";
55
import { resolveProperty } from "../lib/env.ts";
6-
import { GoogleAdsLinksOutputSchema } from "../lib/schemas.ts";
6+
import { GoogleAdsLinksResponseSchema } from "../lib/schemas.ts";
77

88
const propertySchema = z
9+
910
.string()
11+
1012
.optional()
13+
1114
.describe(
1215
"GA4 Property identifier — 'properties/1234567' or just '1234567'. Falls back to the default propertyId configured for this integration when omitted.",
1316
);
@@ -18,14 +21,14 @@ export const listGoogleAdsLinksTool = (env: Env) =>
1821
description:
1922
"Returns a list of links to Google Ads accounts for a GA4 property.",
2023
inputSchema: z.object({ property: propertySchema }),
21-
outputSchema: GoogleAdsLinksOutputSchema,
24+
outputSchema: GoogleAdsLinksResponseSchema,
2225
execute: async ({ context: args }) => {
2326
const client = GaClient.fromEnv(env);
2427
try {
2528
const result = await client.listGoogleAdsLinks(
2629
resolveProperty(env, args.property),
2730
);
28-
return GoogleAdsLinksOutputSchema.parse(result);
31+
return GoogleAdsLinksResponseSchema.parse({ response: result });
2932
} catch (error) {
3033
throw new Error(
3134
`Failed to retrieve Google Ads links: ${error instanceof Error ? error.message : String(error)}`,

google-analytics/server/tools/annotations.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@ import { createPrivateTool } from "@decocms/runtime/tools";
33
import type { Env } from "../../shared/deco.gen.ts";
44
import { GaClient } from "../lib/ga-client.ts";
55
import { resolveProperty } from "../lib/env.ts";
6-
import { PropertyAnnotationsOutputSchema } from "../lib/schemas.ts";
6+
import { PropertyAnnotationsResponseSchema } from "../lib/schemas.ts";
77

88
const propertySchema = z
9+
910
.string()
11+
1012
.optional()
13+
1114
.describe(
1215
"GA4 Property identifier — 'properties/1234567' or just '1234567'. Falls back to the default propertyId configured for this integration when omitted.",
1316
);
@@ -18,14 +21,14 @@ export const listPropertyAnnotationsTool = (env: Env) =>
1821
description:
1922
"Returns timestamped annotations for a GA4 property — useful for correlating traffic changes with events like campaign launches, site releases, or data collection changes.",
2023
inputSchema: z.object({ property: propertySchema }),
21-
outputSchema: PropertyAnnotationsOutputSchema,
24+
outputSchema: PropertyAnnotationsResponseSchema,
2225
execute: async ({ context: args }) => {
2326
const client = GaClient.fromEnv(env);
2427
try {
2528
const result = await client.listPropertyAnnotations(
2629
resolveProperty(env, args.property),
2730
);
28-
return PropertyAnnotationsOutputSchema.parse(result);
31+
return PropertyAnnotationsResponseSchema.parse({ response: result });
2932
} catch (error) {
3033
throw new Error(
3134
`Failed to retrieve property annotations: ${error instanceof Error ? error.message : String(error)}`,

google-analytics/server/tools/properties.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@ import type { Env } from "../../shared/deco.gen.ts";
44
import { GaClient } from "../lib/ga-client.ts";
55
import { resolveProperty } from "../lib/env.ts";
66
import {
7-
PropertySchema,
8-
CustomDimensionsAndMetricsOutputSchema,
7+
PropertyResponseSchema,
8+
CustomDimensionsAndMetricsResponseSchema,
99
} from "../lib/schemas.ts";
1010

1111
const propertySchema = z
12+
1213
.string()
14+
1315
.optional()
16+
1417
.describe(
1518
"GA4 Property identifier — 'properties/1234567' or just '1234567'. Falls back to the default propertyId configured for this integration when omitted.",
1619
);
@@ -21,14 +24,14 @@ export const getPropertyDetailsTool = (env: Env) =>
2124
description:
2225
"Returns metadata and configuration details about a GA4 property.",
2326
inputSchema: z.object({ property: propertySchema }),
24-
outputSchema: PropertySchema,
27+
outputSchema: PropertyResponseSchema,
2528
execute: async ({ context: args }) => {
2629
const client = GaClient.fromEnv(env);
2730
try {
2831
const result = await client.getProperty(
2932
resolveProperty(env, args.property),
3033
);
31-
return PropertySchema.parse(result);
34+
return PropertyResponseSchema.parse({ response: result });
3235
} catch (error) {
3336
throw new Error(
3437
`Failed to retrieve property details: ${error instanceof Error ? error.message : String(error)}`,
@@ -43,19 +46,20 @@ export const getCustomDimensionsAndMetricsTool = (env: Env) =>
4346
description:
4447
"Retrieves the custom dimensions and custom metrics configured for a GA4 property.",
4548
inputSchema: z.object({ property: propertySchema }),
46-
outputSchema: CustomDimensionsAndMetricsOutputSchema,
49+
outputSchema: CustomDimensionsAndMetricsResponseSchema,
4750
execute: async ({ context: args }) => {
4851
const client = GaClient.fromEnv(env);
4952
try {
5053
const property = resolveProperty(env, args.property);
5154
// Both calls are independent — run in parallel to halve latency.
52-
const [dimensionsResult, metricsResult] = await Promise.all([
55+
const [dimensions, metrics] = await Promise.all([
5356
client.listCustomDimensions(property),
5457
client.listCustomMetrics(property),
5558
]);
56-
return CustomDimensionsAndMetricsOutputSchema.parse({
57-
...(dimensionsResult as object),
58-
...(metricsResult as object),
59+
60+
return CustomDimensionsAndMetricsResponseSchema.parse({
61+
dimensions,
62+
metrics,
5963
});
6064
} catch (error) {
6165
throw new Error(

0 commit comments

Comments
 (0)