Skip to main content
Glama
Google Analytics MCP Server

Google Analytics MCP Server

Official

Google Analytics MCP Server

PyPI version Python 3.10+ GitHub branch check runs PyPI - Downloads GitHub stars GitHub forks YouTube Video Views

This repo contains the source code for running a local or remote multi-tenant MCP server that interacts with APIs for Google Analytics.

Join the discussion and ask questions in the 🤖-analytics-mcp channel on Discord.

Tools 🛠️

The server uses the Google Analytics Admin API and Google Analytics Data API to provide several Tools for use with LLMs.

Retrieve account and property information 🟠

  • get_account_summaries: Retrieves information about the user's Google Analytics accounts and properties.

  • get_property_details: Returns details about a property.

  • list_google_ads_links: Returns a list of links to Google Ads accounts for a property.

  • list_property_annotations: Returns annotations for a property.

  • create_property_annotation: Creates an annotation for a property (requires passing the --allow-write flag and the analytics.edit scope).

  • list_key_events: Returns the key events (formerly conversions) defined on a property.

  • create_custom_dimension: Creates a custom dimension on a property (requires passing the --allow-write flag and the analytics.edit scope, and the Editor role on the property).

  • create_key_event: Marks an event as a key event on a property (requires passing the --allow-write flag and the analytics.edit scope, and the Marketer or Editor role on the property).

Run core reports 📙

  • run_report: Runs a Google Analytics report using the Data API.

  • run_funnel_report: Runs a Google Analytics funnel report using the Data API.

  • run_conversions_report: Runs a Google Analytics conversions report (ad costs, conversions, ROAS and attribution models) using the Data API.

  • get_custom_dimensions_and_metrics: Retrieves the custom dimensions and metrics for a specific property.

Run realtime reports ⏳

  • run_realtime_report: Runs a Google Analytics realtime report using the Data API.

Related MCP server: Google Analytics MCP Server

Setup instructions 🔧

✨ Watch the Google Analytics MCP Setup Tutorial on YouTube for a step-by-step walkthrough of these instructions.

Watch the video

Setup involves the following steps:

  1. Configure Python.

  2. Configure credentials for Google Analytics.

  3. Configure Gemini.

Configure Python 🐍

Install pipx.

Enable APIs in your project ✅

Follow the instructions to enable the following APIs in your Google Cloud project:

Configure credentials 🔑

Configure your Application Default Credentials (ADC). Make sure the credentials are for a user with access to your Google Analytics accounts or properties.

Credentials must include the Google Analytics read-only scope:

https://www.googleapis.com/auth/analytics.readonly

If you plan to enable write tools (such as create_property_annotation, create_custom_dimension or create_key_event) using the --allow-write flag, your credentials must also include the edit scope:

https://www.googleapis.com/auth/analytics.edit

When using Application Default Credentials, add this scope to the --scopes value of the gcloud commands below and re-run the login.

Check out Manage OAuth Clients for how to create an OAuth client.

Here are some sample gcloud commands you might find useful:

  • Set up ADC using user credentials and an OAuth desktop or web client after downloading the client JSON to YOUR_CLIENT_JSON_FILE.

    gcloud auth application-default login \
      --scopes https://www.googleapis.com/auth/analytics.readonly,https://www.googleapis.com/auth/cloud-platform \
      --client-id-file=YOUR_CLIENT_JSON_FILE
  • Set up ADC using service account impersonation.

    gcloud auth application-default login \
      --impersonate-service-account=SERVICE_ACCOUNT_EMAIL \
      --scopes=https://www.googleapis.com/auth/analytics.readonly,https://www.googleapis.com/auth/cloud-platform

When the gcloud auth application-default command completes, copy the PATH_TO_CREDENTIALS_JSON file location printed to the console in the following message. You'll need this for the next step!

Credentials saved to file: [PATH_TO_CREDENTIALS_JSON]

