Skip to content

fix(google-analytics): fix input validation and align output schemas#475

Open
yuriassuncx wants to merge 3 commits into
mainfrom
fix/google-analytics-input-validation
Open

fix(google-analytics): fix input validation and align output schemas#475
yuriassuncx wants to merge 3 commits into
mainfrom
fix/google-analytics-input-validation

Conversation

@yuriassuncx

@yuriassuncx yuriassuncx commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Fix input validation errors — some MCP clients (e.g. Claude Desktop, third-party hosts) serialize array and object parameters as JSON strings instead of native types. Added a fromJson preprocessor (z.preprocess) in reports.ts that transparently parses JSON strings before Zod validation. This fixes all 6 reported errors: dateRanges, dimensions, metrics, dimensionFilter, metricFilter, orderBys, orderBys, limit, and offset.
  • Remove { response: ... } wrapper from all output schemas — all tools now return data directly (e.g. { rows: [...] } instead of { response: { rows: [...] } }), consistent with google-search-console and google-tag-manager patterns.
  • Flatten getCustomDimensionsAndMetrics output — from { dimensions: { customDimensions: [...] }, metrics: { customMetrics: [...] } } to { customDimensions: [...], customMetrics: [...] }.
  • Fix code formatting — remove unnecessary blank lines between chained Zod method calls across all tool files.

Root cause

The validation error was:
```
Invalid input: expected array, received string (dateRanges, dimensions, metrics, orderBys)
Invalid input: expected record, received string (dimensionFilter)
Invalid input: expected number, received string (limit)
```

The fix uses z.preprocess to attempt JSON.parse on string inputs before Zod validates them. If parsing fails, the original value is passed through and Zod produces a clear type error.

Test plan

  • Run run-report with native JSON arrays — should work as before
  • Run run-report with JSON-stringified arrays — should now pass validation
  • Verify get-account-summaries output is now { accountSummaries: [...] } (no response wrapper)
  • Verify run-report output is now { rows: [...], dimensionHeaders: [...], ... } (no response wrapper)
  • Verify get-custom-dimensions-and-metrics output is { customDimensions: [...], customMetrics: [...] } (flat)

🤖 Generated with Claude Code


Summary by cubic

Fixes GA4 tool input validation across MCP clients (handles JSON‑stringified arrays/objects/booleans and both "null" strings and native nulls) and updates all outputs to return top‑level data without a response wrapper, matching google-search-console and google-tag-manager. Also flattens the custom dimensions/metrics output.

  • Bug Fixes

    • Parse JSON‑stringified arrays/objects/booleans and coerce "null" and native null to undefined before validation.
    • Handles: dateRanges, dimensions, metrics, dimensionFilter, metricFilter, orderBys, limit, offset, funnelSteps, returnPropertyQuota, isDirectlyFollowedBy.
  • Migration

    • All tools now return data directly (no { response: ... }). Remove response. from callers.
    • getCustomDimensionsAndMetrics now returns { customDimensions, customMetrics }.
    • Affected tools: accounts, properties, ads links, annotations, runReport, runRealtimeReport, runFunnelReport.

Written for commit fd42de0. Summary will update on new commits.

Review in cubic

…with other Google MCPs

- Add `fromJson` preprocessor (z.preprocess) to handle MCP clients that
  serialize arrays and objects as JSON strings instead of native types.
  Fixes validation errors for dateRanges, dimensions, metrics,
  dimensionFilter, metricFilter, orderBys, limit, offset, and funnelSteps.
- Remove the `response` wrapper from all output schemas so tools return
  data directly (e.g. `{ rows: [...] }` instead of `{ response: { rows: [...] } }`),
  consistent with google-search-console and google-tag-manager patterns.
- Flatten `getCustomDimensionsAndMetrics` output from
  `{ dimensions: { customDimensions: [...] }, metrics: { customMetrics: [...] } }`
  to `{ customDimensions: [...], customMetrics: [...] }`.
- Fix code formatting: remove unnecessary blank lines between chained
  Zod method calls across all tool files.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
@yuriassuncx yuriassuncx enabled auto-merge (squash) June 24, 2026 20:50
yuriassuncx and others added 2 commits June 24, 2026 18:08
…ull strings

- Apply fromJson() to returnPropertyQuota (all 3 report tools) and
  FunnelStepSchema.isDirectlyFollowedBy so MCP clients that serialize
  booleans as JSON strings (e.g. "true") pass validation, consistent
  with the existing fix for arrays, objects, and numbers.
- In fromJson, treat JSON-parsed null as undefined so optional fields
  that receive the string "null" degrade gracefully instead of failing
  Zod validation.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…eprocessor

MCP clients that send null explicitly for absent optional fields (e.g.
{"dimensionFilter": null}) were getting a hard Zod type error instead of
the field being treated as absent. Add an explicit null check so both
native null and the JSON string "null" are treated as undefined.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant