google_ads_auction_insights
Analyze auction insights to improve campaign competitive position. Obtain impression share metrics, identify budget or ad rank constraints, and receive actionable recommendations.
Instructions
Get auction insights and competitive intelligence for a campaign.
Provides:
Impression share metrics (overall, top, absolute top)
Competitive position analysis
Primary constraints (budget vs. ad rank)
Specific recommendations to improve auction performance
Args: customer_id: Google Ads customer ID (10 digits, no hyphens) campaign_id: Campaign ID to analyze date_range: Date range (LAST_7_DAYS, LAST_30_DAYS, LAST_90_DAYS)
Returns: Auction insights with competitive analysis
Example: google_ads_auction_insights( customer_id="1234567890", campaign_id="12345678", date_range="LAST_30_DAYS" )
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| customer_id | Yes | ||
| campaign_id | Yes | ||
| date_range | No | LAST_30_DAYS |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |
Implementation Reference
- The main tool handler for google_ads_auction_insights. This is an MCP-tool-decorated function that takes customer_id, campaign_id, and date_range, fetches auction insights via InsightsManager.get_auction_insights(), and formats the output into a human-readable analysis with competitive position, impression share metrics, primary constraint analysis, and recommendations.
@mcp.tool() def google_ads_auction_insights( customer_id: str, campaign_id: str, date_range: str = "LAST_30_DAYS" ) -> str: """Get auction insights and competitive intelligence for a campaign. Provides: - Impression share metrics (overall, top, absolute top) - Competitive position analysis - Primary constraints (budget vs. ad rank) - Specific recommendations to improve auction performance Args: customer_id: Google Ads customer ID (10 digits, no hyphens) campaign_id: Campaign ID to analyze date_range: Date range (LAST_7_DAYS, LAST_30_DAYS, LAST_90_DAYS) Returns: Auction insights with competitive analysis Example: google_ads_auction_insights( customer_id="1234567890", campaign_id="12345678", date_range="LAST_30_DAYS" ) """ with performance_logger.track_operation('auction_insights', customer_id=customer_id): try: client = get_auth_manager().get_client() insights_manager = InsightsManager(client) result = insights_manager.get_auction_insights( customer_id=customer_id, campaign_id=campaign_id, date_range=date_range ) if 'error' in result: return f"ā {result['error']}" audit_logger.log_api_call( customer_id=customer_id, operation='get_auction_insights', campaign_id=campaign_id, status='success' ) # Format response output = f"# š Auction Insights Report\n\n" output += f"**Campaign**: {result['campaign_name']}\n\n" # Competitive position position = result['competitive_position'] position_emoji = "š¢" if position == "STRONG" else "š”" if position == "MODERATE" else "š“" output += f"## {position_emoji} Competitive Position: {position}\n\n" # Impression share metrics output += "## Impression Share Metrics\n\n" output += f"- **Overall Impression Share**: {result['impression_share']:.1%}\n" output += f"- **Top Impression Share**: {result['top_impression_share']:.1%}\n" output += f"- **Absolute Top Impression Share**: {result['absolute_top_impression_share']:.1%}\n\n" # Lost impression share output += "## Lost Impression Share\n\n" output += f"- **Rank Lost IS**: {result['rank_lost_is']:.1%}\n" output += f"- **Budget Lost IS**: {result['budget_lost_is']:.1%}\n\n" # Primary constraint constraint = result['primary_constraint'] output += f"## šÆ Primary Constraint: {constraint}\n\n" output += f"{result['constraint_message']}\n\n" if constraint == "BUDGET": output += "š” **Quick Fix**: Increase your daily budget to capture more impressions.\n\n" elif constraint == "AD_RANK": output += "š” **Quick Fix**: Improve Quality Score or increase bids to compete more effectively.\n\n" # Recommendations output += "## š Recommendations\n\n" for i, rec in enumerate(result['recommendations'], 1): output += f"{i}. {rec}\n" output += "\n---\n\n" # Opportunity analysis total_lost = result['rank_lost_is'] + result['budget_lost_is'] if total_lost > 0.3: output += f"ā ļø **Major Opportunity**: You're losing {total_lost:.0%} of possible impressions. " output += "Addressing these constraints could significantly increase visibility.\n" elif total_lost > 0.1: output += f"š” **Moderate Opportunity**: Capturing the missing {total_lost:.0%} of impressions " output += "could improve performance.\n" else: output += "ā **Strong Performance**: You're capturing most available impressions in your target market.\n" return output except Exception as e: error_msg = ErrorHandler.handle_error(e, context="auction_insights") return f"ā Failed to get auction insights: {error_msg}" - The input schema/parameters for the google_ads_auction_insights tool: customer_id (str, required), campaign_id (str, required), and date_range (str, optional, default LAST_30_DAYS). The docstring describes the output and competitive intelligence provided.
"""Get auction insights and competitive intelligence for a campaign. Provides: - Impression share metrics (overall, top, absolute top) - Competitive position analysis - Primary constraints (budget vs. ad rank) - Specific recommendations to improve auction performance Args: customer_id: Google Ads customer ID (10 digits, no hyphens) campaign_id: Campaign ID to analyze date_range: Date range (LAST_7_DAYS, LAST_30_DAYS, LAST_90_DAYS) Returns: Auction insights with competitive analysis Example: google_ads_auction_insights( customer_id="1234567890", campaign_id="12345678", date_range="LAST_30_DAYS" ) """ - tools/insights/mcp_tools_insights.py:28-867 (registration)The register_insights_tools function that registers all 8 insight tools (including google_ads_auction_insights) using @mcp.tool() decorator within its scope.
def register_insights_tools(mcp): """Register all insights and recommendations MCP tools.""" @mcp.tool() def google_ads_performance_insights( customer_id: str, entity_type: str = "CAMPAIGN", entity_id: Optional[str] = None, date_range: str = "LAST_30_DAYS" ) -> str: """Generate AI-powered performance insights for campaigns, ad groups, keywords, or ads. Analyzes performance metrics and provides actionable recommendations for: - Low CTR (below industry benchmarks) - Low conversion rates - Low impression share - Low quality scores - High performers worthy of increased budget Args: customer_id: Google Ads customer ID (10 digits, no hyphens) entity_type: Entity to analyze - CAMPAIGN, AD_GROUP, KEYWORD, or AD entity_id: Optional specific entity ID (if not provided, analyzes all) date_range: Date range (LAST_7_DAYS, LAST_30_DAYS, LAST_90_DAYS, THIS_MONTH, LAST_MONTH) Returns: Performance insights with AI-generated recommendations Example: google_ads_performance_insights( customer_id="1234567890", entity_type="CAMPAIGN", date_range="LAST_30_DAYS" ) """ with performance_logger.track_operation('performance_insights', customer_id=customer_id): try: client = get_auth_manager().get_client() insights_manager = InsightsManager(client) result = insights_manager.get_performance_insights( customer_id=customer_id, entity_type=entity_type, entity_id=entity_id, date_range=date_range ) if 'error' in result: return f"ā {result['error']}" audit_logger.log_api_call( customer_id=customer_id, operation='get_performance_insights', entity_type=entity_type, status='success' ) # Format response output = f"# š Performance Insights Report\n\n" output += f"**Entity Type**: {result['entity_type']}\n" output += f"**Total Analyzed**: {result['total_analyzed']}\n" output += f"**Insights Found**: {result['insights_count']}\n\n" if result['insights_count'] == 0: output += "ā **All entities are performing within expected ranges!**\n\n" output += "No major issues detected. Continue monitoring performance.\n" return output output += "---\n\n" # Group insights by severity high_severity = [i for i in result['insights'] if any( insight['severity'] == 'HIGH' for insight in i['insights'] )] medium_severity = [i for i in result['insights'] if any( insight['severity'] == 'MEDIUM' for insight in i['insights'] ) and i not in high_severity] positive = [i for i in result['insights'] if any( insight['severity'] == 'POSITIVE' for insight in i['insights'] )] # High priority issues if high_severity: output += "## šØ High Priority Issues\n\n" for entity in high_severity[:5]: # Top 5 output += f"### {entity['entity_name']}\n" output += f"**Cost**: ${entity['metrics']['cost']:,.2f} | " output += f"**Conversions**: {entity['metrics']['conversions']}\n\n" for insight in entity['insights']: if insight['severity'] == 'HIGH': output += f"**ā ļø {insight['type'].replace('_', ' ').title()}**\n" output += f"- {insight['message']}\n" output += f"- š” *{insight['recommendation']}*\n\n" # Medium priority issues if medium_severity: output += "## ā” Medium Priority Opportunities\n\n" for entity in medium_severity[:3]: # Top 3 output += f"### {entity['entity_name']}\n" for insight in entity['insights']: if insight['severity'] == 'MEDIUM': output += f"- {insight['message']}\n" output += f" š” *{insight['recommendation']}*\n\n" # Positive performers if positive: output += "## ⨠Top Performers\n\n" for entity in positive[:3]: # Top 3 output += f"### {entity['entity_name']}\n" output += f"**Cost**: ${entity['metrics']['cost']:,.2f} | " output += f"**CTR**: {entity['metrics']['ctr']:.2%}\n" for insight in entity['insights']: if insight['severity'] == 'POSITIVE': output += f"- ā {insight['message']}\n" output += f" š” *{insight['recommendation']}*\n\n" output += "---\n\n" output += "š” **Next Steps**: Prioritize high-severity issues first, then explore medium-priority opportunities.\n" return output except Exception as e: error_msg = ErrorHandler.handle_error(e, context="performance_insights") return f"ā Failed to generate performance insights: {error_msg}" @mcp.tool() def google_ads_trend_analysis( customer_id: str, campaign_id: Optional[str] = None, lookback_days: int = 30 ) -> str: """Analyze performance trends and detect anomalies over time. Identifies: - Increasing/decreasing cost trends - Conversion performance trends - Anomalous days with unusual spending or performance - Provides daily performance data for visualization Args: customer_id: Google Ads customer ID (10 digits, no hyphens) campaign_id: Optional campaign ID filter (analyzes all campaigns if not provided) lookback_days: Number of days to analyze (7-90) Returns: Trend analysis with anomaly detection Example: google_ads_trend_analysis( customer_id="1234567890", lookback_days=30 ) """ with performance_logger.track_operation('trend_analysis', customer_id=customer_id): try: client = get_auth_manager().get_client() insights_manager = InsightsManager(client) result = insights_manager.analyze_trends( customer_id=customer_id, campaign_id=campaign_id, lookback_days=lookback_days ) if 'error' in result: return f"ā {result['error']}" audit_logger.log_api_call( customer_id=customer_id, operation='analyze_trends', campaign_id=campaign_id, status='success' ) # Format response output = f"# š Trend Analysis Report\n\n" output += f"**Lookback Period**: {result['lookback_days']} days\n" output += f"**Data Points**: {result['data_points']}\n\n" trends = result['trends'] output += "## Cost Trends\n\n" trend_emoji = "š" if trends['cost_trend'] == "INCREASING" else \ "š" if trends['cost_trend'] == "DECREASING" else "ā”ļø" output += f"{trend_emoji} **{trends['cost_trend']}** " output += f"({trends['cost_change_pct']:+.1f}%)\n\n" if abs(trends['cost_change_pct']) > 20: output += f"ā ļø **Significant change detected!** Cost has changed by {abs(trends['cost_change_pct']):.0f}%.\n\n" output += "## Conversion Trends\n\n" conv_emoji = "š" if trends['conversion_trend'] == "INCREASING" else \ "š" if trends['conversion_trend'] == "DECREASING" else "ā”ļø" output += f"{conv_emoji} **{trends['conversion_trend']}** " output += f"({trends['conversion_change_pct']:+.1f}%)\n\n" if trends['conversion_trend'] == "DECREASING" and abs(trends['conversion_change_pct']) > 15: output += f"šØ **Action Required**: Conversions have dropped {abs(trends['conversion_change_pct']):.0f}%. Investigate immediately.\n\n" # Anomalies if result['anomalies']: output += "## š Anomalies Detected\n\n" output += f"Found {len(result['anomalies'])} unusual data points:\n\n" for anomaly in result['anomalies'][:5]: # Top 5 output += f"- **{anomaly['date']}**: {anomaly['metric'].title()} = ${anomaly['value']:,.2f} " output += f"({anomaly['deviation']:.1f}Ļ from mean)\n" output += "\nš” Review these dates for campaign changes, external events, or data issues.\n\n" else: output += "## ā No Anomalies\n\n" output += "Performance has been consistent with no unusual spikes or drops.\n\n" # Recent performance summary output += "## Recent Daily Performance\n\n" recent_days = result['daily_data'][-7:] # Last 7 days output += "| Date | Impressions | Clicks | Cost | Conversions |\n" output += "|------|-------------|--------|------|-------------|\n" for day in recent_days: output += f"| {day['date']} | {day['impressions']:,} | {day['clicks']:,} | " output += f"${day['cost']:,.2f} | {day['conversions']:.1f} |\n" return output except Exception as e: error_msg = ErrorHandler.handle_error(e, context="trend_analysis") return f"ā Failed to analyze trends: {error_msg}" @mcp.tool() def google_ads_budget_pacing( customer_id: str, campaign_id: str ) -> str: """Analyze budget pacing and spending velocity for a campaign. Shows: - Current spend vs. expected spend - Pacing percentage (overpacing, underpacing, on track) - Projected month-end spend - Days remaining in the month - Recommendations for budget adjustments Args: customer_id: Google Ads customer ID (10 digits, no hyphens) campaign_id: Campaign ID to analyze Returns: Budget pacing analysis with recommendations Example: google_ads_budget_pacing( customer_id="1234567890", campaign_id="12345678" ) """ with performance_logger.track_operation('budget_pacing', customer_id=customer_id): try: client = get_auth_manager().get_client() insights_manager = InsightsManager(client) result = insights_manager.get_budget_pacing( customer_id=customer_id, campaign_id=campaign_id ) if 'error' in result: return f"ā {result['error']}" audit_logger.log_api_call( customer_id=customer_id, operation='get_budget_pacing', campaign_id=campaign_id, status='success' ) # Format response output = f"# š° Budget Pacing Report\n\n" output += f"**Campaign**: {result['campaign_name']}\n" output += f"**Budget Period**: {result['budget_period']}\n\n" output += "## Budget Overview\n\n" output += f"- **Monthly Budget**: ${result['monthly_budget']:,.2f}\n" output += f"- **Current Spend**: ${result['current_spend']:,.2f}\n" output += f"- **Expected Spend**: ${result['expected_spend']:,.2f}\n" output += f"- **Projected Month-End**: ${result['projected_spend']:,.2f}\n\n" output += "## Pacing Status\n\n" status = result['status'] pace = result['pace_percentage'] if status == "OVERPACING": output += f"šØ **OVERPACING** ({pace:.0f}%)\n\n" output += f"{result['message']}\n\n" output += "**ā ļø Risk**: Budget may be exhausted before month-end.\n\n" output += "**Recommended Actions**:\n" output += "- Reduce bids or pause low-performing keywords\n" output += "- Narrow targeting to control costs\n" output += "- Consider increasing monthly budget if performance is strong\n" elif status == "UNDERPACING": output += f"ā” **UNDERPACING** ({pace:.0f}%)\n\n" output += f"{result['message']}\n\n" output += "**š” Opportunity**: Budget is underutilized.\n\n" output += "**Recommended Actions**:\n" output += "- Increase bids to capture more traffic\n" output += "- Expand targeting (keywords, locations, audiences)\n" output += "- Review if budget is too high for current strategy\n" else: output += f"ā **ON TRACK** ({pace:.0f}%)\n\n" output += f"{result['message']}\n\n" output += "Continue monitoring daily spend to maintain healthy pacing.\n" output += "\n## Timeline\n\n" output += f"- **Days Elapsed**: {result['days_elapsed']}\n" output += f"- **Days Remaining**: {result['days_remaining']}\n\n" budget_remaining = result['monthly_budget'] - result['current_spend'] daily_budget_needed = budget_remaining / result['days_remaining'] if result['days_remaining'] > 0 else 0 output += f"**Budget Remaining**: ${budget_remaining:,.2f}\n" output += f"**Required Daily Spend**: ${daily_budget_needed:,.2f}\n" return output except Exception as e: error_msg = ErrorHandler.handle_error(e, context="budget_pacing") return f"ā Failed to analyze budget pacing: {error_msg}" @mcp.tool() def google_ads_budget_recommendations( customer_id: str, date_range: str = "LAST_30_DAYS" ) -> str: """Generate AI-powered budget reallocation recommendations. Identifies: - Budget-constrained campaigns losing impression share - Underperforming campaigns with excessive spend - High ROAS campaigns deserving more budget - Prioritized recommendations with expected impact Args: customer_id: Google Ads customer ID (10 digits, no hyphens) date_range: Date range for analysis (LAST_7_DAYS, LAST_30_DAYS, LAST_90_DAYS) Returns: Budget reallocation recommendations prioritized by impact Example: google_ads_budget_recommendations( customer_id="1234567890", date_range="LAST_30_DAYS" ) """ with performance_logger.track_operation('budget_recommendations', customer_id=customer_id): try: client = get_auth_manager().get_client() insights_manager = InsightsManager(client) recommendations = insights_manager.get_budget_recommendations( customer_id=customer_id, date_range=date_range ) audit_logger.log_api_call( customer_id=customer_id, operation='get_budget_recommendations', status='success' ) # Format response output = f"# š” Budget Optimization Recommendations\n\n" if not recommendations: output += "ā **All budgets are properly allocated!**\n\n" output += "No immediate reallocation opportunities detected.\n" return output output += f"Found **{len(recommendations)}** optimization opportunities:\n\n" # Group by type increase_recs = [r for r in recommendations if r['type'] == 'INCREASE_BUDGET'] decrease_recs = [r for r in recommendations if r['type'] == 'DECREASE_BUDGET'] # Increase recommendations if increase_recs: output += "## š Budget Increase Opportunities\n\n" total_increase = sum(r['increase_amount'] for r in increase_recs) output += f"**Total Recommended Increase**: ${total_increase:,.2f}/day\n\n" for rec in increase_recs: priority_emoji = "š“" if rec['priority'] == 'HIGH' else "š”" output += f"### {priority_emoji} {rec['campaign_name']}\n\n" output += f"**Current Budget**: ${rec['current_budget']:,.2f}/day\n" output += f"**Recommended**: ${rec['recommended_budget']:,.2f}/day " output += f"(+${rec['increase_amount']:,.2f})\n\n" output += f"**Reason**: {rec['reason']}\n" output += f"**Expected Impact**: {rec['expected_impact']}\n\n" # Decrease recommendations if decrease_recs: output += "## š Budget Decrease Opportunities\n\n" total_decrease = sum(r['decrease_amount'] for r in decrease_recs) output += f"**Total Recommended Decrease**: ${total_decrease:,.2f}/day\n\n" for rec in decrease_recs: output += f"### {rec['campaign_name']}\n\n" output += f"**Current Budget**: ${rec['current_budget']:,.2f}/day\n" output += f"**Recommended**: ${rec['recommended_budget']:,.2f}/day " output += f"(-${rec['decrease_amount']:,.2f})\n\n" output += f"**Reason**: {rec['reason']}\n" output += f"**Expected Impact**: {rec['expected_impact']}\n\n" output += "---\n\n" output += "š” **Implementation Tip**: Start with high-priority recommendations and monitor performance for 7 days before making additional changes.\n" return output except Exception as e: error_msg = ErrorHandler.handle_error(e, context="budget_recommendations") return f"ā Failed to generate budget recommendations: {error_msg}" @mcp.tool() def google_ads_wasted_spend_analysis( customer_id: str, date_range: str = "LAST_30_DAYS", min_cost: float = 10.0 ) -> str: """Identify sources of wasted ad spend and optimization opportunities. Analyzes: - Keywords with high cost but no conversions - Poor match type usage - Inefficient spending patterns - Specific recommendations to reduce waste Args: customer_id: Google Ads customer ID (10 digits, no hyphens) date_range: Date range for analysis (LAST_7_DAYS, LAST_30_DAYS, LAST_90_DAYS) min_cost: Minimum cost threshold for analysis (default: $10) Returns: Wasted spend analysis with actionable recommendations Example: google_ads_wasted_spend_analysis( customer_id="1234567890", date_range="LAST_30_DAYS", min_cost=20.0 ) """ with performance_logger.track_operation('wasted_spend_analysis', customer_id=customer_id): try: client = get_auth_manager().get_client() insights_manager = InsightsManager(client) result = insights_manager.analyze_wasted_spend( customer_id=customer_id, date_range=date_range, min_cost=min_cost ) audit_logger.log_api_call( customer_id=customer_id, operation='analyze_wasted_spend', status='success' ) # Format response output = f"# š Wasted Spend Analysis\n\n" output += f"**Date Range**: {result['date_range']}\n" output += f"**Total Wasted Spend**: ${result['total_wasted_spend']:,.2f}\n\n" if result['total_wasted_spend'] == 0: output += "ā **No significant wasted spend detected!**\n\n" output += "All keywords with spend are generating conversions. Great job!\n" return output output += "---\n\n" # Waste categories output += "## Waste Categories\n\n" for category, data in result['waste_categories'].items(): output += f"### {category.replace('_', ' ').title()}\n\n" output += f"- **Count**: {data['count']} keywords\n" output += f"- **Total Cost**: ${data['cost']:,.2f}\n" output += f"- **Description**: {data['description']}\n\n" # Top wasters if result['top_wasters']: output += "## šØ Top 10 Wasted Spend Keywords\n\n" output += "| Keyword | Match Type | Campaign | Cost | Clicks | Conversions |\n" output += "|---------|------------|----------|------|--------|-------------|\n" for kw in result['top_wasters']: output += f"| {kw['keyword']} | {kw['match_type']} | " output += f"{kw['campaign']} | ${kw['cost']:,.2f} | " output += f"{kw['clicks']} | {kw['conversions']} |\n" output += "\n" # Recommendations output += "## š” Recommended Actions\n\n" for i, rec in enumerate(result['recommendations'], 1): output += f"{i}. {rec}\n" output += "\n---\n\n" output += "**š° Potential Monthly Savings**: " monthly_savings = result['total_wasted_spend'] * (30 / 30) # Normalize to monthly output += f"${monthly_savings:,.2f}\n" return output except Exception as e: error_msg = ErrorHandler.handle_error(e, context="wasted_spend_analysis") return f"ā Failed to analyze wasted spend: {error_msg}" @mcp.tool() def google_ads_auction_insights( customer_id: str, campaign_id: str, date_range: str = "LAST_30_DAYS" ) -> str: """Get auction insights and competitive intelligence for a campaign. Provides: - Impression share metrics (overall, top, absolute top) - Competitive position analysis - Primary constraints (budget vs. ad rank) - Specific recommendations to improve auction performance Args: customer_id: Google Ads customer ID (10 digits, no hyphens) campaign_id: Campaign ID to analyze date_range: Date range (LAST_7_DAYS, LAST_30_DAYS, LAST_90_DAYS) Returns: Auction insights with competitive analysis Example: google_ads_auction_insights( customer_id="1234567890", campaign_id="12345678", date_range="LAST_30_DAYS" ) """ with performance_logger.track_operation('auction_insights', customer_id=customer_id): try: client = get_auth_manager().get_client() insights_manager = InsightsManager(client) result = insights_manager.get_auction_insights( customer_id=customer_id, campaign_id=campaign_id, date_range=date_range ) if 'error' in result: return f"ā {result['error']}" audit_logger.log_api_call( customer_id=customer_id, operation='get_auction_insights', campaign_id=campaign_id, status='success' ) # Format response output = f"# š Auction Insights Report\n\n" output += f"**Campaign**: {result['campaign_name']}\n\n" # Competitive position position = result['competitive_position'] position_emoji = "š¢" if position == "STRONG" else "š”" if position == "MODERATE" else "š“" output += f"## {position_emoji} Competitive Position: {position}\n\n" # Impression share metrics output += "## Impression Share Metrics\n\n" output += f"- **Overall Impression Share**: {result['impression_share']:.1%}\n" output += f"- **Top Impression Share**: {result['top_impression_share']:.1%}\n" output += f"- **Absolute Top Impression Share**: {result['absolute_top_impression_share']:.1%}\n\n" # Lost impression share output += "## Lost Impression Share\n\n" output += f"- **Rank Lost IS**: {result['rank_lost_is']:.1%}\n" output += f"- **Budget Lost IS**: {result['budget_lost_is']:.1%}\n\n" # Primary constraint constraint = result['primary_constraint'] output += f"## šÆ Primary Constraint: {constraint}\n\n" output += f"{result['constraint_message']}\n\n" if constraint == "BUDGET": output += "š” **Quick Fix**: Increase your daily budget to capture more impressions.\n\n" elif constraint == "AD_RANK": output += "š” **Quick Fix**: Improve Quality Score or increase bids to compete more effectively.\n\n" # Recommendations output += "## š Recommendations\n\n" for i, rec in enumerate(result['recommendations'], 1): output += f"{i}. {rec}\n" output += "\n---\n\n" # Opportunity analysis total_lost = result['rank_lost_is'] + result['budget_lost_is'] if total_lost > 0.3: output += f"ā ļø **Major Opportunity**: You're losing {total_lost:.0%} of possible impressions. " output += "Addressing these constraints could significantly increase visibility.\n" elif total_lost > 0.1: output += f"š” **Moderate Opportunity**: Capturing the missing {total_lost:.0%} of impressions " output += "could improve performance.\n" else: output += "ā **Strong Performance**: You're capturing most available impressions in your target market.\n" return output except Exception as e: error_msg = ErrorHandler.handle_error(e, context="auction_insights") return f"ā Failed to get auction insights: {error_msg}" @mcp.tool() def google_ads_opportunity_finder( customer_id: str, opportunity_type: str = "ALL" ) -> str: """Find optimization opportunities across your Google Ads account. Combines multiple analyses to identify: - Budget optimization opportunities - Wasted spend to eliminate - Performance improvement areas - Quick wins for immediate impact Args: customer_id: Google Ads customer ID (10 digits, no hyphens) opportunity_type: Type of opportunities to find (ALL, BUDGET, WASTE, PERFORMANCE) Returns: Comprehensive opportunity analysis with prioritized recommendations Example: google_ads_opportunity_finder( customer_id="1234567890", opportunity_type="ALL" ) """ with performance_logger.track_operation('opportunity_finder', customer_id=customer_id): try: client = get_auth_manager().get_client() insights_manager = InsightsManager(client) output = f"# šÆ Opportunity Finder Report\n\n" opportunities = [] # Budget opportunities if opportunity_type in ["ALL", "BUDGET"]: budget_recs = insights_manager.get_budget_recommendations( customer_id=customer_id, date_range="LAST_30_DAYS" ) for rec in budget_recs: opportunities.append({ 'type': 'BUDGET', 'priority': rec['priority'], 'campaign': rec['campaign_name'], 'action': rec['type'], 'impact': rec['expected_impact'], 'details': rec }) # Wasted spend opportunities if opportunity_type in ["ALL", "WASTE"]: waste_analysis = insights_manager.analyze_wasted_spend( customer_id=customer_id, date_range="LAST_30_DAYS", min_cost=10.0 ) if waste_analysis['total_wasted_spend'] > 0: opportunities.append({ 'type': 'WASTE_REDUCTION', 'priority': 'HIGH', 'campaign': 'Multiple', 'action': 'REDUCE_WASTE', 'impact': f"Save ${waste_analysis['total_wasted_spend']:,.2f}", 'details': waste_analysis }) audit_logger.log_api_call( customer_id=customer_id, operation='opportunity_finder', status='success' ) # Format response if not opportunities: output += "ā **No immediate opportunities found!**\n\n" output += "Your account is well-optimized. Continue monitoring performance.\n" return output output += f"Found **{len(opportunities)}** optimization opportunities:\n\n" # Sort by priority high_priority = [o for o in opportunities if o['priority'] == 'HIGH'] medium_priority = [o for o in opportunities if o['priority'] == 'MEDIUM'] # High priority opportunities if high_priority: output += "## š“ High Priority Opportunities\n\n" for opp in high_priority: output += f"### {opp['type'].replace('_', ' ').title()}\n" output += f"- **Campaign**: {opp['campaign']}\n" output += f"- **Action**: {opp['action'].replace('_', ' ').title()}\n" output += f"- **Expected Impact**: {opp['impact']}\n\n" # Medium priority opportunities if medium_priority: output += "## š” Medium Priority Opportunities\n\n" for opp in medium_priority: output += f"### {opp['type'].replace('_', ' ').title()}\n" output += f"- **Campaign**: {opp['campaign']}\n" output += f"- **Action**: {opp['action'].replace('_', ' ').title()}\n" output += f"- **Expected Impact**: {opp['impact']}\n\n" output += "---\n\n" output += "š” **Next Steps**: Implement high-priority opportunities first for maximum impact.\n" return output except Exception as e: error_msg = ErrorHandler.handle_error(e, context="opportunity_finder") return f"ā Failed to find opportunities: {error_msg}" @mcp.tool() def google_ads_performance_forecaster( customer_id: str, campaign_id: str, forecast_days: int = 30 ) -> str: """Predict future campaign performance based on historical trends. Uses historical data to forecast: - Projected spend - Estimated conversions - Expected ROAS - Confidence intervals Args: customer_id: Google Ads customer ID (10 digits, no hyphens) campaign_id: Campaign ID to forecast forecast_days: Number of days to forecast (7-90) Returns: Performance forecast with confidence ranges Example: google_ads_performance_forecaster( customer_id="1234567890", campaign_id="12345678", forecast_days=30 ) """ with performance_logger.track_operation('performance_forecaster', customer_id=customer_id): try: client = get_auth_manager().get_client() insights_manager = InsightsManager(client) # Get trend data for forecasting trend_data = insights_manager.analyze_trends( customer_id=customer_id, campaign_id=campaign_id, lookback_days=30 ) if 'error' in trend_data: return f"ā {trend_data['error']}" audit_logger.log_api_call( customer_id=customer_id, operation='performance_forecaster', campaign_id=campaign_id, status='success' ) # Simple linear forecast based on recent trend daily_data = trend_data['daily_data'] recent_avg_cost = sum(d['cost'] for d in daily_data[-7:]) / 7 recent_avg_conversions = sum(d['conversions'] for d in daily_data[-7:]) / 7 trend = trend_data['trends'] # Apply trend multiplier trend_multiplier = 1.0 if trend['cost_trend'] == "INCREASING": trend_multiplier = 1 + (abs(trend['cost_change_pct']) / 100 / 2) # Half the change rate elif trend['cost_trend'] == "DECREASING": trend_multiplier = 1 - (abs(trend['cost_change_pct']) / 100 / 2) forecasted_daily_cost = recent_avg_cost * trend_multiplier forecasted_daily_conversions = recent_avg_conversions * trend_multiplier total_forecasted_cost = forecasted_daily_cost * forecast_days total_forecasted_conversions = forecasted_daily_conversions * forecast_days # Format response output = f"# š® Performance Forecast\n\n" output += f"**Forecast Period**: Next {forecast_days} days\n" output += f"**Based On**: Last 30 days of historical data\n\n" output += "## Projected Performance\n\n" output += f"- **Total Spend**: ${total_forecasted_cost:,.2f}\n" output += f"- **Total Conversions**: {total_forecasted_conversions:.0f}\n" output += f"- **Avg Daily Spend**: ${forecasted_daily_cost:,.2f}\n" output += f"- **Avg Daily Conversions**: {forecasted_daily_conversions:.1f}\n\n" if total_forecasted_conversions > 0: forecasted_cpa = total_forecasted_cost / total_forecasted_conversions output += f"- **Projected CPA**: ${forecasted_cpa:,.2f}\n\n" output += "## Trend Context\n\n" output += f"- **Cost Trend**: {trend['cost_trend']} ({trend['cost_change_pct']:+.1f}%)\n" output += f"- **Conversion Trend**: {trend['conversion_trend']} ({trend['conversion_change_pct']:+.1f}%)\n\n" output += "---\n\n" output += "ā ļø **Note**: Forecasts are estimates based on current trends. " output += "Actual performance may vary due to seasonality, competition, and market changes.\n" return output except Exception as e: error_msg = ErrorHandler.handle_error(e, context="performance_forecaster") return f"ā Failed to generate forecast: {error_msg}" logger.info("Insights and recommendations tools registered (8 tools)") - google_ads_mcp.py:490-495 (registration)The top-level registration entry point: the _TOOL_MODULES list maps the 'insights' label to 'tools.insights.mcp_tools_insights' module and 'register_insights_tools' function, which is dynamically imported and called.
("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"), ] - managers/insights_manager.py:522-598 (helper)The underlying business logic: InsightsManager.get_auction_insights() queries Google Ads API for impression share metrics, calculates competitive position (STRONG/MODERATE/WEAK), identifies primary constraint (BUDGET vs AD_RANK), and generates recommendations via the helper _get_auction_recommendations().
def get_auction_insights( self, customer_id: str, campaign_id: str, date_range: str = "LAST_30_DAYS" ) -> Dict[str, Any]: """Get auction insights and competitive data. Args: customer_id: Customer ID (without hyphens) campaign_id: Campaign ID date_range: Date range Returns: Auction insights data """ ga_service = self.client.get_service("GoogleAdsService") query = f""" SELECT campaign.id, campaign.name, metrics.search_impression_share, metrics.search_rank_lost_impression_share, metrics.search_budget_lost_impression_share, metrics.search_top_impression_share, metrics.search_absolute_top_impression_share, metrics.search_exact_match_impression_share FROM campaign WHERE campaign.id = {campaign_id} AND segments.date DURING {date_range} """ response = ga_service.search(customer_id=customer_id, query=query) results = list(response) if not results: return {'error': 'No auction insights data available'} row = results[0] metrics = row.metrics # Calculate competitive position total_is = metrics.search_impression_share rank_lost = metrics.search_rank_lost_impression_share budget_lost = metrics.search_budget_lost_impression_share competitive_position = "STRONG" if total_is > 0.7 else \ "MODERATE" if total_is > 0.4 else "WEAK" # Identify primary constraint if budget_lost > rank_lost: primary_constraint = "BUDGET" constraint_message = f"Budget is limiting visibility ({budget_lost:.0%} lost)" elif rank_lost > budget_lost: primary_constraint = "AD_RANK" constraint_message = f"Ad rank is limiting visibility ({rank_lost:.0%} lost)" else: primary_constraint = "NONE" constraint_message = "No significant constraints" return { 'campaign_id': campaign_id, 'campaign_name': row.campaign.name, 'impression_share': total_is, 'top_impression_share': metrics.search_top_impression_share, 'absolute_top_impression_share': metrics.search_absolute_top_impression_share, 'rank_lost_is': rank_lost, 'budget_lost_is': budget_lost, 'competitive_position': competitive_position, 'primary_constraint': primary_constraint, 'constraint_message': constraint_message, 'recommendations': self._get_auction_recommendations( total_is, rank_lost, budget_lost, metrics.search_top_impression_share ) }