Configure Gemini

  1. Install Gemini CLI or Gemini Code Assist.

  2. Create or edit the file at ~/.gemini/settings.json, adding your server to the mcpServers list.

    Replace PATH_TO_CREDENTIALS_JSON with the path you copied in the previous step.

    We also recommend that you add a GOOGLE_CLOUD_PROJECT attribute to the env object. Replace YOUR_PROJECT_ID in the following example with the project ID of your Google Cloud project.

    {
      "mcpServers": {
        "analytics-mcp": {
          "command": "pipx",
          "args": ["run", "analytics-mcp"],
          "env": {
            "GOOGLE_APPLICATION_CREDENTIALS": "PATH_TO_CREDENTIALS_JSON",
            "GOOGLE_CLOUD_PROJECT": "YOUR_PROJECT_ID"
          }
        }
      }
    }

    To enable write tools (e.g. create_property_annotation), append "--allow-write" to "args": ["run", "analytics-mcp", "--allow-write"].

Configure Claude Code

  1. Add the MCP server with the following command:

    Replace PATH_TO_CREDENTIALS_JSON with the path you copied in the previous step, and replace YOUR_PROJECT_ID with the project ID of your Google Cloud project.

    claude mcp add analytics-mcp \
      --scope user \
      -e "GOOGLE_APPLICATION_CREDENTIALS=PATH_TO_CREDENTIALS_JSON" \
      -e "GOOGLE_CLOUD_PROJECT=YOUR_PROJECT_ID" \
      -- pipx run analytics-mcp

Multi-tenant HTTP & End-User OAuth 🌐

To host analytics-mcp as a shared multi-tenant HTTP service (where each end user signs in with their own Google account via OAuth 2.0 rather than using server-side Application Default Credentials), start the server with --transport http:

pipx run analytics-mcp \
  --transport http --stateless-http --host 0.0.0.0 --port 8080
  • Agent Framework OAuth (e.g. Google ADK): Configure per-user Google OAuth on McpToolset so end users are automatically prompted with a Sign in button in the chat UI, and can even combine Google Analytics MCP alongside other MCP servers in the same agent. Paired with --stateless-http, this mode is completely stateless and horizontally scalable across multiple replicas.

  • Native MCP OAuth 2.1 Server (--oauth): Pass --oauth or set ANALYTICS_MCP_OAUTH=true (with GOOGLE_OAUTH_CLIENT_ID, GOOGLE_OAUTH_CLIENT_SECRET, and optional ANALYTICS_MCP_ISSUER_URL) to enable the built-in MCP OAuth 2.1 Authorization Server:

    export GOOGLE_OAUTH_CLIENT_ID="your-client-id.apps.googleusercontent.com"
    export GOOGLE_OAUTH_CLIENT_SECRET="your-client-secret"
    export ANALYTICS_MCP_ISSUER_URL="https://analytics-mcp.yourdomain.com"
    
    pipx run analytics-mcp \
      --transport http --stateless-http --oauth --host 0.0.0.0 --port 8080

    Note: The built-in --oauth provider stores dynamic client registrations, pending authorization state, and refresh tokens in process memory (run as a single instance or with sticky sessions; restarts require re-authentication).

Deploy with Docker & Google Cloud Run 🐳

The repository includes a root Dockerfile that runs analytics-mcp in stateless HTTP mode on $PORT (default 8080) as a non-root user. Server flags can be configured entirely through environment variables:

Environment Variable

CLI Option

Default

Description

PORT

--port

8000 (8080 in Dockerfile)

Port to bind when --transport http.

ANALYTICS_MCP_STATELESS_HTTP

--stateless-http

false (true in Dockerfile)

Handle each HTTP request independently without in-memory session state.

ANALYTICS_MCP_ALLOW_WRITE

--allow-write

false

Enable tools that create or modify Google Analytics resources.

ANALYTICS_MCP_OAUTH

--oauth

false

Enable the built-in MCP OAuth 2.1 Authorization Server.

