Skip to content

feat: add batch_run_reports tool - #172

Open
Avicennasis wants to merge 8 commits into
googleanalytics:mainfrom
Avicennasis:feat/batch-run-reports
Open

feat: add batch_run_reports tool#172
Avicennasis wants to merge 8 commits into
googleanalytics:mainfrom
Avicennasis:feat/batch-run-reports

Conversation

@Avicennasis

Copy link
Copy Markdown

Summary

Adds a new batch_run_reports tool that wraps the Data API v1beta batchRunReports endpoint, allowing up to 5 reports to be run in a single API call.

  • Each report in the batch accepts the same parameters as the existing run_report tool (dimensions, metrics, date_ranges, filters, order_bys, limit, offset, currency_code, return_property_quota)
  • Includes input validation (1–5 requests, required fields, type checks)
  • Reuses the existing v1beta client and read-only auth scope
  • Includes LLM-facing hints matching run_report's format

Use case

When an LLM needs data from multiple reports for the same property (e.g. building a dashboard, comparing metrics across dimensions), this reduces latency vs. calling run_report sequentially. The API processes all reports server-side in a single round trip.

Files changed

File Change
analytics_mcp/tools/reporting/batch.py New tool + _build_report_request helper
analytics_mcp/coordinator.py Register new tool
tests/batch_test.py 11 unit tests (request construction, validation, mocked API call)

Test plan

  • nox -s lint passes (black, 80-char line width)
  • nox -s tests passes — 17 tests total (6 existing + 11 new)
  • Manual test: run a batch of 2–3 reports against a real GA4 property

@Avicennasis
Avicennasis force-pushed the feat/batch-run-reports branch from f73dfe5 to 3afb237 Compare June 11, 2026 16:11
Audience exports (Data API v1beta, analytics.readonly-compatible):
create_audience_export starts the async export job and returns the
operation metadata for polling; get/list/query retrieve state and
user rows.

Measurement Protocol (plain HTTP, write-capable):
validate_event hits only the debug endpoint and never records data.
send_event is guarded for AI callers — the API secret comes solely
from the ANALYTICS_MCP_MP_API_SECRET env var, dry-run validation is
the default, recording requires an explicit confirm=True, and even
confirmed sends abort if validation fails.
Fixes from a stargazer review of the server:

- coordinator: call_mcp_tool now returns CallToolResult(content=[...],
  isError=True) on both failure paths (tool raised, and tool-not-found)
  instead of a plain TextContent that MCP clients read as a *successful*
  response. This is the one genuinely client-observable fix — clients can
  now detect failures programmatically. [FR-179]
- coordinator: drop the unused `from json import tool` import, which bound
  `tool` to the json.tool CLI module only for it to be shadowed by later
  `for tool in ...` loops. [FR-173]
- client: `except:` -> `except Exception:` in the package-version fallback
  so Ctrl-C / SystemExit are no longer swallowed into "unknown". [FR-175]
- reporting (core, realtime, audience_exports, conversions): replace
  truthy `if limit:` / `if offset:` / `if currency_code:` guards with
  `is not None`. NOTE: these RunReportRequest fields are proto3 scalars
  with no field presence, so offset=0 / limit=0 serialize identically to
  unset — this is a correctness/consistency cleanup and a guard against
  presence-aware fields, NOT a behavior change today (verified by
  comparing serialized requests). [FR-170, FR-171, FR-172, FR-181]

Verified: black --check clean; existing suite (19 tests) green; ad-hoc
harness confirms isError=True on both failure paths, the success path still
returns list[Content], and offset/limit=0 requests are wire-identical to
unset.
@Avicennasis
Avicennasis force-pushed the feat/batch-run-reports branch from 3afb237 to 6d7ea57 Compare August 19, 2026 17:20
Avicennasis and others added 2 commits August 19, 2026 13:24
Rebuilt on top of current main rather than rebased — the original branch's
coordinator.py hunk conflicted through an unterminated import statement, so a
union merge produced nested open imports. Reapplied the branch's actual
additions (imports, three FunctionTool wrappers, three registry entries, three
inputSchema clauses) at the correct anchors in main's current file.

pivot.py, compatibility.py and their tests are unchanged from the original branch.
Reapplied onto main after #4 (pivot tools) merged — that touched the same
coordinator.py registry, so this branch conflicted again. Same four additions
at the same anchors; verified the pivot registrations from #4 are still intact
(6 references) rather than clobbered.

batch_test.py uses asyncio.run() to match the repo's other tests, and
black --check -l 80 is clean across all 27 files.
@Avicennasis
Avicennasis force-pushed the feat/batch-run-reports branch from 95447fe to 760f880 Compare August 19, 2026 17:59
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