Skip to main content
Glama
Walma-Labs

ga4-mcp

by Walma-Labs

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
PORTNoPort for the HTTP entrypoint (default 8080).8080
GA4_SERVICE_ACCOUNT_FILENoPath to the service-account JSON key (`~` is expanded).
GA4_SERVICE_ACCOUNT_JSONNoThe service-account key as inline JSON. Wins over the file when both are set.

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": true
}

Tools

Functions exposed to the LLM to take actions

NameDescription
get_account_summariesA

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

get_property_detailsB

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

list_google_ads_linksC

List the Google Ads accounts linked to a property.

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.

get_custom_dimensions_and_metricsA

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

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.

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.

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"} ]

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.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

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