ANALYTICS_MCP_ISSUER_URL

--issuer-url

http://<host>:<port>

Public HTTPS base URL of the service when OAuth is enabled.

GOOGLE_OAUTH_CLIENT_ID

—

—

Google OAuth 2.0 Web Client ID (required when OAuth is enabled).

GOOGLE_OAUTH_CLIENT_SECRET

—

—

Google OAuth 2.0 Web Client Secret (inject via Secret Manager in production).

  • Stateless HTTP mode on Cloud Run (for upstream agents like Google ADK that forward per-user Bearer tokens):

    gcloud run deploy analytics-mcp \
      --source . \
      --region us-central1 \
      --allow-unauthenticated

    Note that --allow-unauthenticated exposes the public HTTPS endpoint at the Cloud Run layer, while analytics-mcp itself strictly requires a Google OAuth Bearer token on every tool request.

  • Native MCP OAuth 2.1 mode on Cloud Run (storing the client secret in Google Cloud Secret Manager so it is injected as an environment variable at runtime rather than stored in files or source control):

    # 1. Store your Google OAuth Client Secret in Secret Manager once
    printf "%s" "YOUR_CLIENT_SECRET" | \
      gcloud secrets create analytics-mcp-oauth-secret --data-file=-
    
    # 2. Deploy to Cloud Run (--max-instances=1 keeps in-memory OAuth state consistent)
    gcloud run deploy analytics-mcp \
      --source . \
      --region us-central1 \
      --allow-unauthenticated \
      --max-instances 1 \
      --set-env-vars "ANALYTICS_MCP_OAUTH=true,GOOGLE_OAUTH_CLIENT_ID=YOUR_CLIENT_ID.apps.googleusercontent.com" \
      --set-secrets "GOOGLE_OAUTH_CLIENT_SECRET=analytics-mcp-oauth-secret:latest"
    
    # 3. Set ANALYTICS_MCP_ISSUER_URL to the deployed Cloud Run URL and add
    #    <SERVICE_URL>/oauth/callback to Authorized redirect URIs in Cloud Console
    SERVICE_URL=$(gcloud run services describe analytics-mcp --region us-central1 --format="value(status.url)")
    gcloud run services update analytics-mcp \
      --region us-central1 \
      --update-env-vars "ANALYTICS_MCP_ISSUER_URL=${SERVICE_URL}"
  • Local Docker:

    docker build -t analytics-mcp .
    docker run --rm -p 8080:8080 \
      -e ANALYTICS_MCP_OAUTH=true \
      -e GOOGLE_OAUTH_CLIENT_ID="your-client-id.apps.googleusercontent.com" \
      -e GOOGLE_OAUTH_CLIENT_SECRET="your-client-secret" \
      analytics-mcp

See the complete multi-tenant walkthrough and runnable ADK agent code in examples/multi_tenant_adk_agent/README.md.

Try it out 🥼

Launch Gemini Code Assist or Gemini CLI and type /mcp. You should see analytics-mcp listed in the results.

Here are some sample prompts to get you started:

  • Ask what the server can do:

    what can the analytics-mcp server do?
  • Ask about a Google Analytics property

    Give me details about my Google Analytics property with 'xyz' in the name
  • Prompt for analysis:

    what are the most popular events in my Google Analytics property in the last 180 days?
  • Ask about signed-in users:

    were most of my users in the last 6 months logged in?
  • Ask about property configuration:

    what are the custom dimensions and custom metrics in my property?
  • Create a custom dimension (requires the --allow-write flag):

    Create an event-scoped custom dimension for the plan_tier parameter in property 12345

Contributing ✨

Contributions welcome! See the Contributing Guide.

Troubleshooting

See the Troubleshooting Guide for common issues and workarounds.

Available Tools

10 tools
get_account_summariesB
Read-only

Retrieves information about the user's Google Analytics accounts and properties.

Inputs: no named parameters.

get_custom_dimensions_and_metricsB
Read-only

