Skip to main content
Glama
Walma-Labs

ga4-mcp

by Walma-Labs

ga4-mcp — Google Analytics 4 MCP server

A read-only Model Context Protocol server that gives Claude, Cursor, Claude Code and any other MCP client access to Google Analytics 4: core, realtime, funnel and conversions reports, plus account and property information.

It is a TypeScript port of Google's own analytics-mcp. It has the same nine tools, the same argument names and the same filter hints, so prompts written for one work on the other. What differs:

  • Service-account auth, no gcloud. Point it at a key file, or pass the key inline. Nothing to log in to on the machine that runs the agent.

  • Streamable HTTP as well as stdio. It can run centrally. This is how Walma serves it to whole organisations through its AI gateway.

  • Compact results. Report rows come back as one object per row ({ "country": "Sweden", "sessions": 120 }) instead of parallel value arrays, so the model spends fewer tokens on the same data.

  • Three runtime dependencies. It calls the REST API directly instead of using the gRPC client libraries and Google's agent framework.

Built and used by Walma AI.

Tools

Tool

What it does

get_account_summaries

Accounts and properties the service account can read, with property IDs

get_property_details

Time zone, currency, industry and service level of a property

list_google_ads_links

Google Ads accounts linked to a property

list_property_annotations

Notes left on dates in GA4 (releases, campaigns, outages)

get_custom_dimensions_and_metrics

The property's custom definitions, with the apiName to report on

run_report

Data API report: any dimensions and metrics, filters, ordering, several date ranges, pagination

run_realtime_report

The last ~30 minutes

run_funnel_report

Funnel progression and abandonment, with breakdowns and next actions

run_conversions_report

Ad cost, ROAS and conversions with a chosen attribution model

Everything is read-only (analytics.readonly scope). The server cannot change anything in Google Analytics.

Related MCP server: google_analytics

Setup

1. Create a service account and key

  1. In Google Cloud Console, pick or create a project.

  2. Enable the Google Analytics Data API and the Google Analytics Admin API.

  3. IAM & Admin → Service accounts → Create. No project roles are needed.

  4. Keys → Add key → JSON. Save the file somewhere outside any repository, for example ~/.config/gcloud/ga4-service-account.json.

2. Give the service account access in Google Analytics

In GA4, open Admin → Property access management (or Account access management to cover every property in the account). Add the service account's email address (…@….iam.gserviceaccount.com) with the Viewer role.

The server sees exactly the properties it was invited to.

3. Add it to your MCP client

Claude Code:

claude mcp add ga4 --scope user \
  -e GA4_SERVICE_ACCOUNT_FILE=~/.config/gcloud/ga4-service-account.json \
  -- npx -y github:Walma-Labs/ga4-mcp

Claude Desktop, Cursor and others (mcpServers in the client's config):

{
  "mcpServers": {
    "ga4": {
      "command": "npx",
      "args": ["-y", "github:Walma-Labs/ga4-mcp"],
      "env": { "GA4_SERVICE_ACCOUNT_FILE": "/absolute/path/to/ga4-service-account.json" }
    }
  }
}

Environment variables

Variable

Meaning

GA4_SERVICE_ACCOUNT_FILE

Path to the service-account JSON key (~ is expanded)

GA4_SERVICE_ACCOUNT_JSON

The key as inline JSON. Wins over the file when both are set

PORT

Port for the HTTP entrypoint (default 8080)

Running over HTTP

npm install && npm run build
GA4_SERVICE_ACCOUNT_FILE=… npm run start:http

This starts a stateless streamable-HTTP endpoint on POST /, plus GET /healthz. It has no authentication of its own. Put it behind something that authenticates callers. In Walma's deployment, the gateway relay does that.

Using it as a library

import { createGa4Server, createGa4Client } from "@walma-labs/ga4-mcp";

const client = createGa4Client();          // or createGa4Client(myRequestFn)
const server = createGa4Server(client);    // an McpServer; connect any transport

createGa4Client takes an optional request function, so you can supply your own authorisation or a test double.

Development

npm install
npm test        # unit + MCP-wire tests against a mocked client, no network
npm run build

License

Apache-2.0. Tool names, argument contracts and hint text derive from Google's analytics-mcp; see NOTICE.

Available Tools

9 tools
get_account_summariesA

List the Google Analytics accounts and properties the service account can read, with property IDs.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden, and it does disclose the key behavioral fact that results are limited to what the service account can read (a permission boundary). However, it never states that it is a read-only, side-effect-free operation, and says nothing about pagination, rate limits, or result volume.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single sentence with no filler, front-loading the resource and scoping constraint before the returned identifier detail. Nothing extraneous and nothing buried.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description must sketch the return; it does so at a high level (accounts, properties, property IDs). It stops short of clarifying the account→property nesting or whether results are paginated, which an agent would need to parse the response confidently.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so there are no parameter semantics to document and the baseline of 4 applies. The description correctly adds no spurious parameter guidance.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb ("List") plus specific resource (Google Analytics accounts and properties) and a scope qualifier ("the service account can read"), plus the notable payload detail "with property IDs". It is distinguishable from siblings like get_property_details or run_report by being the account/property discovery call, though no sibling is named explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: because it returns property IDs, an agent can infer this is the discovery step before run_report or get_property_details. There is no explicit statement of when to call it, when not to, or which sibling to use instead.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_custom_dimensions_and_metricsA

Return the property's custom dimensions and metrics, with the apiName to use in reports.

ParametersJSON Schema
NameRequiredDescriptionDefault
property_idYesThe Google Analytics property ID: a number, or 'properties/' followed by a number. Use get_account_summaries to find it.

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. 'Return' implies a read-only lookup and it discloses the returned content (dimensions, metrics, apiName), but it says nothing about authentication/permission needs, empty-result behavior, or possible errors for an invalid property.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single sentence with no filler, and the core resource is front-loaded before the apiName purpose. Nothing could be trimmed without losing information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read tool with one fully documented parameter this is close to adequate, and the mention of apiName hints at the payload. With no output schema, however, the description should at least sketch the shape of the returned dimensions/metrics rather than leaving the agent to guess.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single property_id parameter is fully documented in the schema, including how to find it. The description adds no parameter-level meaning beyond that, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Return') and resource ('the property's custom dimensions and metrics') with the added detail that it supplies the apiName for reports. That distinguishes it from siblings like get_property_details or get_account_summaries, though it never names a sibling explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'with the apiName to use in reports' implies the tool is a lookup used to build report requests, which is useful inferred context. There is no explicit when-to-use statement, no exclusion of alternatives, and no guidance on what to do if the property has no custom dimensions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_property_detailsB

