Skip to main content
Glama
johnoconnor0

Google Ads MCP Server

by johnoconnor0
mcp_tools_insights.py38.8 kB
""" MCP Tools - Insights & Recommendations Tools for AI-powered performance insights, budget optimization, and competitive intelligence. Tools: 1. google_ads_performance_insights - AI-powered performance analysis 2. google_ads_trend_analysis - Trend detection and anomaly identification 3. google_ads_budget_pacing - Budget pacing and spending velocity 4. google_ads_budget_recommendations - Budget reallocation suggestions 5. google_ads_wasted_spend_analysis - Identify inefficient spending 6. google_ads_auction_insights - Competitive auction intelligence 7. google_ads_opportunity_finder - Find optimization opportunities 8. google_ads_performance_forecaster - Predict future performance """ from typing import Optional from insights_manager import InsightsManager from auth_manager import get_auth_manager from error_handler import ErrorHandler from logger import get_logger, get_performance_logger, get_audit_logger logger = get_logger(__name__) performance_logger = get_performance_logger() audit_logger = get_audit_logger() 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)")

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/johnoconnor0/google-ads-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server