Returns the property's custom dimensions and metrics.

Args: property_id: The Google Analytics property ID. Accepted formats are: - A number - A string consisting of 'properties/' followed by a number

Inputs: property_id (required).

get_property_detailsB
Read-only

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

Inputs: property_id (required).

list_key_eventsA
Read-only

Returns the key events (formerly conversions) defined on a property.

Each key event has its event name, counting method, default value, and whether it is custom and deletable. Use this for key event definitions; use run_conversions_report for key event numbers.

Args: property_id: The Google Analytics property ID. Accepted formats are: - A number - A string consisting of 'properties/' followed by a number

Inputs: property_id (required).

list_property_annotationsA
Read-only

Returns annotations for a property.

Annotations are a feature that allows you to leave notes on Google Analytics 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.

Args: property_id: The Google Analytics property ID. Accepted formats are: - A number - A string consisting of 'properties/' followed by a number

Inputs: property_id (required).

run_conversions_reportA
Read-only
      Runs a Google Analytics Data API conversions report.

USE THIS TOOL INSTEAD OF `run_report` WHEN:
- You need to report specifically on conversions, ad performance, return on ad spend (ROAS), or attribution.
- You need to query specific conversion metrics (e.g., advertiserAdCost, returnOnAdSpendByInteractionDate, allConversionsByConversionDate, etc.).
- You need to apply a specific attribution model (e.g., DATA_DRIVEN or LAST_CLICK) to your data.
- The user's query explicitly asks about conversions, ad clicks, ad costs, or campaigns related to conversions.

