google_ads_compare_ad_performance
Compare performance between two ads to conduct A/B testing. Identify which ad drives better results using specified metrics and date range.
Instructions
Compare performance between two ads (A/B testing).
Args: customer_id: Customer ID (without hyphens) ad_id_1: First ad ID ad_id_2: Second ad ID date_range: Date range for comparison
Returns: Comparison report
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| customer_id | Yes | ||
| ad_id_1 | Yes | ||
| ad_id_2 | Yes | ||
| date_range | No | LAST_30_DAYS |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |
Implementation Reference
- tools/ads/mcp_tools_ads.py:532-608 (handler)Core handler function for the 'google_ads_compare_ad_performance' tool. Fetches performance data for two ads, formats a comparison report showing impressions, clicks, CTR, avg CPC, cost, conversions, and conversion rates, then determines a winner based on CTR and conversion rate.
@mcp.tool() def google_ads_compare_ad_performance( customer_id: str, ad_id_1: str, ad_id_2: str, date_range: str = "LAST_30_DAYS" ) -> str: """ Compare performance between two ads (A/B testing). Args: customer_id: Customer ID (without hyphens) ad_id_1: First ad ID ad_id_2: Second ad ID date_range: Date range for comparison Returns: Comparison report """ with performance_logger.track_operation('compare_ad_performance', customer_id=customer_id): try: # Get all ad performance client = get_auth_manager().get_client() ad_manager = AdManager(client) all_ads = ad_manager.get_ad_performance(customer_id, date_range=date_range) # Find the two ads ad1 = next((a for a in all_ads if a['ad_id'] == ad_id_1), None) ad2 = next((a for a in all_ads if a['ad_id'] == ad_id_2), None) if not ad1 or not ad2: return "❌ One or both ads not found" output = f"# Ad Performance Comparison ({date_range})\n\n" # Ad 1 output += f"## Ad A (ID: {ad_id_1})\n" metrics1 = ad1['metrics'] output += f"- **Impressions**: {metrics1['impressions']:,}\n" output += f"- **Clicks**: {metrics1['clicks']:,}\n" output += f"- **CTR**: {metrics1['ctr']:.2f}%\n" output += f"- **Avg CPC**: ${metrics1['average_cpc']:.2f}\n" output += f"- **Cost**: ${metrics1['cost']:,.2f}\n" output += f"- **Conversions**: {metrics1['conversions']:.2f}\n" conv_rate_1 = (metrics1['conversions'] / metrics1['clicks'] * 100) if metrics1['clicks'] > 0 else 0 output += f"- **Conv Rate**: {conv_rate_1:.2f}%\n\n" # Ad 2 output += f"## Ad B (ID: {ad_id_2})\n" metrics2 = ad2['metrics'] output += f"- **Impressions**: {metrics2['impressions']:,}\n" output += f"- **Clicks**: {metrics2['clicks']:,}\n" output += f"- **CTR**: {metrics2['ctr']:.2f}%\n" output += f"- **Avg CPC**: ${metrics2['average_cpc']:.2f}\n" output += f"- **Cost**: ${metrics2['cost']:,.2f}\n" output += f"- **Conversions**: {metrics2['conversions']:.2f}\n" conv_rate_2 = (metrics2['conversions'] / metrics2['clicks'] * 100) if metrics2['clicks'] > 0 else 0 output += f"- **Conv Rate**: {conv_rate_2:.2f}%\n\n" # Winner determination output += "## Analysis\n" if metrics1['ctr'] > metrics2['ctr']: output += f"🏆 Ad A has better CTR ({metrics1['ctr']:.2f}% vs {metrics2['ctr']:.2f}%)\n" else: output += f"🏆 Ad B has better CTR ({metrics2['ctr']:.2f}% vs {metrics1['ctr']:.2f}%)\n" if conv_rate_1 > conv_rate_2: output += f"🏆 Ad A has better conversion rate ({conv_rate_1:.2f}% vs {conv_rate_2:.2f}%)\n" else: output += f"🏆 Ad B has better conversion rate ({conv_rate_2:.2f}% vs {conv_rate_1:.2f}%)\n" return output except Exception as e: error_msg = ErrorHandler.handle_error(e, context="compare_ad_performance") return f"❌ Failed to compare ads: {error_msg}" - google_ads_mcp.py:498-508 (registration)Registration mechanism: _register_all_modular_tools() imports and calls register_ad_tools(mcp) from tools.ads.mcp_tools_ads, which registers the tool via the @mcp.tool() decorator.
def _register_all_modular_tools(): """Import and register every modular tool module.""" import importlib registered = 0 for label, module_path, func_name in _TOOL_MODULES: try: mod = importlib.import_module(module_path) register_fn = getattr(mod, func_name) register_fn(mcp) logger.info(f" ✓ {label}") - tools/ads/mcp_tools_ads.py:24-26 (registration)The register_ad_tools function definition where the @mcp.tool() decorator (on line 532) registers the tool with the FastMCP server.
def register_ad_tools(mcp: FastMCP): """Register ad management tools with MCP server.""" - managers/ad_manager.py:268-338 (helper)The get_ad_performance method in AdManager which queries the Google Ads API for ad metrics (impressions, clicks, CTR, avg CPC, cost, conversions) and is called by the comparison handler.
def get_ad_performance( self, customer_id: str, ad_group_id: Optional[str] = None, date_range: str = "LAST_30_DAYS" ) -> List[Dict[str, Any]]: """ Get ad performance metrics. Args: customer_id: Customer ID ad_group_id: Optional ad group ID to filter date_range: Date range for metrics Returns: List of ads with performance data """ query = f""" SELECT ad_group_ad.ad.id, ad_group_ad.ad.type, ad_group_ad.status, ad_group.id, ad_group.name, campaign.id, campaign.name, metrics.impressions, metrics.clicks, metrics.ctr, metrics.average_cpc, metrics.cost_micros, metrics.conversions, metrics.conversions_value FROM ad_group_ad WHERE segments.date DURING {date_range} """ if ad_group_id: query += f" AND ad_group.id = {ad_group_id}" query += " ORDER BY metrics.cost_micros DESC" ga_service = self.client.get_service("GoogleAdsService") response = ga_service.search(customer_id=customer_id, query=query) ads = [] for row in response: ads.append({ "ad_id": str(row.ad_group_ad.ad.id), "ad_type": row.ad_group_ad.ad.type_.name, "status": row.ad_group_ad.status.name, "ad_group": { "id": str(row.ad_group.id), "name": row.ad_group.name }, "campaign": { "id": str(row.campaign.id), "name": row.campaign.name }, "metrics": { "impressions": row.metrics.impressions, "clicks": row.metrics.clicks, "ctr": row.metrics.ctr, "average_cpc": row.metrics.average_cpc / 1_000_000 if row.metrics.average_cpc else 0, "cost": row.metrics.cost_micros / 1_000_000, "conversions": row.metrics.conversions, "conversions_value": row.metrics.conversions_value } }) return ads - google_ads_mcp.py:480-494 (registration)The _TOOL_MODULES list entry mapping 'ads' to 'tools.ads.mcp_tools_ads.register_ad_tools' for modular tool registration.
_TOOL_MODULES = [ ("campaigns", "tools.campaigns.mcp_tools_campaigns", "register_campaign_tools"), ("ad_groups", "tools.ad_groups.mcp_tools_ad_groups", "register_ad_group_tools"), ("keywords", "tools.keywords.mcp_tools_keywords", "register_keyword_tools"), ("ads", "tools.ads.mcp_tools_ads", "register_ad_tools"), ("bidding", "tools.bidding.mcp_tools_bidding", "register_bidding_tools"), ("automation", "tools.automation.mcp_tools_automation", "register_automation_tools"), ("audiences", "tools.audiences.mcp_tools_audiences", "register_audience_tools"), ("conversions", "tools.conversions.mcp_tools_conversions", "register_conversion_tools"), ("reporting", "tools.reporting.mcp_tools_reporting", "register_reporting_tools"), ("insights", "tools.insights.mcp_tools_insights", "register_insights_tools"), ("batch", "tools.batch.mcp_tools_batch", "register_batch_tools"), ("shopping_pmax", "tools.shopping_pmax.mcp_tools_shopping_pmax", "register_shopping_pmax_tools"), ("extensions", "tools.extensions.mcp_tools_extensions", "register_extension_tools"), ("local_app", "tools.local_app.mcp_tools_local_app", "register_local_app_tools"),