Return details about a property: time zone, currency, industry, service level, create time.

ParametersJSON Schema
NameRequiredDescriptionDefault
property_idYesThe Google Analytics property ID: a number, or 'properties/' followed by a number. Use get_account_summaries to find it.

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description must carry behavioral disclosure. It implicitly signals a read-only lookup and usefully enumerates the fields returned, which is real behavioral value. However, it says nothing about error behavior for an invalid/missing property, permission requirements, or rate limits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single, front-loaded sentence with the verb and the returned-field list; every word earns its place with no preamble or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, so the description usefully compensates by listing the returned fields. Combined with a fully documented single parameter, this is nearly complete for a simple read tool; only edge-case behavior (missing property, auth) is unaddressed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and there is only one parameter, whose accepted formats and discovery path are fully documented in the schema. The description adds no additional meaning about property_id, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Return details about a property') and enumerates the returned fields (time zone, currency, industry, service level, create time), so the agent knows exactly what this yields. It doesn't explicitly differentiate itself from siblings like get_account_summaries, but those operate on a different resource, so confusion risk is low.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No when-to-use guidance, no prerequisites, and no alternatives named. The useful routing hint ('Use get_account_summaries to find it') lives in the schema's property_id description, not in the tool description, so the description itself offers no selection help.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_property_annotationsA

List a property's annotations: notes left in GA4 on specific dates or periods, typically for releases, campaign launches or changes, and traffic jumps or drops with an external cause.