See the conversions report guide at
https://developers.google.com/analytics/devguides/reporting/data/v1/conversions-api-basics
for details and examples.

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/v1alpha/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.
    conversion_spec: The specification for conversions reporting.
      Should include 'conversion_actions' (list of resource names) and
      'attribution_model'.
    dimension_filter: A Data API FilterExpression
      (https://developers.google.com/analytics/devguides/reporting/data/v1/rest/v1alpha/FilterExpression)
      to apply to the dimensions.
    metric_filter: A Data API FilterExpression
      (https://developers.google.com/analytics/devguides/reporting/data/v1/rest/v1alpha/FilterExpression)
      to apply to the metrics.
    order_bys: A list of Data API OrderBy
      (https://developers.google.com/analytics/devguides/reporting/data/v1/rest/v1alpha/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.
    offset: The row count of the start row. The first row is counted as row 0.
    currency_code: The currency code to use for currency values.
    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 the following allowed standard dimensions:
      - campaignName
      - continent
      - country
      - defaultChannelGroup
      - deviceCategory
      - medium
      - platform
      - primaryChannelGroup
      - source
      - sourceMedium
      - sourcePlatform
      - subcontinent

      ### Hints for `metrics`

      The `metrics` list must consist solely of the following allowed standard metrics:
      - advertiserAdClicks
      - advertiserAdCost
      - advertiserAdCostPerAllConversionsByConversionDate
      - advertiserAdCostPerAllConversionsByInteractionDate
      - advertiserAdCostPerClick
      - advertiserAdImpressions
      - allConversionsByConversionDate
      - allConversionsByInteractionDate
      - returnOnAdSpendByConversionDate
      - returnOnAdSpendByInteractionDate
      - totalRevenueByConversionDate
      - totalRevenueByInteractionDate

      ### Hints for `conversion_spec`

      The `conversion_spec` argument is required for conversions reporting.
      You can pass an empty list for `conversion_actions` if you want all conversion events.
      Example:
      {
          "conversion_actions": ["conversionActions/12345"], # Or [] for all actions
          "attribution_model": "DATA_DRIVEN"  # Or "LAST_CLICK"
      }

      ### 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.

Inputs: metrics (required), dimensions (required), date_ranges (required), property_id (required), +8 more.

run_funnel_reportA
Read-only
    Run a Google Analytics Data API funnel report.

See the funnel report guide at
https://developers.google.com/analytics/devguides/reporting/data/v1/funnels
for details and examples.

Args:
    property_id: The Google Analytics property ID. Accepted formats are:
      - A number
      - A string consisting of 'properties/' followed by a number
    funnel_steps: A list of funnel steps. Each step should be a dictionary
      containing:
      - 'name': (str) Display name for the step
      - 'filter_expression': (Dict) Complete filter expression for the step
      OR for simple event-based steps:
      - 'name': (str) Display name for the step
      - 'event': (str) Event name to filter on
    date_ranges: A list of date ranges
      (https://developers.google.com/analytics/devguides/reporting/data/v1/rest/v1beta/DateRange)
      to include in the report.
    funnel_breakdown: Optional breakdown dimension to segment the funnel.
      This creates separate funnel results for each value of the dimension.
      Example: {"breakdown_dimension": "deviceCategory"}
    funnel_next_action: Optional next action analysis configuration.
      This analyzes what users do after completing or dropping off from
      the funnel.
      Example: {"next_action_dimension": "eventName", "limit": 5}
    segments: Optional list of segments to apply to the funnel.
    return_property_quota: Whether to return current property quota
      information.

Returns:
    Dict containing the funnel report response with funnel results
    including:
    - funnel_table: Table showing progression through funnel steps
    - funnel_visualization: Data for visualizing the funnel
    - property_quota: (if requested) Current quota usage information

Raises:
    ValueError: If funnel_steps is empty or contains invalid configurations
    Exception: If the API request fails


    ## Hints for arguments

    Here are some hints that outline the expected format and requirements
    for arguments.

    ### Hints for `funnel_breakdown`

    The `funnel_breakdown` parameter allows you to segment funnel results by a dimension:
    ```json
    {
        "breakdown_dimension": "deviceCategory"
    }
    ```
    Common breakdown dimensions include:
    - `deviceCategory` - Desktop, Mobile, Tablet
    - `country` - User's country
    - `operatingSystem` - User's operating system
    - `browser` - User's browser

    ### Hints for `funnel_next_action`

    The `funnel_next_action` parameter analyzes what users do after completing or dropping off from the funnel:
    ```json
    {
        "next_action_dimension": "eventName",
        "limit": 5
    }
    ```
    Common next action dimensions include:
    - `eventName` - Next events users trigger
    - `pagePath` - Next pages users visit

    ### Hints for `segments`

    The `segments` parameter allows you to segment funnel results by user criteria.
    Each segment is a dictionary passed directly to `data_v1alpha.Segment()`.
    See https://developers.google.com/analytics/devguides/reporting/data/v1/funnels#segments
    for details and examples.

    ### 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 `funnel_steps`
    Example funnel_steps configurations:

1. Simple event-based step (first open/visit):
    {"name": "First open/visit", "filter_expression": {"or_group": {"expressions": [{"funnel_event_filter": {"event_name": "first_open"}}, {"funnel_event_filter": {"event_name": "first_visit"}}]}}, "is_directly_followed_by": false}

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

3. Simple event filter:
    {"name": "Session start", "filter_expression": {"funnel_event_filter": {"event_name": "session_start"}}, "is_directly_followed_by": false}

4. Multiple events with OR condition:
    {"name": "Screen/Page view", "filter_expression": {"or_group": {"expressions": [{"funnel_event_filter": {"event_name": "screen_view"}}, {"funnel_event_filter": {"event_name": "page_view"}}]}}, "is_directly_followed_by": false}

5. Purchase events (multiple event types):
    {"name": "Purchase", "filter_expression": {"or_group": {"expressions": [{"funnel_event_filter": {"event_name": "purchase"}}, {"funnel_event_filter": {"event_name": "in_app_purchase"}}]}}, "is_directly_followed_by": false}

6. Event with 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": 4, "value": {"double_value": 50.0}}}}}}, "is_directly_followed_by": false}

7. Complex AND condition (page view + specific 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": 4, "value": "/", "case_sensitive": false}}}]}}, "is_directly_followed_by": false}


## Complete Funnel Example

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

Inputs: property_id (required), funnel_steps (required), segments, date_ranges, +3 more.

run_realtime_reportA
Read-only
      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.
    minute_ranges: Optional minute ranges (max 2), e.g.
      [{"name": "last5", "start_minutes_ago": 4, "end_minutes_ago": 0}].
      start_minutes_ago can be at most 29. Omit for the last 30 minutes.


      ## 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 `minute_ranges`:
      Example minute_ranges arguments:
  1. The last 5 minutes:
    [ {"start_minutes_ago": 4, "end_minutes_ago": 0, "name": "Last5Minutes"} ]

  2. The last 5 minutes compared with the last 30 minutes:
    [ {"start_minutes_ago": 4, "end_minutes_ago": 0, "name": "Last5Minutes"}, {"start_minutes_ago": 29, "end_minutes_ago": 0, "name": "Last30Minutes"} ]

  3. A window that ends before now (15 to 29 minutes ago):
    [ {"start_minutes_ago": 29, "end_minutes_ago": 15, "name": "Earlier15Minutes"} ]

  Notes:
    - At most 2 minute ranges are allowed.
    - `start_minutes_ago` can be at most 29 for standard properties.
    - Each range counts unique users within that window, so use a minute
      range instead of summing rows of the `minutesAgo` dimension.
    - When 2 ranges are given, the response includes a `dateRange`
      dimension with each range's `name`.
    - Omit `minute_ranges` to report on the last 30 minutes.


      ### 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.

Inputs: metrics (required), dimensions (required), property_id (required), limit, +6 more.

run_reportA
Read-only
      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.

Inputs: metrics (required), dimensions (required), date_ranges (required), property_id (required), +7 more.

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    A3.7/5.0

    Scored across 10 tools

    Disambiguation4/5

    The four report tools (run_report, run_realtime_report, run_conversions_report, run_funnel_report) share a verb but are cleanly split by report type, and run_conversions_report explicitly instructs when to prefer it over run_report. The metadata tools (list_key_events, get_property_details, get_account_summaries, get_custom_dimensions_and_metrics, list_google_ads_links, list_property_annotations) each target a distinct resource. Only minor potential for confusion between run_report and run_conversions_report when a query mentions revenue but not ads.

    Naming Consistency5/5

    Every name follows a predictable verb_noun pattern (get_, list_, run_) with snake_case throughout. The verb choice maps sensibly to semantics: get_ for single-resource detail, list_ for collections, run_ for report executions. No mixed conventions or vague verbs.

    Tool Count5/5

    Ten tools is well within the healthy 3-15 range and each earns its place: discovery, schema introspection, and four distinct report types. Nothing appears padded or redundant for a read-oriented analytics surface.

    Completeness3/5

    Reporting coverage is broad (standard, realtime, conversions, funnel) and account/property discovery is present, but there is no tool to list standard dimensions or metrics even though descriptions repeatedly reference non-existent helpers (get_standard_dimensions, get_metrics, run_report_*_hints), forcing agents to rely on external URLs. Write operations are also absent (no annotation or key event creation), leaving some dead ends for the stated GA administration domain.

    Maintenance

    ActivityMaintained
    ResponsivenessUsually handled

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      Not graded
      maintenance
      An experimental MCP server that enables interaction with Google Analytics APIs, allowing users to retrieve account information, run core reports, and access realtime analytics data through natural language queries.
      Apache 2.0
    • A
      license
      Not graded
      quality
      D
      maintenance
      MCP server for querying Google Analytics accounts, properties, reports, and realtime data using the Data API and Admin API.
      1
      Apache 2.0
    • A
      license
      Not graded
      quality
      F
      maintenance
      MCP server that provides tools to interact with Google Analytics APIs, enabling account and property retrieval, report running, and custom dimension/metrics access.
      Apache 2.0