google-analytics-mcp 2.2.1__tar.gz → 2.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (19) hide show
  1. {google_analytics_mcp-2.2.1/google_analytics_mcp.egg-info → google_analytics_mcp-2.3.0}/PKG-INFO +1 -1
  2. {google_analytics_mcp-2.2.1 → google_analytics_mcp-2.3.0}/ga4_mcp/server.py +1 -1
  3. {google_analytics_mcp-2.2.1 → google_analytics_mcp-2.3.0}/ga4_mcp/tools/reporting.py +29 -16
  4. {google_analytics_mcp-2.2.1 → google_analytics_mcp-2.3.0}/ga4_mcp/tools/troubleshooting.py +5 -5
  5. {google_analytics_mcp-2.2.1 → google_analytics_mcp-2.3.0/google_analytics_mcp.egg-info}/PKG-INFO +1 -1
  6. {google_analytics_mcp-2.2.1 → google_analytics_mcp-2.3.0}/pyproject.toml +1 -1
  7. {google_analytics_mcp-2.2.1 → google_analytics_mcp-2.3.0}/LICENSE +0 -0
  8. {google_analytics_mcp-2.2.1 → google_analytics_mcp-2.3.0}/README.md +0 -0
  9. {google_analytics_mcp-2.2.1 → google_analytics_mcp-2.3.0}/ga4_mcp/__init__.py +0 -0
  10. {google_analytics_mcp-2.2.1 → google_analytics_mcp-2.3.0}/ga4_mcp/__main__.py +0 -0
  11. {google_analytics_mcp-2.2.1 → google_analytics_mcp-2.3.0}/ga4_mcp/coordinator.py +0 -0
  12. {google_analytics_mcp-2.2.1 → google_analytics_mcp-2.3.0}/ga4_mcp/resources.py +0 -0
  13. {google_analytics_mcp-2.2.1 → google_analytics_mcp-2.3.0}/ga4_mcp/tools/metadata.py +0 -0
  14. {google_analytics_mcp-2.2.1 → google_analytics_mcp-2.3.0}/google_analytics_mcp.egg-info/SOURCES.txt +0 -0
  15. {google_analytics_mcp-2.2.1 → google_analytics_mcp-2.3.0}/google_analytics_mcp.egg-info/dependency_links.txt +0 -0
  16. {google_analytics_mcp-2.2.1 → google_analytics_mcp-2.3.0}/google_analytics_mcp.egg-info/entry_points.txt +0 -0
  17. {google_analytics_mcp-2.2.1 → google_analytics_mcp-2.3.0}/google_analytics_mcp.egg-info/requires.txt +0 -0
  18. {google_analytics_mcp-2.2.1 → google_analytics_mcp-2.3.0}/google_analytics_mcp.egg-info/top_level.txt +0 -0
  19. {google_analytics_mcp-2.2.1 → google_analytics_mcp-2.3.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: google-analytics-mcp
3
- Version: 2.2.1
3
+ Version: 2.3.0
4
4
  Summary: Model Context Protocol for Google Analytics 4 (Data API) allowing autonomous agents to query dimensions and metrics. Gives agents analysis-ready GA4 access with schema discovery, server-side aggregation, and smart defaults.
5
5
  Author-email: Surendran B <reachsuren@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -71,7 +71,7 @@ def main():
71
71
  print(f"FATAL: Could not fetch GA4 property schema: {e}", file=sys.stderr)
72
72
  err_str = str(e)
73
73
  if "403" in err_str or "PermissionDenied" in err_str or "permission" in err_str.lower():
74
- coordinator.SERVER_INIT_ERROR = f"IAM Error: The service account does not have Viewer access to the GA4 property. SYSTEM DIRECTIVE: You MUST immediately call the 'get_troubleshooting_guide' tool with topic='iam' to read the step-by-step IAM guide and help the user fix this."
74
+ coordinator.SERVER_INIT_ERROR = f"IAM Error: The service account does not have Viewer access to the GA4 property. SYSTEM DIRECTIVE: You do not know how to solve this. You MUST immediately call the 'get_troubleshooting_guide' tool with topic='iam' to read the step-by-step IAM guide and help the user fix this."
75
75
  else:
76
76
  coordinator.SERVER_INIT_ERROR = f"Could not fetch GA4 property schema: {err_str}.{docs_suffix}"
77
77
  config_status = "error"
@@ -27,6 +27,17 @@ from ga4_mcp.coordinator import mcp
27
27
  # This global variable will be populated by the server on startup.
28
28
  PROPERTY_SCHEMA = None
29
29
 
30
+ def _camel_to_snake(name: str) -> str:
31
+ import re
32
+ return re.sub(r'(?<!^)(?=[A-Z])', '_', name).lower()
33
+
34
+ def _convert_keys_to_snake(d):
35
+ if isinstance(d, dict):
36
+ return {_camel_to_snake(k): _convert_keys_to_snake(v) for k, v in d.items()}
37
+ elif isinstance(d, list):
38
+ return [_convert_keys_to_snake(x) for x in d]
39
+ return d
40
+
30
41
  def _get_smart_sorting(dimensions, metrics):
31
42
  """Determine optimal sorting strategy for relevance."""
32
43
  order_bys = []
@@ -40,6 +51,7 @@ def _should_aggregate(dimensions, metrics):
40
51
  """Detect when server-side aggregation would be beneficial."""
41
52
  return len(dimensions) == 0 or "date" not in dimensions
42
53
 
54
+
43
55
  @mcp.tool()
44
56
  def get_ga4_data(
45
57
  dimensions: list[str] = ["date"],
@@ -55,9 +67,11 @@ def get_ga4_data(
55
67
  """
56
68
  Retrieve GA4 data with built-in intelligence for better and safer results.
57
69
 
58
- This tool is a powerful wrapper around the Google Analytics Data API. It not only
59
- fetches data but also includes "smart" features to protect against context window
60
- overloads and to provide more relevant results by default.
70
+ CRITICAL WORKFLOW INSTRUCTIONS FOR AI AGENTS:
71
+ To ensure deterministic and successful data retrieval, you MUST follow this sequence:
72
+ 1. DISCOVER: NEVER guess dimension or metric names. Always call `search_schema`, `list_dimension_categories`, or `list_metric_categories` FIRST to verify the exact API names available for this property.
73
+ 2. RETRIEVE: Call this tool (`get_ga4_data`) using the verified dimensions and metrics.
74
+ 3. TROUBLESHOOT: If you receive a SchemaError, an Invalid Dimension/Metric error, or an error about `dimension_filter` structure, DO NOT RETRY BY GUESSING. You MUST immediately call `get_troubleshooting_guide(topic='schema')` to learn the correct structure and available fields.
61
75
 
62
76
  **Smart Features:**
63
77
  - **Data Volume Protection:** Before running a query that could produce a huge
@@ -73,13 +87,14 @@ def get_ga4_data(
73
87
  relevant data at the top.
74
88
 
75
89
  Args:
76
- dimensions: List of GA4 dimensions (e.g., ["date", "city"]).
77
- metrics: List of GA4 metrics (e.g., ["totalUsers", "sessions"]).
90
+ dimensions: List of GA4 dimensions (e.g., ["date", "city"]). MUST be verified via schema tools.
91
+ metrics: List of GA4 metrics (e.g., ["totalUsers", "sessions"]). MUST be verified via schema tools.
78
92
  date_range_start: Start date in YYYY-MM-DD format or relative date ('7daysAgo').
79
93
  date_range_end: End date in YYYY-MM-DD format or relative date ('yesterday').
80
94
  dimension_filter: (Optional) A dictionary representing a GA4 FilterExpression.
81
- CRITICAL: You MUST use the exact structure. Do not invent fields.
82
- If you receive an error about dimension_filter structure, you MUST immediately call get_troubleshooting_guide(topic='schema').
95
+ CRITICAL: The GA4 API requires a very specific, nested dictionary structure.
96
+ DO NOT GUESS the structure (e.g., do not use `field_name`). If you are unsure how
97
+ to format a FilterExpression, call get_troubleshooting_guide(topic='schema') first.
83
98
  limit: (Optional) Maximum number of rows to return. Defaults to 1000.
84
99
  estimate_only: (Optional) If True, returns only the estimated row count
85
100
  without fetching the full dataset.
@@ -105,22 +120,20 @@ def get_ga4_data(
105
120
  valid_mets = PROPERTY_SCHEMA["metrics"].keys()
106
121
  for dim in parsed_dimensions:
107
122
  if dim not in valid_dims:
108
- return {"error": f"Invalid dimension: '{dim}'. DO NOT GUESS DIMENSIONS. You must call search_schema() first to find the exact API name for this dimension."}
123
+ return {"error": f"Invalid dimension: '{dim}'. DO NOT GUESS DIMENSIONS. SYSTEM DIRECTIVE: You do not know how to solve this. You MUST immediately call the 'get_troubleshooting_guide' tool with topic='schema' to learn how to find valid dimensions."}
109
124
  for met in parsed_metrics:
110
125
  if met not in valid_mets:
111
- return {"error": f"Invalid metric: '{met}'. DO NOT GUESS METRICS. You must call search_schema() first to find the exact API name for this metric."}
126
+ return {"error": f"Invalid metric: '{met}'. DO NOT GUESS METRICS. SYSTEM DIRECTIVE: You do not know how to solve this. You MUST immediately call the 'get_troubleshooting_guide' tool with topic='schema' to learn how to find valid metrics."}
112
127
 
113
128
  # --- Filter Expression Building ---
114
129
  filter_expression = None
115
130
  if dimension_filter:
116
- # The original script had a complex recursive builder. For this refactoring,
117
- # we'll rely on the user passing a correctly structured dict, similar to the
118
- # official google/analytics-mcp project. This simplifies the code greatly.
119
- # A more robust builder can be added back later if needed.
120
131
  try:
121
- filter_expression = FilterExpression(dimension_filter)
132
+ # Recursively translate camelCase keys to snake_case for proto-plus compatibility
133
+ snake_filter = _convert_keys_to_snake(dimension_filter)
134
+ filter_expression = FilterExpression(snake_filter)
122
135
  except Exception as e:
123
- return {"error": f"Invalid dimension_filter structure: {e}. SYSTEM DIRECTIVE: You MUST immediately call get_troubleshooting_guide(topic='schema') to learn the correct structure."}
136
+ return {"error": f"Invalid dimension_filter structure: {e}. SYSTEM DIRECTIVE: You do not know how to solve this. You MUST immediately call get_troubleshooting_guide(topic='schema') to learn the correct structure."}
124
137
 
125
138
  # --- API Client and Request Objects ---
126
139
  client = BetaAnalyticsDataClient()
@@ -197,6 +210,6 @@ def get_ga4_data(
197
210
  error_message += f" Details: {e.details()}"
198
211
 
199
212
  if "403" in error_message or "PermissionDenied" in error_message or "permission" in error_message.lower():
200
- error_message += " SYSTEM DIRECTIVE: You MUST immediately call get_troubleshooting_guide(topic='iam') to fix this."
213
+ error_message += " SYSTEM DIRECTIVE: You do not know how to solve this. You MUST immediately call get_troubleshooting_guide(topic='iam') to read the step-by-step IAM permissions guide and help the user resolve this."
201
214
 
202
215
  return {"error": error_message}
@@ -2,15 +2,15 @@ import urllib.request
2
2
  import urllib.error
3
3
  from ga4_mcp.coordinator import mcp
4
4
 
5
- # Use raw.githubusercontent.com for OTA updates for now.
6
- # This can be swapped to docs.ga4mcp.com in the future.
7
- OTA_BASE_URL = "https://raw.githubusercontent.com/surendranb/google-analytics-mcp/main/docs"
5
+ # Fetches troubleshooting guides directly from the documentation site.
6
+ OTA_BASE_URL = "https://ga4mcp.com"
8
7
 
9
8
  @mcp.tool()
10
9
  def get_troubleshooting_guide(topic: str) -> str:
11
10
  """
12
- Fetches the latest troubleshooting and setup guides Over-The-Air (OTA).
13
- Use this tool whenever you encounter a schema error, IAM error, or setup error.
11
+ Fetches the latest troubleshooting and setup guides Over-The-Air (OTA) from ga4mcp.com.
12
+ Use this tool whenever you encounter a schema error, dimension_filter parse error,
13
+ IAM / 403 authorization error, or boot-time setup error.
14
14
 
15
15
  Args:
16
16
  topic: The topic of the guide to fetch. Valid options are "setup", "iam", or "schema".
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: google-analytics-mcp
3
- Version: 2.2.1
3
+ Version: 2.3.0
4
4
  Summary: Model Context Protocol for Google Analytics 4 (Data API) allowing autonomous agents to query dimensions and metrics. Gives agents analysis-ready GA4 access with schema discovery, server-side aggregation, and smart defaults.
5
5
  Author-email: Surendran B <reachsuren@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "google-analytics-mcp"
7
- version = "2.2.1"
7
+ version = "2.3.0"
8
8
  description = "Model Context Protocol for Google Analytics 4 (Data API) allowing autonomous agents to query dimensions and metrics. Gives agents analysis-ready GA4 access with schema discovery, server-side aggregation, and smart defaults."
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"