ParametersJSON Schema
NameRequiredDescriptionDefault
property_idYesThe Google Analytics property ID: a number, or 'properties/' followed by a number. Use get_account_summaries to find it.

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. 'List' plus the note-like nature of annotations conveys that this is a non-mutating read, but it says nothing about permissions, rate limits, result volume, or ordering. It adds useful domain context (what annotations contain) without covering the operational traits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single sentence that front-loads the verb and resource, then spends the remainder clarifying the domain term 'annotation'. Every clause earns its place and nothing is repeated.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema and no annotations, so the description is the only source of behavioral information. It conveys the concept of annotations but not the shape of the response (fields, ordering, pagination), which for a list tool leaves a gap despite the simple one-parameter surface.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single property_id parameter is thoroughly documented in the schema, including the accepted formats and how to discover it via get_account_summaries. The description adds no parameter detail, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific verb ('List') and a precisely scoped resource ('a property's annotations'), then explains what an annotation is in GA4. No sibling tool touches annotations, so an agent can tell this apart from the report/get siblings without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explains what annotations are and when they typically exist ('for releases, campaign launches or changes'), but never states when to call this tool, what prerequisite (a valid property_id) is needed, or how it relates to alternatives. That context is about the data, not about tool selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

run_conversions_reportA

Runs a Google Analytics Data API conversions report.

USE THIS TOOL INSTEAD OF run_report WHEN:

  • You need to report on conversions, ad performance, return on ad spend (ROAS) or attribution.

  • You need conversion metrics such as advertiserAdCost, returnOnAdSpendByInteractionDate or allConversionsByConversionDate.

  • You need a specific attribution model (DATA_DRIVEN or LAST_CLICK).

  • The question is explicitly about conversions, ad clicks, ad costs, or campaigns related to conversions.

See https://developers.google.com/analytics/devguides/reporting/data/v1/conversions-api-basics.

dimensions

Only these standard dimensions: campaignName, continent, country, defaultChannelGroup, deviceCategory, medium, platform, primaryChannelGroup, source, sourceMedium, sourcePlatform, subcontinent.

metrics

Only these standard metrics: advertiserAdClicks, advertiserAdCost, advertiserAdCostPerAllConversionsByConversionDate, advertiserAdCostPerAllConversionsByInteractionDate, advertiserAdCostPerClick, advertiserAdImpressions, allConversionsByConversionDate, allConversionsByInteractionDate, returnOnAdSpendByConversionDate, returnOnAdSpendByInteractionDate, totalRevenueByConversionDate, totalRevenueByInteractionDate.

conversion_spec

Required. Pass an empty conversion_actions list for all conversion events: {"conversion_actions": ["conversionActions/12345"], "attribution_model": "DATA_DRIVEN"} (or [] / "LAST_CLICK")

date_ranges

Example date_ranges arguments:

  1. A single date range: [ {"start_date":"2025-01-01","end_date":"2025-01-31","name":"Jan2025"} ]

  2. A relative date range using 'yesterday' and 'today': [ {"start_date":"yesterday","end_date":"today","name":"YesterdayAndToday"} ]

  3. A relative date range using 'NdaysAgo': [ {"start_date":"30daysAgo","end_date":"yesterday","name":"Previous30Days"} ]

  4. Multiple date ranges (adds a 'dateRange' column to every row): [ {"start_date":"2025-01-01","end_date":"2025-01-31","name":"Jan2025"}, {"start_date":"2025-02-01","end_date":"2025-02-28","name":"Feb2025"} ]

dimension_filter

Example dimension_filter arguments:

  1. A simple filter: {"filter":{"field_name":"eventName","string_filter":{"match_type":"BEGINS_WITH","value":"add"}}}

  2. A NOT filter: {"not_expression":{"filter":{"field_name":"eventName","string_filter":{"match_type":"BEGINS_WITH","value":"add"}}}}

  3. An empty value filter: {"filter":{"field_name":"source","empty_filter":{}}}

  4. An AND group filter: {"and_group":{"expressions":[{"filter":{"field_name":"sourceMedium","string_filter":{"match_type":"EXACT","value":"google / cpc"}}},{"filter":{"field_name":"eventName","in_list_filter":{"case_sensitive":true,"values":["first_visit","purchase","add_to_cart"]}}}]}}

  5. An OR group filter: {"or_group":{"expressions":[{"filter":{"field_name":"sourceMedium","string_filter":{"match_type":"EXACT","value":"google / cpc"}}},{"filter":{"field_name":"eventName","in_list_filter":{"case_sensitive":true,"values":["first_visit","purchase","add_to_cart"]}}}]}}

Notes: The API applies dimension_filter and metric_filter independently, so some combinations are impossible in one request, e.g. ((eventName = "page_view" AND eventCount > 100) OR (eventName = "join_group" AND eventCount < 50)). For conditions shaped ((D1 AND M1) OR (D2 AND M2)) either: a) run one report filtering on the supported subset (eventName in ["page_view","join_group"]) with eventCount included, and apply the metric conditions to the rows yourself; or b) run one report per (dimension condition, metric condition) pair. Prefer (a) — fewer reports — unless it would use excessive quota (https://developers.google.com/analytics/blog/2023/data-api-quota-management).

metric_filter

Example metric_filter arguments:

  1. A simple filter: {"filter":{"field_name":"eventCount","numeric_filter":{"operation":"GREATER_THAN","value":{"int64_value":"10"}}}}

  2. A NOT filter: {"not_expression":{"filter":{"field_name":"eventCount","numeric_filter":{"operation":"GREATER_THAN","value":{"int64_value":"10"}}}}}

  3. An empty value filter: {"filter":{"field_name":"purchaseRevenue","empty_filter":{}}}

  4. An AND group filter: {"and_group":{"expressions":[{"filter":{"field_name":"eventCount","numeric_filter":{"operation":"GREATER_THAN","value":{"int64_value":"10"}}}},{"filter":{"field_name":"purchaseRevenue","between_filter":{"from_value":{"double_value":10},"to_value":{"double_value":25}}}}]}}

  5. An OR group filter: {"or_group":{"expressions":[{"filter":{"field_name":"eventCount","numeric_filter":{"operation":"GREATER_THAN","value":{"int64_value":"10"}}}},{"filter":{"field_name":"purchaseRevenue","between_filter":{"from_value":{"double_value":10},"to_value":{"double_value":25}}}}]}}

Notes: The API applies dimension_filter and metric_filter independently, so some combinations are impossible in one request, e.g. ((eventName = "page_view" AND eventCount > 100) OR (eventName = "join_group" AND eventCount < 50)). For conditions shaped ((D1 AND M1) OR (D2 AND M2)) either: a) run one report filtering on the supported subset (eventName in ["page_view","join_group"]) with eventCount included, and apply the metric conditions to the rows yourself; or b) run one report per (dimension condition, metric condition) pair. Prefer (a) — fewer reports — unless it would use excessive quota (https://developers.google.com/analytics/blog/2023/data-api-quota-management).

order_bys

Example order_bys arguments:

  1. Ascending 'eventName': [ {"dimension":{"dimension_name":"eventName","order_type":"ALPHANUMERIC"},"desc":false} ]

  2. Descending 'campaignName', ignoring case: [ {"dimension":{"dimension_name":"campaignName","order_type":"CASE_INSENSITIVE_ALPHANUMERIC"},"desc":true} ]

  3. Ascending 'audienceId' (numeric): [ {"dimension":{"dimension_name":"audienceId","order_type":"NUMERIC"},"desc":false} ]

  4. Descending 'eventCount': [ {"metric":{"metric_name":"eventCount"},"desc":true} ]

  5. Ascending 'eventCount': [ {"metric":{"metric_name":"eventCount"},"desc":false} ]

  6. Dimension and metric combined: [ {"dimension":{"dimension_name":"eventName","order_type":"ALPHANUMERIC"},"desc":false}, {"metric":{"metric_name":"eventCount"},"desc":true} ]

  7. Several dimensions and metrics: [ {"dimension":{"dimension_name":"eventName","order_type":"ALPHANUMERIC"},"desc":false}, {"dimension":{"dimension_name":"audienceId","order_type":"NUMERIC"},"desc":false}, {"metric":{"metric_name":"eventCount"},"desc":true} ] The dimensions and metrics in order_bys must also be in the request's dimensions and metrics.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax rows per response, 1-250000. Paginate with offset.
offsetNoRow count of the start row (first row is 0).
metricsYes
order_bysNoData API OrderBy objects; every field named must be in dimensions/metrics.
dimensionsYes
date_rangesYesDate ranges: [{start_date, end_date, name?}]. Dates are YYYY-MM-DD, 'today', 'yesterday' or 'NdaysAgo'.
property_idYesThe Google Analytics property ID: a number, or 'properties/' followed by a number. Use get_account_summaries to find it.
currency_codeNo
metric_filterNoData API FilterExpression on metrics. Don't use it for dimensions; use dimension_filter.
conversion_specYes{conversion_actions: string[], attribution_model: 'DATA_DRIVEN' | 'LAST_CLICK'}
dimension_filterNoData API FilterExpression on dimensions. Don't use it for metrics; use metric_filter.
return_property_quotaNoInclude the property's quota usage in the response.

TDQS

A4.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It discloses the conversion/dimension restriction and links to quota documentation plus the max-row/pagination limit, which is useful. However it never states this is a read-only report (no mutation side effects), nor auth/permission requirements for the property, leaving the safety profile implicit.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads purpose and the run_report alternative well, but the long 'Notes: The API applies dimension_filter and metric_filter independently...' block is duplicated verbatim under both filter sections, adding significant redundancy. The reference-example format is otherwise scannable but bloats length.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex 12-parameter tool with nested filters and no output schema, the description supplies the allowed dimensions/metrics enumerations, required conversion_spec, and example payloads for every structured param. An agent has enough to call it correctly; only return-value shape is unstated, which is acceptable for a report tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 75%, but the description goes well beyond it: worked examples for date_ranges (relative dates, multiple ranges), dimension_filter and metric_filter (all filter shapes including AND/OR/NOT/empty), order_bys, and a required conversion_spec format with empty-list semantics. This meaningfully reduces invocation errors.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Runs a Google Analytics Data API conversions report') and explicitly distinguishes itself from the sibling run_report, listing the exact metrics and dimensions that are conversions-only. An agent can select it over run_report without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides an explicit 'USE THIS TOOL INSTEAD OF run_report WHEN' list with four concrete triggering conditions (conversions, ROAS, attribution model, ad metrics). This is a textbook when-to-use/when-to-prefer-alternative block naming the sibling.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

run_funnel_reportA

Runs a Google Analytics Data API funnel report (https://developers.google.com/analytics/devguides/reporting/data/v1/funnels).

Returns funnel_table (progression through the steps) and funnel_visualization, both flattened to one object per row.

funnel_steps

Each step is {name, filter_expression} or the shorthand {name, event}. Example funnel_steps configurations:

  1. Shorthand event step: {"name":"Session start","event":"session_start"}

  2. Several events with OR: {"name":"First open/visit","filter_expression":{"or_group":{"expressions":[{"funnel_event_filter":{"event_name":"first_open"}},{"funnel_event_filter":{"event_name":"first_visit"}}]}}}

  3. Field filter for organic traffic: {"name":"Organic visitors","filter_expression":{"funnel_field_filter":{"field_name":"firstUserMedium","string_filter":{"match_type":"CONTAINS","case_sensitive":false,"value":"organic"}}}}

  4. Event with a parameter filter (value > 50): {"name":"Add to cart (value > 50)","filter_expression":{"funnel_event_filter":{"event_name":"add_to_cart","funnel_parameter_filter_expression":{"funnel_parameter_filter":{"event_parameter_name":"value","numeric_filter":{"operation":"GREATER_THAN","value":{"double_value":50}}}}}}}

  5. AND condition (page view on a path): {"name":"Home page view","filter_expression":{"and_group":{"expressions":[{"funnel_event_filter":{"event_name":"page_view"}},{"funnel_field_filter":{"field_name":"pageLocation","string_filter":{"match_type":"CONTAINS","value":"/"}}}]}}}

A typical e-commerce funnel: [ {"name":"First open/visit","filter_expression":{"or_group":{"expressions":[{"funnel_event_filter":{"event_name":"first_open"}},{"funnel_event_filter":{"event_name":"first_visit"}}]}}}, {"name":"Organic visitors","filter_expression":{"funnel_field_filter":{"field_name":"firstUserMedium","string_filter":{"match_type":"CONTAINS","case_sensitive":false,"value":"organic"}}}}, {"name":"Session start","filter_expression":{"funnel_event_filter":{"event_name":"session_start"}}}, {"name":"Screen/Page view","filter_expression":{"or_group":{"expressions":[{"funnel_event_filter":{"event_name":"screen_view"}},{"funnel_event_filter":{"event_name":"page_view"}}]}}}, {"name":"Purchase","filter_expression":{"or_group":{"expressions":[{"funnel_event_filter":{"event_name":"purchase"}},{"funnel_event_filter":{"event_name":"in_app_purchase"}}]}}} ]

funnel_breakdown

Segment the funnel by a dimension: {"breakdown_dimension": "deviceCategory"}. Common: deviceCategory, country, operatingSystem, browser.

funnel_next_action

What users do after completing or dropping off: {"next_action_dimension": "eventName", "limit": 5}. Common: eventName, pagePath.

segments

Data API Segment objects (https://developers.google.com/analytics/devguides/reporting/data/v1/funnels#segments).

date_ranges

Example date_ranges arguments:

  1. A single date range: [ {"start_date":"2025-01-01","end_date":"2025-01-31","name":"Jan2025"} ]

  2. A relative date range using 'yesterday' and 'today': [ {"start_date":"yesterday","end_date":"today","name":"YesterdayAndToday"} ]

  3. A relative date range using 'NdaysAgo': [ {"start_date":"30daysAgo","end_date":"yesterday","name":"Previous30Days"} ]

  4. Multiple date ranges (adds a 'dateRange' column to every row): [ {"start_date":"2025-01-01","end_date":"2025-01-31","name":"Jan2025"}, {"start_date":"2025-02-01","end_date":"2025-02-28","name":"Feb2025"} ]

ParametersJSON Schema
NameRequiredDescriptionDefault
segmentsNo
date_rangesNoDate ranges: [{start_date, end_date, name?}]. Dates are YYYY-MM-DD, 'today', 'yesterday' or 'NdaysAgo'.
property_idYesThe Google Analytics property ID: a number, or 'properties/' followed by a number. Use get_account_summaries to find it.
funnel_stepsYes
funnel_breakdownNo
funnel_next_actionNo
return_property_quotaNoInclude the property's quota usage in the response.

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden. It discloses that results are flattened to one object per row and that multiple date_ranges add a dateRange column, but it does not describe permissions, quota behavior, error conditions, or whether the operation is read-only.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well organized with purpose and return values front-loaded, followed by parameter-specific sections. It is long and includes multiple verbose examples, but for a complex nested funnel_steps schema this length is largely justified.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complex nested input, lack of annotations, and absence of an output schema, the description provides strong invocation guidance and partial return-value context. It still omits deeper behavioral details such as auth requirements, quota limits, and error handling.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 43%, so the description must compensate and does so extensively. It provides detailed examples for funnel_steps, funnel_breakdown, funnel_next_action, segments, and date_ranges, including shorthand event steps, filter_expression shapes, AND/OR groups, and relative date syntax.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Runs a Google Analytics Data API funnel report.' It clearly identifies the report type and mentions the returned artifacts, funnel_table and funnel_visualization, but it does not explicitly distinguish this tool from sibling tools such as run_report or run_conversions_report.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the funnel-specific examples and configuration sections, but the description never states when to choose this tool over run_report or run_conversions_report. There are no explicit when-to-use or when-not-to-use rules.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

run_realtime_reportA

Runs a Google Analytics Data API realtime report covering roughly the last 30 minutes (https://developers.google.com/analytics/devguides/reporting/data/v1/realtime-basics).

dimensions

Realtime dimensions (https://developers.google.com/analytics/devguides/reporting/data/v1/realtime-api-schema#dimensions), or user-scoped custom dimensions: from get_custom_dimensions_and_metrics, those whose apiName begins with "customUser:".

metrics

Realtime metrics only (https://developers.google.com/analytics/devguides/reporting/data/v1/realtime-api-schema#metrics). Realtime reports can't use custom metrics.

dimension_filter

Example dimension_filter arguments:

  1. A simple filter: {"filter":{"field_name":"eventName","string_filter":{"match_type":"BEGINS_WITH","value":"add"}}}

  2. A NOT filter: {"not_expression":{"filter":{"field_name":"eventName","string_filter":{"match_type":"BEGINS_WITH","value":"add"}}}}

  3. An empty value filter: {"filter":{"field_name":"source","empty_filter":{}}}

  4. An AND group filter: {"and_group":{"expressions":[{"filter":{"field_name":"sourceMedium","string_filter":{"match_type":"EXACT","value":"google / cpc"}}},{"filter":{"field_name":"eventName","in_list_filter":{"case_sensitive":true,"values":["first_visit","purchase","add_to_cart"]}}}]}}

  5. An OR group filter: {"or_group":{"expressions":[{"filter":{"field_name":"sourceMedium","string_filter":{"match_type":"EXACT","value":"google / cpc"}}},{"filter":{"field_name":"eventName","in_list_filter":{"case_sensitive":true,"values":["first_visit","purchase","add_to_cart"]}}}]}}

Notes: The API applies dimension_filter and metric_filter independently, so some combinations are impossible in one request, e.g. ((eventName = "page_view" AND eventCount > 100) OR (eventName = "join_group" AND eventCount < 50)). For conditions shaped ((D1 AND M1) OR (D2 AND M2)) either: a) run one report filtering on the supported subset (eventName in ["page_view","join_group"]) with eventCount included, and apply the metric conditions to the rows yourself; or b) run one report per (dimension condition, metric condition) pair. Prefer (a) — fewer reports — unless it would use excessive quota (https://developers.google.com/analytics/blog/2023/data-api-quota-management).

metric_filter

Example metric_filter arguments:

  1. A simple filter: {"filter":{"field_name":"eventCount","numeric_filter":{"operation":"GREATER_THAN","value":{"int64_value":"10"}}}}

  2. A NOT filter: {"not_expression":{"filter":{"field_name":"eventCount","numeric_filter":{"operation":"GREATER_THAN","value":{"int64_value":"10"}}}}}

  3. An empty value filter: {"filter":{"field_name":"purchaseRevenue","empty_filter":{}}}

  4. An AND group filter: {"and_group":{"expressions":[{"filter":{"field_name":"eventCount","numeric_filter":{"operation":"GREATER_THAN","value":{"int64_value":"10"}}}},{"filter":{"field_name":"purchaseRevenue","between_filter":{"from_value":{"double_value":10},"to_value":{"double_value":25}}}}]}}

  5. An OR group filter: {"or_group":{"expressions":[{"filter":{"field_name":"eventCount","numeric_filter":{"operation":"GREATER_THAN","value":{"int64_value":"10"}}}},{"filter":{"field_name":"purchaseRevenue","between_filter":{"from_value":{"double_value":10},"to_value":{"double_value":25}}}}]}}

Notes: The API applies dimension_filter and metric_filter independently, so some combinations are impossible in one request, e.g. ((eventName = "page_view" AND eventCount > 100) OR (eventName = "join_group" AND eventCount < 50)). For conditions shaped ((D1 AND M1) OR (D2 AND M2)) either: a) run one report filtering on the supported subset (eventName in ["page_view","join_group"]) with eventCount included, and apply the metric conditions to the rows yourself; or b) run one report per (dimension condition, metric condition) pair. Prefer (a) — fewer reports — unless it would use excessive quota (https://developers.google.com/analytics/blog/2023/data-api-quota-management).

order_bys

Example order_bys arguments:

  1. Ascending 'eventName': [ {"dimension":{"dimension_name":"eventName","order_type":"ALPHANUMERIC"},"desc":false} ]

  2. Descending 'campaignName', ignoring case: [ {"dimension":{"dimension_name":"campaignName","order_type":"CASE_INSENSITIVE_ALPHANUMERIC"},"desc":true} ]

  3. Ascending 'audienceId' (numeric): [ {"dimension":{"dimension_name":"audienceId","order_type":"NUMERIC"},"desc":false} ]

  4. Descending 'eventCount': [ {"metric":{"metric_name":"eventCount"},"desc":true} ]

  5. Ascending 'eventCount': [ {"metric":{"metric_name":"eventCount"},"desc":false} ]

  6. Dimension and metric combined: [ {"dimension":{"dimension_name":"eventName","order_type":"ALPHANUMERIC"},"desc":false}, {"metric":{"metric_name":"eventCount"},"desc":true} ]

  7. Several dimensions and metrics: [ {"dimension":{"dimension_name":"eventName","order_type":"ALPHANUMERIC"},"desc":false}, {"dimension":{"dimension_name":"audienceId","order_type":"NUMERIC"},"desc":false}, {"metric":{"metric_name":"eventCount"},"desc":true} ] The dimensions and metrics in order_bys must also be in the request's dimensions and metrics.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax rows per response, 1-250000. Paginate with offset.
offsetNoRow count of the start row (first row is 0).
metricsYes
order_bysNoData API OrderBy objects; every field named must be in dimensions/metrics.
dimensionsYes
property_idYesThe Google Analytics property ID: a number, or 'properties/' followed by a number. Use get_account_summaries to find it.
metric_filterNoData API FilterExpression on metrics. Don't use it for dimensions; use dimension_filter.
dimension_filterNoData API FilterExpression on dimensions. Don't use it for metrics; use metric_filter.
return_property_quotaNoInclude the property's quota usage in the response.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does substantial work: it discloses the 30-minute window, mutual exclusivity of custom metrics, the independence of dimension_filter and metric_filter, and quota implications with a link. It stops short of describing response shape or pagination behavior, which matters for a tool with no output schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Headings front-load the important material and the examples are genuinely useful, but the Notes block under dimension_filter is reproduced verbatim under metric_filter, wasting roughly a third of the text. An agent must read past duplicated prose to reach order_bys.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 9-parameter, nested-object tool with no output schema and no annotations, the description covers the hard parts (filter semantics, ordering rules, realtime restrictions). Remaining gaps are pagination and response format, both of which the schema only partially covers.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 78%, yet the description adds real meaning for the four complex parameters (dimensions, metrics, dimension_filter, metric_filter, order_bys) via five worked examples each and the constraint that order_bys fields must also appear in dimensions/metrics. It adds nothing for limit, offset, or return_property_quota, which the schema already documents.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Runs a Google Analytics Data API realtime report') plus the defining scope ('roughly the last 30 minutes'), which cleanly separates it from the sibling run_report (historical). An agent can pick it without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear operational constraints: realtime dimensions only (plus 'customUser:' custom dimensions from get_custom_dimensions_and_metrics), realtime metrics only, and no custom metrics. It also explains how to handle impossible filter combinations and which workaround to prefer. It never explicitly contrasts with run_report, so the alternative-selection guidance is implied rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

run_reportA

Runs a Google Analytics Data API report (sessions, users, page views, events, revenue, and so on).

Rows come back flattened: one object per row keyed by dimension and metric name, metrics as numbers.

dimensions

Standard dimensions (https://developers.google.com/analytics/devguides/reporting/data/v1/api-schema#dimensions) available to every property, or the property's custom dimensions from get_custom_dimensions_and_metrics.

metrics

Standard metrics (https://developers.google.com/analytics/devguides/reporting/data/v1/api-schema#metrics) available to every property, or the property's custom metrics from get_custom_dimensions_and_metrics.

date_ranges

Example date_ranges arguments:

  1. A single date range: [ {"start_date":"2025-01-01","end_date":"2025-01-31","name":"Jan2025"} ]

  2. A relative date range using 'yesterday' and 'today': [ {"start_date":"yesterday","end_date":"today","name":"YesterdayAndToday"} ]

  3. A relative date range using 'NdaysAgo': [ {"start_date":"30daysAgo","end_date":"yesterday","name":"Previous30Days"} ]

  4. Multiple date ranges (adds a 'dateRange' column to every row): [ {"start_date":"2025-01-01","end_date":"2025-01-31","name":"Jan2025"}, {"start_date":"2025-02-01","end_date":"2025-02-28","name":"Feb2025"} ]

dimension_filter

Example dimension_filter arguments:

  1. A simple filter: {"filter":{"field_name":"eventName","string_filter":{"match_type":"BEGINS_WITH","value":"add"}}}

  2. A NOT filter: {"not_expression":{"filter":{"field_name":"eventName","string_filter":{"match_type":"BEGINS_WITH","value":"add"}}}}

  3. An empty value filter: {"filter":{"field_name":"source","empty_filter":{}}}

  4. An AND group filter: {"and_group":{"expressions":[{"filter":{"field_name":"sourceMedium","string_filter":{"match_type":"EXACT","value":"google / cpc"}}},{"filter":{"field_name":"eventName","in_list_filter":{"case_sensitive":true,"values":["first_visit","purchase","add_to_cart"]}}}]}}

  5. An OR group filter: {"or_group":{"expressions":[{"filter":{"field_name":"sourceMedium","string_filter":{"match_type":"EXACT","value":"google / cpc"}}},{"filter":{"field_name":"eventName","in_list_filter":{"case_sensitive":true,"values":["first_visit","purchase","add_to_cart"]}}}]}}

Notes: The API applies dimension_filter and metric_filter independently, so some combinations are impossible in one request, e.g. ((eventName = "page_view" AND eventCount > 100) OR (eventName = "join_group" AND eventCount < 50)). For conditions shaped ((D1 AND M1) OR (D2 AND M2)) either: a) run one report filtering on the supported subset (eventName in ["page_view","join_group"]) with eventCount included, and apply the metric conditions to the rows yourself; or b) run one report per (dimension condition, metric condition) pair. Prefer (a) — fewer reports — unless it would use excessive quota (https://developers.google.com/analytics/blog/2023/data-api-quota-management).

metric_filter

Example metric_filter arguments:

  1. A simple filter: {"filter":{"field_name":"eventCount","numeric_filter":{"operation":"GREATER_THAN","value":{"int64_value":"10"}}}}

  2. A NOT filter: {"not_expression":{"filter":{"field_name":"eventCount","numeric_filter":{"operation":"GREATER_THAN","value":{"int64_value":"10"}}}}}

  3. An empty value filter: {"filter":{"field_name":"purchaseRevenue","empty_filter":{}}}

  4. An AND group filter: {"and_group":{"expressions":[{"filter":{"field_name":"eventCount","numeric_filter":{"operation":"GREATER_THAN","value":{"int64_value":"10"}}}},{"filter":{"field_name":"purchaseRevenue","between_filter":{"from_value":{"double_value":10},"to_value":{"double_value":25}}}}]}}

  5. An OR group filter: {"or_group":{"expressions":[{"filter":{"field_name":"eventCount","numeric_filter":{"operation":"GREATER_THAN","value":{"int64_value":"10"}}}},{"filter":{"field_name":"purchaseRevenue","between_filter":{"from_value":{"double_value":10},"to_value":{"double_value":25}}}}]}}

Notes: The API applies dimension_filter and metric_filter independently, so some combinations are impossible in one request, e.g. ((eventName = "page_view" AND eventCount > 100) OR (eventName = "join_group" AND eventCount < 50)). For conditions shaped ((D1 AND M1) OR (D2 AND M2)) either: a) run one report filtering on the supported subset (eventName in ["page_view","join_group"]) with eventCount included, and apply the metric conditions to the rows yourself; or b) run one report per (dimension condition, metric condition) pair. Prefer (a) — fewer reports — unless it would use excessive quota (https://developers.google.com/analytics/blog/2023/data-api-quota-management).

order_bys

Example order_bys arguments:

  1. Ascending 'eventName': [ {"dimension":{"dimension_name":"eventName","order_type":"ALPHANUMERIC"},"desc":false} ]

  2. Descending 'campaignName', ignoring case: [ {"dimension":{"dimension_name":"campaignName","order_type":"CASE_INSENSITIVE_ALPHANUMERIC"},"desc":true} ]

  3. Ascending 'audienceId' (numeric): [ {"dimension":{"dimension_name":"audienceId","order_type":"NUMERIC"},"desc":false} ]

  4. Descending 'eventCount': [ {"metric":{"metric_name":"eventCount"},"desc":true} ]

  5. Ascending 'eventCount': [ {"metric":{"metric_name":"eventCount"},"desc":false} ]

  6. Dimension and metric combined: [ {"dimension":{"dimension_name":"eventName","order_type":"ALPHANUMERIC"},"desc":false}, {"metric":{"metric_name":"eventCount"},"desc":true} ]

  7. Several dimensions and metrics: [ {"dimension":{"dimension_name":"eventName","order_type":"ALPHANUMERIC"},"desc":false}, {"dimension":{"dimension_name":"audienceId","order_type":"NUMERIC"},"desc":false}, {"metric":{"metric_name":"eventCount"},"desc":true} ] The dimensions and metrics in order_bys must also be in the request's dimensions and metrics.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax rows per response, 1-250000. Paginate with offset.
offsetNoRow count of the start row (first row is 0).
metricsYes
order_bysNoData API OrderBy objects; every field named must be in dimensions/metrics.
dimensionsYes
date_rangesYesDate ranges: [{start_date, end_date, name?}]. Dates are YYYY-MM-DD, 'today', 'yesterday' or 'NdaysAgo'.
property_idYesThe Google Analytics property ID: a number, or 'properties/' followed by a number. Use get_account_summaries to find it.
currency_codeNoISO 4217, e.g. SEK. Defaults to the property's currency.
metric_filterNoData API FilterExpression on metrics. Don't use it for dimensions; use dimension_filter.
dimension_filterNoData API FilterExpression on dimensions. Don't use it for metrics; use metric_filter.
return_property_quotaNoInclude the property's quota usage in the response.

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does well: it discloses the flattened row shape ('one object per row keyed by dimension and metric name, metrics as numbers'), the multi-date-range behavior (adds a 'dateRange' column), the independent-application quirk of the two filters, and a quota warning with a link. It does not state auth/permission requirements explicitly, though the read-only nature is strongly implied by 'runs a report'.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with a one-line purpose and organized under headers, which is good. However, the identical multi-line 'Notes:' block about independent dimension_filter/metric_filter application is duplicated verbatim under both sections, wasting roughly ten lines, and the sheer length is disproportionate for routine calls.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an 11-parameter tool with no output schema, the description covers return shape, the complex filter/ordering/date semantics, quota implications, and pagination (via the schema's limit/offset). What is missing is comparatively minor: auth/permission expectations and any note on maximum result scaling beyond the quota link.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 82%, so the baseline would be 3, but the description goes well beyond the schema with concrete worked examples for the four hardest parameters (date_ranges, dimension_filter, metric_filter, order_bys), including relative dates, AND/OR/NOT groups, and numeric/between filters. It also warns that order_bys fields must also appear in dimensions/metrics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Runs a Google Analytics Data API report', with illustrative metrics (sessions, users, page views, events, revenue). It does not distinguish itself from the siblings run_realtime_report, run_funnel_report, or run_conversions_report, so an agent must infer that this is the general-purpose reporting tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no explicit routing guidance against the sibling report tools, only an implied 'general report' role. The description does give real operational guidance for a tricky case (that dimension_filter and metric_filter apply independently, with two workarounds and a preference for option (a) to conserve quota), which raises it above a bare 2.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 9 tool updatesv0.1.0
    • First observedget_account_summaries
    • First observedget_custom_dimensions_and_metrics
    • First observedget_property_details
    • First observedlist_google_ads_links
    • First observedlist_property_annotations
    • First observedrun_conversions_report
    • First observedrun_funnel_report
    • First observedrun_realtime_report
    • First observedrun_report

TDQS

A3.7/5.0

Scored across 9 tools

Disambiguation4/5

Most tools are clearly distinct, but run_report vs run_conversions_report overlap in scope and the description has to explicitly say 'USE THIS TOOL INSTEAD OF run_report WHEN...' to disambiguate. run_realtime_report, run_funnel_report, and the get_/list_ discovery tools are cleanly separated, so only one boundary is fuzzy and it is well-documented.

Naming Consistency4/5

All tools follow a predictable verb_noun pattern (get_*, list_*, run_*), which is readable and consistent. The only weakness is that the generic run_report lacks a qualifier like run_standard_report, making it slightly ambiguous against run_realtime_report/run_funnel_report/run_conversions_report.

Tool Count5/5

Nine tools is well-scoped for a GA4 reporting server: five read/discovery tools plus four report runners covering the main Data API report shapes. No tool feels redundant or padded.

Completeness4/5

The surface covers discovery (accounts, property, ads links, annotations, custom dims/metrics) and all major report types (standard, realtime, funnel, conversions), so core analytical workflows are fully reachable. Minor gaps remain: no pivot or batch-run report equivalents and no annotation write operations.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    Enables querying Google Analytics 4 properties using natural language through MCP clients. Supports customizable reports with any dimensions and metrics, listing properties, and real-time data.
    4
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables querying Google Analytics 4 data through MCP tools for running reports, listing properties, getting real-time metrics, and exploring metadata.
    14 npm
    MIT
  • A
    license
    B
    quality
    B
    maintenance
    Enables read-only Google Analytics 4 reporting through MCP, including daily summaries, top pages, acquisition, events, realtime activity, metadata, and custom reports with CSV/JSON output.
    8
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Enables read-only access to Google Analytics 4 data through seventeen tools covering reports, realtime data, funnels, pivots, metadata, and admin lists. It runs locally with service account credentials and lets users query properties via standard MCP clients.
    17
    35 PyPI
    MIT