ga4-mcp
Lists Google Ads links associated with GA4 properties.
Provides access to Google Analytics 4 data, including property metadata, custom dimensions and metrics, standard and real-time reports, property annotations, and account summaries.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ga4-mcpwhat were my top pages by views in the last 7 days?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
ga4-mcp
Production-grade MCP server for Google Analytics 4 — self-hosted, token-secured, Claude-connector-ready.
A Model Context Protocol server that gives Claude, ChatGPT, Cursor, and any other MCP client direct access to your GA4 data — property metadata, custom dimensions and metrics, run_report (the full Data API surface), real-time reporting, property annotations, and Google Ads link inventories.
Built for remote deployment behind a reverse proxy: streamable-HTTP transport, token-gated auth, CORS, the path-rewrite fix that makes the Claude web connector actually load, and explicit prompts/resources capability declarations in the initialize response.
Highlights
Three transports —
stdio(Claude Desktop),sse(legacy remote), andstreamable-httpat/mcp(current spec, what the Claude web connector expects)Bare
/mcpworks — no 307 →http://redirect that Claude's connector refuses to followToken auth via 4 paths —
?token=,Authorization: Bearer,X-Api-Key,Mcp-Auth-TokenCORS for browser-based MCP clients — wildcard origins by default, restrict via env
No-compress middleware — Claude's web connector breaks on brotli-compressed event streams
prompts+resourcescapabilities declared in initialize — without this Claude's validator rejects the server/healthzendpoint for liveness probes.envloading viapython-dotenvproxy_headers=Trueso X-Forwarded-Proto is respected when behind Traefik/CaddyPure-ASGI path rewriter (bare
/mcp→/mcp/) — solved at scope level, before routing
The non-obvious bugs this server already solves
Bare
/mcpreturned 307 tohttp://. Starlette'sMount("/mcp", X)regex requires a trailing slash, so a bare POST/mcpfalls through to a 307 redirect. Worse, Traefik terminating TLS doesn't always rewrite the Location header back tohttps://— so Claude's connector validator got anhttp://redirect and rejected it with "Couldn't reach the MCP server". Fix: pure-ASGI middleware rewritesscope["path"]from/mcpto/mcp/before the router sees it. Alsoproxy_headers=Trueon uvicorn so any future redirect stays HTTPS.Missing capability blocks in initialize. Claude's connector validator rejects servers whose initialize response omits the
promptsorresourcescapability — even when the server has nothing to offer in those slots. FastMCP-based servers escape this because their wrapper registers default handlers, but a baremcp.server.lowlevel.Serveronly declares a capability when at least one handler is registered for it. Fix: register emptylist_prompts/list_resources/list_resource_templateshandlers so the initialize response declares all four blocks (experimental,prompts,resources,tools).
If you've ever spent an afternoon debugging "Couldn't reach the MCP server" with a working curl, these are the two fixes you needed.
Related MCP server: ga-mcp-full
Tool surface — 7 tools
get_account_summaries · list_google_ads_links · get_property_details · list_property_annotations · get_custom_dimensions_and_metrics · run_report · run_realtime_report
Tool surface mirrors the public Google Analytics MCP spec — the work here is in transport, auth, and deploy-ability, not in changing tool behavior.
Quick start — local (Claude Desktop)
git clone https://github.com/thesyedyahya/ga4-mcp.git
cd ga4-mcp
uv venv .venv
uv pip install -e .
export GOOGLE_APPLICATION_CREDENTIALS=/abs/path/to/service-account.json
analytics-mcpIn ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"ga4": {
"command": "/abs/path/to/.venv/bin/analytics-mcp",
"env": {
"GOOGLE_APPLICATION_CREDENTIALS": "/abs/path/to/service-account.json"
}
}
}
}Quick start — remote (Docker / Dokploy / any VPS)
docker build -t ga4-mcp .
docker run -d -p 8080:8080 \
-e GOOGLE_APPLICATION_CREDENTIALS_JSON="$(cat service-account.json | python3 -c 'import json,sys;print(json.dumps(json.load(sys.stdin)))')" \
-e MCP_AUTH_TOKEN="$(openssl rand -hex 32)" \
-e MCP_ALLOWED_ORIGINS="*" \
ga4-mcpPut Caddy/Traefik in front for HTTPS, point a domain at it, then add the connector in Claude:
https://mcp-ga4.example.com/mcp?token=<your-token>Auth setup
The service account must be added as a Viewer (or higher) on each GA4 property you want to query — not just at the account level. If get_account_summaries returns 0 properties, the SA is on the account but not on any properties.
GCP Console → IAM & Admin → Service Accounts → Create + JSON key
Google Analytics → Admin → Property access management → Add user → enter the SA email → Viewer
Repeat for each property the MCP should access
Set
GOOGLE_APPLICATION_CREDENTIALS(local) orGOOGLE_APPLICATION_CREDENTIALS_JSON(Docker)
Environment variables
Variable | Required | Default | Description |
| local | — | Absolute path to SA JSON |
| container | — | Single-line SA JSON. Entrypoint decodes to a file. |
| No |
|
|
| No |
| Bind host |
| No |
| Bind port |
| Public deploy | — | If unset, server runs open |
| No |
| CORS allowlist (token gates access) |
Sample prompts
After connecting:
"List my GA4 properties and their key timezones."
"Run a 28-day report on property
properties/XXXXX— sessions, conversions, average engagement time, broken down by source/medium.""Show me the last hour of users on property
properties/XXXXX, broken down by country.""List custom dimensions and metrics on
properties/XXXXX. Which are unused in the last 30 days?"
License
Apache 2.0. See LICENSE.
About
Maintained by @thesyedyahya — I build production MCP servers for Claude, ChatGPT, and Cursor. If you need a custom MCP for your API or help deploying one, open an issue or reach me on Upwork or Fiverr.
Available Tools
7 toolsget_account_summariesGet Account SummariesB
Retrieves information about the user's Google Analytics accounts and properties.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It only implies a read-only operation via 'Retrieves' but does not mention permissions, pagination, rate limits, or any side effects. This is minimal disclosure for a tool that likely fetches a list of accounts and properties.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence with no wasted words. It is front-loaded with the action and clearly states the resource. It is appropriately concise for a tool with no parameters and no complex logic.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given that the tool has no parameters and an output schema exists (which likely describes the returned summary structure), the description is largely complete for its purpose. It clearly identifies the domain (Google Analytics accounts and properties). A slight gap is that 'summaries' is vague, but the output schema should resolve this. Overall, adequate for a simple read-only listing tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the schema coverage is 100% vacuously. According to the rubric, a 0-parameter tool receives a baseline score of 4. The description does not need to explain parameters, and it appropriately omits any parameter details.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Retrieves') and a clear resource ('the user's Google Analytics accounts and properties'). It is not a tautology and conveys the primary function. However, it does not explicitly differentiate itself from sibling tools like get_property_details, which also deals with properties, leaving some ambiguity about the scope of 'summaries'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no guidance on when to use this tool versus alternatives. It does not mention any distinguishing conditions, such as when to use get_property_details for a single property instead. This is a clear gap for an agent trying to select the appropriate tool.
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_metricsGet Custom Dimensions And MetricsB
Returns the property's custom dimensions and metrics.
| Name | Required | Description | Default |
|---|---|---|---|
| property_id | Yes | The Google Analytics property ID. Accepted formats are: - A number - A string consisting of 'properties/' followed by a number |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure. It only states 'returns' without explicitly noting read-only behavior, permissions, error handling, or rate limits. The sparse wording leaves the agent without important context for a non-trivial operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence with no filler, front-loading the core purpose. Every word is necessary and it is appropriately sized for a simple tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple with one well-documented parameter and an output schema, so the description does not need to explain return values. However, it lacks any usage context or mention of when to call it, which is a gap given the sibling tools. It is minimally complete but not comprehensive.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description does not mention the parameter at all, but the schema provides a detailed description of property_id with accepted formats, achieving 100% coverage. Baseline is 3 since the schema fully documents the parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Returns') and resource ('the property's custom dimensions and metrics'), making the tool's function clear. It is distinct from siblings like get_account_summaries or run_report, which have different purposes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance is provided on when to use this tool versus alternatives. The description does not mention conditions, prerequisites, or exclusions, leaving the agent to infer usage from the name alone.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_property_detailsGet Property DetailsA
Returns details about a property. Args: property_id: The Google Analytics property ID. Accepted formats are: - A number - A string consisting of 'properties/' followed by a number
| Name | Required | Description | Default |
|---|---|---|---|
| property_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must carry behavioral context. 'Returns details' implies a read-only operation)Skip no mutation is signaledasi. Still, it does not disclose authorization needs, rate limits, or any side effects. This is adequate for a simple getter but not rich.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is short, front-loaded with the core purpose, and uses a compact bullet list for the parameter formats. Every sentence contributes useful information with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter getter with an output schema present, the description is largely complete: it defines the purpose and the exact accepted parameter formats. The main missing piece is usage/alternative context, but that is not essential for a straightforward read operation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema only states that property_id can be an integer or string. The description adds meaningful detail by specifying the accepted formats, including the 'properties/' prefix form. This fully covers the single parameter and goes beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific verb and resource: 'Returns details about a property.' It is distinct from sibling tools like run_report or list_google_ads_links. However, 'details' is somewhat vague and could be more explicit about what information is included.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no guidance about when to use this tool versus alternatives. It does not mention exclusions, prerequisites, or scenarios where a sibling tool would be more appropriate, so an agent must infer usage from the name.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_google_ads_linksList Google Ads LinksA
Returns a list of links to Google Ads accounts for a property.
| Name | Required | Description | Default |
|---|---|---|---|
| property_id | Yes | The Google Analytics property ID. Accepted formats are: - A number - A string consisting of 'properties/' followed by a number |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral burden. Saying 'Returns a list' signals a read-style operation and the property scoping is useful, but it does not disclose other traits such as whether links have statuses, whether filtering exists, or whether any authentication nuance applies.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single sentence with no wasted words. The action, object, and scope are immediately clear.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple one-parameter list tool with an output schema, the description is nearly sufficient. It may lack explicit alternatives and deeper behavioral nuance, but these are minor given the tool's low complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the only parameter, property_id, is well documented with accepted formats. The description adds little beyond reinforcing that the list is scoped to a property, so the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Returns a list of') and names the resource ('links to Google Ads accounts') and scope ('for a property'). It is clear, though it doesn't explicitly differentiate from sibling tools like get_account_summaries or get_property_details.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies the tool should be used when a list of Google Ads links for a property is needed. It does not provide explicit guidance about when to prefer it over alternatives or when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_property_annotationsList Property AnnotationsA
Returns annotations for a property.
Annotations are a feature that allows you to leave notes on GA4 for specific dates or periods. They are typically used to record service releases, marketing campaign launches or changes, and rapid traffic increases or decreases due to external factors.
| Name | Required | Description | Default |
|---|---|---|---|
| property_id | Yes | The Google Analytics property ID. Accepted formats are: - A number - A string consisting of 'properties/' followed by a number |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
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 clearly implies a read operation with 'Returns,' and the explanation of annotations adds domain context. It does not disclose pagination, authorization requirements, error behavior, or explicitly state it is read-only, but it is not misleading.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and front-loaded with the core purpose in the first sentence. The additional sentences provide useful domain context about annotations without excessive fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple one-parameter tool with a rich input schema and an output schema, the description covers purpose and domain context effectively. It lacks mention of pagination or permissions, but these are not critical given the tool's simplicity and the presence of an output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with the property_id parameter fully documented including accepted formats. The description adds no additional parameter semantics, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Returns annotations for a property.' The resource is distinct from sibling tools such as run_report or get_property_details, but no explicit differentiation is made.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains what annotations are and typical use cases (service releases, marketing campaigns, traffic changes), which implies when this tool might be useful. However, it does not explicitly state when to use this tool versus alternatives or provide any exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
run_realtime_reportRun Realtime ReportA
Runs a Google Analytics Data API realtime report.See https://developers.google.com/analytics/devguides/reporting/data/v1/realtime-basics for more information.
Args:
property_id: The Google Analytics property ID. Accepted formats are:
- A number
- A string consisting of 'properties/' followed by a number
dimensions: A list of dimensions to include in the report. Dimensions must be realtime dimensions.
metrics: A list of metrics to include in the report. Metrics must be realtime metrics.
dimension_filter: A Data API FilterExpression
(https://developers.google.com/analytics/devguides/reporting/data/v1/rest/v1beta/FilterExpression)
to apply to the dimensions. Don't use this for filtering metrics. Use
metric_filter instead. The field_name in a dimension_filter must
be a dimension, as defined in the get_standard_dimensions and
get_dimensions tools.
For more information about the expected format of this argument, see
the run_report_dimension_filter_hints tool.
metric_filter: A Data API FilterExpression
(https://developers.google.com/analytics/devguides/reporting/data/v1/rest/v1beta/FilterExpression)
to apply to the metrics. Don't use this for filtering dimensions. Use
dimension_filter instead. The field_name in a metric_filter must
be a metric, as defined in the get_standard_metrics and
get_metrics tools.
For more information about the expected format of this argument, see
the run_report_metric_filter_hints tool.
order_bys: A list of Data API OrderBy
(https://developers.google.com/analytics/devguides/reporting/data/v1/rest/v1beta/OrderBy)
objects to apply to the dimensions and metrics.
For more information about the expected format of this argument, see
the run_report_order_bys_hints tool.
limit: The maximum number of rows to return in each response. Value must
be a positive integer <= 250,000. Used to paginate through large
reports, following the guide at
https://developers.google.com/analytics/devguides/reporting/data/v1/basics#pagination.
offset: The row count of the start row. The first row is counted as row
0. Used to paginate through large
reports, following the guide at
https://developers.google.com/analytics/devguides/reporting/data/v1/basics#pagination.
return_property_quota: Whether to return realtime property quota in the response.
## Hints for arguments
Here are some hints that outline the expected format and requirements
for arguments.
### Hints for `dimensions`
The `dimensions` list must consist solely of either of the following:
1. Realtime standard dimensions defined in the HTML table at
https://developers.google.com/analytics/devguides/reporting/data/v1/realtime-api-schema#dimensions.
These dimensions are available to *every* property.
2. User-scoped custom dimensions for the `property_id`. Use the
`get_custom_dimensions_and_metrics` tool to retrieve the list of
custom dimensions for a property, and look for the custom
dimensions with an `apiName` that begins with "customUser:".
### Hints for `metrics`
The `metrics` list must consist solely of the Realtime standard
metrics defined in the HTML table at
https://developers.google.com/analytics/devguides/reporting/data/v1/realtime-api-schema#metrics.
These metrics are available to *every* property.
Realtime reports can't use custom metrics.
### Hints for `date_ranges`:
Example date_range 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' and 'today':
[ {"start_date": "30daysAgo", "end_date": "yesterday", "name": "Previous30Days"}]
4. Multiple date ranges:
[ {"start_date": "2025-01-01", "end_date": "2025-01-31", "name": "Jan2025"}, {"start_date": "2025-02-01", "end_date": "2025-02-28", "name": "Feb2025"} ]
### Hints for `dimension_filter`:
Example dimension_filter arguments:
1. A simple filter:
{"filter": {"field_name": "eventName", "string_filter": {"match_type": 2, "value": "add", "case_sensitive": false}}}
2. A NOT filter:
{"not_expression": {"filter": {"field_name": "eventName", "string_filter": {"match_type": 2, "value": "add", "case_sensitive": false}}}}
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": 1, "value": "google / cpc", "case_sensitive": false}}}, {"filter": {"field_name": "eventName", "in_list_filter": {"values": ["first_visit", "purchase", "add_to_cart"], "case_sensitive": true}}}]}}
5. An OR group filter:
{"or_group": {"expressions": [{"filter": {"field_name": "sourceMedium", "string_filter": {"match_type": 1, "value": "google / cpc", "case_sensitive": false}}}, {"filter": {"field_name": "eventName", "in_list_filter": {"values": ["first_visit", "purchase", "add_to_cart"], "case_sensitive": true}}}]}} Notes:
The API applies the dimension_filter and metric_filter
independently. As a result, some complex combinations of dimension and
metric filters are not possible in a single report request.
For example, you can't create a `dimension_filter` and `metric_filter`
combination for the following condition:
(
(eventName = "page_view" AND eventCount > 100)
OR
(eventName = "join_group" AND eventCount < 50)
)
This isn't possible because there's no way to apply the condition
"eventCount > 100" only to the data with eventName of "page_view", and
the condition "eventCount < 50" only to the data with eventName of
"join_group".
More generally, you can't define a `dimension_filter` and `metric_filter`
for:
(
((dimension condition D1) AND (metric condition M1))
OR
((dimension condition D2) AND (metric condition M2))
)
If you have complex conditions like this, either:
a) Run a single report that applies a subset of the conditions that
the API supports as well as the data needed to perform filtering of the
API response on the client side. For example, for the condition:
(
(eventName = "page_view" AND eventCount > 100)
OR
(eventName = "join_group" AND eventCount < 50)
)
You could run a report that filters only on:
eventName one of "page_view" or "join_group"
and include the eventCount metric, then filter the API response on the
client side to apply the different metric filters for the different
events.
or
b) Run a separate report for each combination of dimension condition and
metric condition. For the example above, you'd run one report for the
combination of (D1 AND M1), and another report for the combination of
(D2 AND M2).
Try to run fewer reports (option a) if possible. However, if running
fewer reports results in excessive quota usage for the API, use option
b. More information on quota usage is at
https://developers.google.com/analytics/blog/2023/data-api-quota-management.
### Hints for `metric_filter`:
Example metric_filter arguments:
1. A simple filter:
{"filter": {"field_name": "eventCount", "numeric_filter": {"operation": 4, "value": {"int64_value": "10"}}}}
2. A NOT filter:
{"not_expression": {"filter": {"field_name": "eventCount", "numeric_filter": {"operation": 4, "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": 4, "value": {"int64_value": "10"}}}}, {"filter": {"field_name": "purchaseRevenue", "between_filter": {"from_value": {"double_value": 10.0}, "to_value": {"double_value": 25.0}}}}]}}
5. An OR group filter:
{"or_group": {"expressions": [{"filter": {"field_name": "eventCount", "numeric_filter": {"operation": 4, "value": {"int64_value": "10"}}}}, {"filter": {"field_name": "purchaseRevenue", "between_filter": {"from_value": {"double_value": 10.0}, "to_value": {"double_value": 25.0}}}}]}} Notes:
The API applies the dimension_filter and metric_filter
independently. As a result, some complex combinations of dimension and
metric filters are not possible in a single report request.
For example, you can't create a `dimension_filter` and `metric_filter`
combination for the following condition:
(
(eventName = "page_view" AND eventCount > 100)
OR
(eventName = "join_group" AND eventCount < 50)
)
This isn't possible because there's no way to apply the condition
"eventCount > 100" only to the data with eventName of "page_view", and
the condition "eventCount < 50" only to the data with eventName of
"join_group".
More generally, you can't define a `dimension_filter` and `metric_filter`
for:
(
((dimension condition D1) AND (metric condition M1))
OR
((dimension condition D2) AND (metric condition M2))
)
If you have complex conditions like this, either:
a) Run a single report that applies a subset of the conditions that
the API supports as well as the data needed to perform filtering of the
API response on the client side. For example, for the condition:
(
(eventName = "page_view" AND eventCount > 100)
OR
(eventName = "join_group" AND eventCount < 50)
)
You could run a report that filters only on:
eventName one of "page_view" or "join_group"
and include the eventCount metric, then filter the API response on the
client side to apply the different metric filters for the different
events.
or
b) Run a separate report for each combination of dimension condition and
metric condition. For the example above, you'd run one report for the
combination of (D1 AND M1), and another report for the combination of
(D2 AND M2).
Try to run fewer reports (option a) if possible. However, if running
fewer reports results in excessive quota usage for the API, use option
b. More information on quota usage is at
https://developers.google.com/analytics/blog/2023/data-api-quota-management.
### Hints for `order_bys`:
Example order_bys arguments:
1. Order by ascending 'eventName':
[ {"dimension": {"dimension_name": "eventName", "order_type": 1}, "desc": false} ]
2. Order by descending 'eventName', ignoring case:
[ {"dimension": {"dimension_name": "campaignName", "order_type": 2}, "desc": true} ]
3. Order by ascending 'audienceId':
[ {"dimension": {"dimension_name": "audienceId", "order_type": 3}, "desc": false} ]
4. Order by descending 'eventCount':
[ {"metric": {"metric_name": "eventValue"}, "desc": true} ]
5. Order by ascending 'eventCount':
[ {"metric": {"metric_name": "eventCount"}, "desc": false} ]
6. Combination of dimension and metric order bys:
[
{"dimension": {"dimension_name": "eventName", "order_type": 1}, "desc": false},
{"metric": {"metric_name": "eventValue"}, "desc": true},
]
7. Order by multiple dimensions and metrics:
[
{"dimension": {"dimension_name": "eventName", "order_type": 1}, "desc": false},
{"dimension": {"dimension_name": "audienceId", "order_type": 3}, "desc": false},
{"metric": {"metric_name": "eventValue"}, "desc": true},
]
The dimensions and metrics in order_bys must also be present in the report
request's "dimensions" and "metrics" arguments, respectively.| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | The maximum number of rows to return in each response. Value must be a positive integer <= 250,000. Used to paginate through large reports, following the guide at https://developers.google.com/analytics/devguides/reporting/data/v1/basics#pagination. | |
| offset | No | The row count of the start row. The first row is counted as row 0. Used to paginate through large reports, following the guide at https://developers.google.com/analytics/devguides/reporting/data/v1/basics#pagination. | |
| metrics | Yes | A list of metrics to include in the report. Metrics must be realtime metrics. | |
| order_bys | No | A list of Data API OrderBy (https://developers.google.com/analytics/devguides/reporting/data/v1/rest/v1beta/OrderBy) objects to apply to the dimensions and metrics. For more information about the expected format of this argument, see the `run_report_order_bys_hints` tool. | |
| dimensions | Yes | A list of dimensions to include in the report. Dimensions must be realtime dimensions. | |
| property_id | Yes | The Google Analytics property ID. Accepted formats are: - A number - A string consisting of 'properties/' followed by a number | |
| metric_filter | No | A Data API FilterExpression (https://developers.google.com/analytics/devguides/reporting/data/v1/rest/v1beta/FilterExpression) to apply to the metrics. Don't use this for filtering dimensions. Use dimension_filter instead. The `field_name` in a `metric_filter` must be a metric, as defined in the `get_standard_metrics` and `get_metrics` tools. For more information about the expected format of this argument, see the `run_report_metric_filter_hints` tool. | |
| dimension_filter | No | A Data API FilterExpression (https://developers.google.com/analytics/devguides/reporting/data/v1/rest/v1beta/FilterExpression) to apply to the dimensions. Don't use this for filtering metrics. Use metric_filter instead. The `field_name` in a `dimension_filter` must be a dimension, as defined in the `get_standard_dimensions` and `get_dimensions` tools. For more information about the expected format of this argument, see the `run_report_dimension_filter_hints` tool. | |
| return_property_quota | No | Whether to return realtime property quota in the response. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
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 a key limitation: dimension_filter and metric_filter are applied independently, with detailed examples of what cannot be expressed and workarounds. It also mentions quota management and pagination via limit/offset. However, it omits operational details like realtime data latency (~30 min window) and that the operation is read-only, though these are somewhat implied by the nature of a report. The thorough filter-limitation disclosure elevates this above average.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is very long and contains redundant sections: the identical 'Notes' about filter independence appears twice (once under dimension_filter, once under metric_filter). More problematically, it includes a 'Hints for date_ranges' section even though date_ranges is not a parameter in the schema, which could mislead the agent. The structure is front-loaded with a clear purpose but suffers from repetition and an irrelevant block, reducing efficiency.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with 9 parameters, nested objects, and complex filter logic, the description is highly complete. It covers all parameters with examples, cross-references supporting tools, and provides strategic advice for handling filter limitations. The presence of an output schema means return values don't need explanation. The main gap is the phantom date_ranges hints and a slight lack of explicit realtime data-window constraints, but overall it is thorough enough for an agent to invoke correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although the schema already documents every parameter (100% coverage), the description goes far beyond by providing concrete JSON examples for dimension_filter, metric_filter, and order_bys, and by linking each complex parameter to dedicated hint tools. It clarifies accepted formats for property_id and enforces that dimensions must be realtime dimensions, metrics must be realtime metrics. This is exemplary parameter guidance that adds substantial meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Runs a Google Analytics Data API realtime report.' — a specific verb and resource that immediately distinguishes it from the sibling run_report (standard reporting). The term 'realtime' in the first sentence and in the tool name makes the scope unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
While it doesn't explicitly compare to run_report, the description clearly frames when realtime data is appropriate and guides the agent to supporting tools (get_standard_dimensions, get_custom_dimensions_and_metrics, and the hint tools). It also provides decision guidance for complex filter combinations, offering two strategies and recommending one based on quota. This is more than implied usage, though it stops short of an explicit 'use this instead of X' statement.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
run_reportRun ReportA
Runs a Google Analytics Data API report.Note that the reference docs at https://developers.google.com/analytics/devguides/reporting/data/v1/rest/v1beta all use camelCase field names, but field names passed to this method should be in snake_case since the tool is using the protocol buffers (protobuf) format. The protocol buffers for the Data API are available at https://github.com/googleapis/googleapis/tree/master/google/analytics/data/v1beta.
Args:
property_id: The Google Analytics property ID. Accepted formats are:
- A number
- A string consisting of 'properties/' followed by a number
date_ranges: A list of date ranges
(https://developers.google.com/analytics/devguides/reporting/data/v1/rest/v1beta/DateRange)
to include in the report.
dimensions: A list of dimensions to include in the report.
metrics: A list of metrics to include in the report.
dimension_filter: A Data API FilterExpression
(https://developers.google.com/analytics/devguides/reporting/data/v1/rest/v1beta/FilterExpression)
to apply to the dimensions. Don't use this for filtering metrics. Use
metric_filter instead. The field_name in a dimension_filter must
be a dimension, as defined in the get_standard_dimensions and
get_dimensions tools.
metric_filter: A Data API FilterExpression
(https://developers.google.com/analytics/devguides/reporting/data/v1/rest/v1beta/FilterExpression)
to apply to the metrics. Don't use this for filtering dimensions. Use
dimension_filter instead. The field_name in a metric_filter must
be a metric, as defined in the get_standard_metrics and
get_metrics tools.
order_bys: A list of Data API OrderBy
(https://developers.google.com/analytics/devguides/reporting/data/v1/rest/v1beta/OrderBy)
objects to apply to the dimensions and metrics.
limit: The maximum number of rows to return in each response. Value must
be a positive integer <= 250,000. Used to paginate through large
reports, following the guide at
https://developers.google.com/analytics/devguides/reporting/data/v1/basics#pagination.
offset: The row count of the start row. The first row is counted as row
0. Used to paginate through large
reports, following the guide at
https://developers.google.com/analytics/devguides/reporting/data/v1/basics#pagination.
currency_code: The currency code to use for currency values. Must be in
ISO4217 format, such as "AED", "USD", "JPY". If the field is empty, the
report uses the property's default currency.
return_property_quota: Whether to return property quota in the response.
## Hints for arguments
Here are some hints that outline the expected format and requirements
for arguments.
### Hints for `dimensions`
The `dimensions` list must consist solely of either of the following:
1. Standard dimensions defined in the HTML table at
https://developers.google.com/analytics/devguides/reporting/data/v1/api-schema#dimensions.
These dimensions are available to *every* property.
2. Custom dimensions for the `property_id`. Use the
`get_custom_dimensions_and_metrics` tool to retrieve the list of
custom dimensions for a property.
### Hints for `metrics`
The `metrics` list must consist solely of either of the following:
1. Standard metrics defined in the HTML table at
https://developers.google.com/analytics/devguides/reporting/data/v1/api-schema#metrics.
These metrics are available to *every* property.
2. Custom metrics for the `property_id`. Use the
`get_custom_dimensions_and_metrics` tool to retrieve the list of
custom metrics for a property.
### Hints for `date_ranges`:
Example date_range 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' and 'today':
[ {"start_date": "30daysAgo", "end_date": "yesterday", "name": "Previous30Days"}]
4. Multiple date ranges:
[ {"start_date": "2025-01-01", "end_date": "2025-01-31", "name": "Jan2025"}, {"start_date": "2025-02-01", "end_date": "2025-02-28", "name": "Feb2025"} ]
### Hints for `dimension_filter`:
Example dimension_filter arguments:
1. A simple filter:
{"filter": {"field_name": "eventName", "string_filter": {"match_type": 2, "value": "add", "case_sensitive": false}}}
2. A NOT filter:
{"not_expression": {"filter": {"field_name": "eventName", "string_filter": {"match_type": 2, "value": "add", "case_sensitive": false}}}}
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": 1, "value": "google / cpc", "case_sensitive": false}}}, {"filter": {"field_name": "eventName", "in_list_filter": {"values": ["first_visit", "purchase", "add_to_cart"], "case_sensitive": true}}}]}}
5. An OR group filter:
{"or_group": {"expressions": [{"filter": {"field_name": "sourceMedium", "string_filter": {"match_type": 1, "value": "google / cpc", "case_sensitive": false}}}, {"filter": {"field_name": "eventName", "in_list_filter": {"values": ["first_visit", "purchase", "add_to_cart"], "case_sensitive": true}}}]}} Notes:
The API applies the dimension_filter and metric_filter
independently. As a result, some complex combinations of dimension and
metric filters are not possible in a single report request.
For example, you can't create a `dimension_filter` and `metric_filter`
combination for the following condition:
(
(eventName = "page_view" AND eventCount > 100)
OR
(eventName = "join_group" AND eventCount < 50)
)
This isn't possible because there's no way to apply the condition
"eventCount > 100" only to the data with eventName of "page_view", and
the condition "eventCount < 50" only to the data with eventName of
"join_group".
More generally, you can't define a `dimension_filter` and `metric_filter`
for:
(
((dimension condition D1) AND (metric condition M1))
OR
((dimension condition D2) AND (metric condition M2))
)
If you have complex conditions like this, either:
a) Run a single report that applies a subset of the conditions that
the API supports as well as the data needed to perform filtering of the
API response on the client side. For example, for the condition:
(
(eventName = "page_view" AND eventCount > 100)
OR
(eventName = "join_group" AND eventCount < 50)
)
You could run a report that filters only on:
eventName one of "page_view" or "join_group"
and include the eventCount metric, then filter the API response on the
client side to apply the different metric filters for the different
events.
or
b) Run a separate report for each combination of dimension condition and
metric condition. For the example above, you'd run one report for the
combination of (D1 AND M1), and another report for the combination of
(D2 AND M2).
Try to run fewer reports (option a) if possible. However, if running
fewer reports results in excessive quota usage for the API, use option
b. More information on quota usage is at
https://developers.google.com/analytics/blog/2023/data-api-quota-management.
### Hints for `metric_filter`:
Example metric_filter arguments:
1. A simple filter:
{"filter": {"field_name": "eventCount", "numeric_filter": {"operation": 4, "value": {"int64_value": "10"}}}}
2. A NOT filter:
{"not_expression": {"filter": {"field_name": "eventCount", "numeric_filter": {"operation": 4, "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": 4, "value": {"int64_value": "10"}}}}, {"filter": {"field_name": "purchaseRevenue", "between_filter": {"from_value": {"double_value": 10.0}, "to_value": {"double_value": 25.0}}}}]}}
5. An OR group filter:
{"or_group": {"expressions": [{"filter": {"field_name": "eventCount", "numeric_filter": {"operation": 4, "value": {"int64_value": "10"}}}}, {"filter": {"field_name": "purchaseRevenue", "between_filter": {"from_value": {"double_value": 10.0}, "to_value": {"double_value": 25.0}}}}]}} Notes:
The API applies the dimension_filter and metric_filter
independently. As a result, some complex combinations of dimension and
metric filters are not possible in a single report request.
For example, you can't create a `dimension_filter` and `metric_filter`
combination for the following condition:
(
(eventName = "page_view" AND eventCount > 100)
OR
(eventName = "join_group" AND eventCount < 50)
)
This isn't possible because there's no way to apply the condition
"eventCount > 100" only to the data with eventName of "page_view", and
the condition "eventCount < 50" only to the data with eventName of
"join_group".
More generally, you can't define a `dimension_filter` and `metric_filter`
for:
(
((dimension condition D1) AND (metric condition M1))
OR
((dimension condition D2) AND (metric condition M2))
)
If you have complex conditions like this, either:
a) Run a single report that applies a subset of the conditions that
the API supports as well as the data needed to perform filtering of the
API response on the client side. For example, for the condition:
(
(eventName = "page_view" AND eventCount > 100)
OR
(eventName = "join_group" AND eventCount < 50)
)
You could run a report that filters only on:
eventName one of "page_view" or "join_group"
and include the eventCount metric, then filter the API response on the
client side to apply the different metric filters for the different
events.
or
b) Run a separate report for each combination of dimension condition and
metric condition. For the example above, you'd run one report for the
combination of (D1 AND M1), and another report for the combination of
(D2 AND M2).
Try to run fewer reports (option a) if possible. However, if running
fewer reports results in excessive quota usage for the API, use option
b. More information on quota usage is at
https://developers.google.com/analytics/blog/2023/data-api-quota-management.
### Hints for `order_bys`:
Example order_bys arguments:
1. Order by ascending 'eventName':
[ {"dimension": {"dimension_name": "eventName", "order_type": 1}, "desc": false} ]
2. Order by descending 'eventName', ignoring case:
[ {"dimension": {"dimension_name": "campaignName", "order_type": 2}, "desc": true} ]
3. Order by ascending 'audienceId':
[ {"dimension": {"dimension_name": "audienceId", "order_type": 3}, "desc": false} ]
4. Order by descending 'eventCount':
[ {"metric": {"metric_name": "eventValue"}, "desc": true} ]
5. Order by ascending 'eventCount':
[ {"metric": {"metric_name": "eventCount"}, "desc": false} ]
6. Combination of dimension and metric order bys:
[
{"dimension": {"dimension_name": "eventName", "order_type": 1}, "desc": false},
{"metric": {"metric_name": "eventValue"}, "desc": true},
]
7. Order by multiple dimensions and metrics:
[
{"dimension": {"dimension_name": "eventName", "order_type": 1}, "desc": false},
{"dimension": {"dimension_name": "audienceId", "order_type": 3}, "desc": false},
{"metric": {"metric_name": "eventValue"}, "desc": true},
]
The dimensions and metrics in order_bys must also be present in the report
request's "dimensions" and "metrics" arguments, respectively.| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | The maximum number of rows to return in each response. Value must be a positive integer <= 250,000. Used to paginate through large reports, following the guide at https://developers.google.com/analytics/devguides/reporting/data/v1/basics#pagination. | |
| offset | No | The row count of the start row. The first row is counted as row 0. Used to paginate through large reports, following the guide at https://developers.google.com/analytics/devguides/reporting/data/v1/basics#pagination. | |
| metrics | Yes | A list of metrics to include in the report. | |
| order_bys | No | A list of Data API OrderBy (https://developers.google.com/analytics/devguides/reporting/data/v1/rest/v1beta/OrderBy) objects to apply to the dimensions and metrics. | |
| dimensions | Yes | A list of dimensions to include in the report. | |
| date_ranges | Yes | A list of date ranges (https://developers.google.com/analytics/devguides/reporting/data/v1/rest/v1beta/DateRange) to include in the report. | |
| property_id | Yes | The Google Analytics property ID. Accepted formats are: - A number - A string consisting of 'properties/' followed by a number | |
| currency_code | No | The currency code to use for currency values. Must be in ISO4217 format, such as "AED", "USD", "JPY". If the field is empty, the report uses the property's default currency. | |
| metric_filter | No | A Data API FilterExpression (https://developers.google.com/analytics/devguides/reporting/data/v1/rest/v1beta/FilterExpression) to apply to the metrics. Don't use this for filtering dimensions. Use dimension_filter instead. The `field_name` in a `metric_filter` must be a metric, as defined in the `get_standard_metrics` and `get_metrics` tools. | |
| dimension_filter | No | A Data API FilterExpression (https://developers.google.com/analytics/devguides/reporting/data/v1/rest/v1beta/FilterExpression) to apply to the dimensions. Don't use this for filtering metrics. Use metric_filter instead. The `field_name` in a `dimension_filter` must be a dimension, as defined in the `get_standard_dimensions` and `get_dimensions` tools. | |
| return_property_quota | No | Whether to return property quota in the response. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It effectively communicates key behaviors: snake_case field naming, the independent application of dimension and metric filters, pagination via limit/offset, quota considerations, and the requirement that order_bys must reference included dimensions/metrics. It does not mention idempotency or side effects, but for a read-only report this is acceptable.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is extremely long and repetitive, with the same note about dimension_filter and metric_filter independence appearing verbatim twice. While it is structured with headings and examples, the redundancy and sheer length prevent it from being concise; many sentences could be consolidated.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with 11 parameters and nested objects, the description is remarkably complete. It covers argument formats, examples, behavioral limitations, pagination, quota, and even workarounds for complex filters. The presence of an output schema means return values need no explanation, and nothing essential for correct usage appears missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, but the description goes far beyond the schema by providing detailed hints, worked examples for date_ranges, filters, order_bys, and clarifying the snake_case convention. It also explains constraints like the independence of filters and the requirement that order_bys reference included fields, adding significant value for correct invocation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool 'Runs a Google Analytics Data API report,' which is a specific verb and resource. It distinguishes the tool from siblings like run_realtime_report by name and the general nature of the report, but it does not explicitly call out the difference, so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no guidance on when to use this tool versus alternatives like run_realtime_report. It focuses entirely on parameter details and examples, but does not mention use cases, prerequisites, or exclusions, leaving the agent to infer when this tool is appropriate.
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.
7 tool updates
v0.2.0- First observed
get_account_summaries - First observed
get_custom_dimensions_and_metrics - First observed
get_property_details - First observed
list_google_ads_links - First observed
list_property_annotations - First observed
run_realtime_report - First observed
run_report
TDQS
Scored across 7 tools
Each tool has a distinct purpose (account summaries, standard reports, realtime reports, ads links, property details, annotations, custom schema), with only minor overlap between run_report and run_realtime_report. The 'realtime' qualifier makes the difference clear, so misselection is unlikely.
All tool names follow a consistent snake_case verb_noun pattern (get_, list_, run_). Retrieval verbs are appropriately differentiated: 'get' for singular objects and 'list' for plural collections, with no mixed conventions.
Seven tools is a well-scoped count for a GA4 data-access server. It covers account discovery, reporting, realtime reporting, schema introspection, annotations, and ad links without feeling bloated or unduly thin.
The server has significant gaps: run_report and run_realtime_report reference non-existent helper tools like get_standard_dimensions, get_dimensions, get_standard_metrics, and hint tools, which will cause agent failures when trying to discover valid fields. Additionally, annotations are read-only (list only), so the surface is incomplete for the domain it claims to support.
Maintenance
Related MCP Connectors
Read and edit GA4, Search Console and Google Tag Manager from any MCP client. 29 tools.
Your whole business as one MCP server: analytics, CRM, SEO, ads, revenue. Scoped per data class.
Governed data discovery, exact queries, decisions, simulations, and runtime utilities over MCP.
Hosted Google Ads MCP with OAuth, bounded reads, and prepare/confirm writes.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceManages Google Analytics 4 accounts, properties, annotations, audiences, and custom dimensions through the MCP protocol.3 npm1ISC
- AlicenseNot gradedqualityBmaintenanceProvides full Google Analytics 4 management and reporting capabilities via MCP, including property management, custom dimensions, audiences, events, data streams, and real-time reporting.MIT
- AlicenseAqualityDmaintenanceEnables 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.4MIT
- AlicenseAqualityDmaintenanceEnables LLM applications to query and analyze Google Analytics 4 data through standard MCP interfaces, supporting service account and OAuth2 authentication.59 npmMIT