Skip to main content
Glama
johnoconnor0

Google Ads MCP Server

by johnoconnor0
mcp_tools_conversions.py30.3 kB
""" MCP Tools - Conversion Tracking & Attribution Provides 10 MCP tools for conversion tracking: Conversion Action Management (4 tools): 1. google_ads_create_conversion_action - Create conversion tracking 2. google_ads_list_conversion_actions - List all conversions 3. google_ads_get_conversion_tag - Get tracking tag/snippet 4. google_ads_set_attribution_model - Set attribution model Offline Conversion Import (3 tools): 5. google_ads_upload_offline_conversions - Upload offline conversions 6. google_ads_upload_call_conversions - Upload call conversions 7. google_ads_upload_store_sales - Upload store sales (uses offline conversions) Performance & Reporting (3 tools): 8. google_ads_get_conversion_performance - Conversion performance metrics 9. google_ads_conversion_summary_report - Account-wide conversion summary 10. google_ads_update_conversion_action - Update conversion settings """ from typing import Optional, List, Dict, Any from conversion_manager import ( ConversionManager, ConversionActionConfig, ConversionActionCategory, ConversionOrigin, AttributionModel ) from auth_manager import get_auth_manager from error_handler import ErrorHandler from logger import performance_logger, audit_logger import json def register_conversion_tools(mcp): """Register all conversion tracking tools with the MCP server. Args: mcp: FastMCP server instance """ @mcp.tool() def google_ads_create_conversion_action( customer_id: str, conversion_name: str, category: str, origin: str, value: Optional[float] = None, always_use_default_value: bool = False, count_type: str = "ONE", click_lookback_days: int = 30, view_lookback_days: int = 1 ) -> str: """ Create a conversion action for tracking. Args: customer_id: Customer ID (without hyphens) conversion_name: Name for the conversion (e.g., "Purchase", "Lead Form") category: Conversion category (PURCHASE, SIGNUP, LEAD, etc.) origin: Where conversions occur (WEBSITE, APP, CALL_FROM_ADS, IMPORT) value: Optional default conversion value always_use_default_value: If True, always use default value (ignore transaction-specific values) count_type: ONE (count once per click) or MANY (count every conversion) click_lookback_days: Attribution window for clicks (1-90 days) view_lookback_days: Attribution window for views (1-30 days) Returns: Success message with conversion action ID and tag snippet Example: google_ads_create_conversion_action( customer_id="1234567890", conversion_name="Purchase", category="PURCHASE", origin="WEBSITE", value=50.00, count_type="ONE" ) Categories: PURCHASE, SIGNUP, LEAD, DOWNLOAD, ADD_TO_CART, BEGIN_CHECKOUT, PHONE_CALL_LEAD, SUBMIT_LEAD_FORM, BOOK_APPOINTMENT, etc. """ with performance_logger.track_operation('create_conversion_action', customer_id=customer_id): try: client = get_auth_manager().get_client() conversion_manager = ConversionManager(client) # Validate category try: cat_enum = ConversionActionCategory[category.upper()] except KeyError: valid = [c.value for c in ConversionActionCategory] return f"❌ Invalid category. Valid: {', '.join(valid[:10])}..." # Validate origin try: origin_enum = ConversionOrigin[origin.upper()] except KeyError: valid = [o.value for o in ConversionOrigin] return f"❌ Invalid origin. Valid: {', '.join(valid)}" config = ConversionActionConfig( name=conversion_name, category=cat_enum, origin=origin_enum, value=value, always_use_default_value=always_use_default_value, count_type=count_type.upper(), click_through_lookback_window_days=click_lookback_days, view_through_lookback_window_days=view_lookback_days ) result = conversion_manager.create_conversion_action(customer_id, config) # Audit log audit_logger.log_api_call( customer_id=customer_id, operation="create_conversion_action", resource_type="conversion_action", resource_id=result['conversion_action_id'], action="create", result="success", details={'name': conversion_name, 'category': category} ) output = f"✅ Conversion action created successfully!\n\n" output += f"**Conversion ID**: {result['conversion_action_id']}\n" output += f"**Name**: {result['name']}\n" output += f"**Category**: {result['category']}\n" output += f"**Origin**: {result['origin']}\n\n" if origin_enum == ConversionOrigin.WEBSITE: output += f"**Next Steps**:\n" output += f"1. Get tracking tag with `google_ads_get_conversion_tag`\n" output += f"2. Install tag on your website conversion page\n" output += f"3. Test conversion tracking\n" output += f"4. Wait 24-48 hours for data to populate\n" elif origin_enum == ConversionOrigin.IMPORT: output += f"**Next Steps**:\n" output += f"1. Use `google_ads_upload_offline_conversions` to import data\n" output += f"2. Upload conversions with GCLID and timestamp\n" return output except Exception as e: error_msg = ErrorHandler.handle_error(e, context="create_conversion_action") return f"❌ Failed to create conversion action: {error_msg}" @mcp.tool() def google_ads_list_conversion_actions( customer_id: str, include_removed: bool = False, response_format: str = "markdown" ) -> str: """ List all conversion actions in the account. Args: customer_id: Customer ID (without hyphens) include_removed: Include removed conversions response_format: Output format (markdown or json) Returns: List of all conversion actions Example: google_ads_list_conversion_actions( customer_id="1234567890" ) """ with performance_logger.track_operation('list_conversion_actions', customer_id=customer_id): try: client = get_auth_manager().get_client() conversion_manager = ConversionManager(client) conversions = conversion_manager.list_conversion_actions(customer_id, include_removed) # Audit log audit_logger.log_api_call( customer_id=customer_id, operation="list_conversion_actions", resource_type="conversion_action", action="read", result="success", details={'count': len(conversions)} ) if response_format.lower() == "json": return json.dumps(conversions, indent=2) if not conversions: return "No conversion actions found. Create one with `google_ads_create_conversion_action`." output = f"# Conversion Actions\n\n" output += f"**Total**: {len(conversions)}\n\n" for conv in conversions: status_marker = " ✅" if conv['status'] == "ENABLED" else " ❌" output += f"## {conv['name']}{status_marker}\n\n" output += f"- **ID**: {conv['id']}\n" output += f"- **Category**: {conv['category']}\n" output += f"- **Origin**: {conv['origin']}\n" output += f"- **Status**: {conv['status']}\n" output += f"- **Counting**: {conv['counting_type']}\n" output += f"- **Default Value**: ${conv['default_value']:.2f}\n" output += f"- **Attribution Model**: {conv['attribution_model']}\n" output += f"- **Click Window**: {conv['click_through_window']} days\n" output += f"- **View Window**: {conv['view_through_window']} days\n\n" return output except Exception as e: error_msg = ErrorHandler.handle_error(e, context="list_conversion_actions") return f"❌ Failed to list conversion actions: {error_msg}" @mcp.tool() def google_ads_get_conversion_tag( customer_id: str, conversion_action_id: str ) -> str: """ Get the tracking tag/snippet for a website conversion action. Returns the Global Site Tag and Event Snippet that must be installed on your website to track conversions. Args: customer_id: Customer ID (without hyphens) conversion_action_id: Conversion action ID Returns: Tracking tag code snippets Example: google_ads_get_conversion_tag( customer_id="1234567890", conversion_action_id="12345" ) """ with performance_logger.track_operation('get_conversion_tag', customer_id=customer_id): try: client = get_auth_manager().get_client() conversion_manager = ConversionManager(client) result = conversion_manager.get_conversion_tracking_tag(customer_id, conversion_action_id) if 'error' in result: return f"❌ {result['error']}" # Audit log audit_logger.log_api_call( customer_id=customer_id, operation="get_conversion_tag", resource_type="conversion_action", resource_id=conversion_action_id, action="read", result="success" ) output = f"# Conversion Tracking Tag\n\n" output += f"**Conversion**: {result['name']}\n" output += f"**ID**: {result['conversion_action_id']}\n\n" output += f"## Installation Instructions\n\n" output += f"Install these tags on your website:\n\n" for snippet in result['tag_snippets']: output += f"### {snippet['type']} ({snippet['page_format']})\n\n" if snippet.get('global_site_tag'): output += f"**Global Site Tag** (install on ALL pages):\n```html\n" output += snippet['global_site_tag'] output += f"\n```\n\n" if snippet.get('event_snippet'): output += f"**Event Snippet** (install on conversion page only):\n```html\n" output += snippet['event_snippet'] output += f"\n```\n\n" output += f"**Important**:\n" output += f"1. Place Global Site Tag in `<head>` on ALL pages\n" output += f"2. Place Event Snippet on conversion page (e.g., thank-you page)\n" output += f"3. Test with Google Tag Assistant\n" output += f"4. Wait 24-48 hours for data to appear\n" return output except Exception as e: error_msg = ErrorHandler.handle_error(e, context="get_conversion_tag") return f"❌ Failed to get conversion tag: {error_msg}" @mcp.tool() def google_ads_upload_offline_conversions( customer_id: str, conversion_action_id: str, conversions: List[Dict[str, Any]] ) -> str: """ Upload offline conversion data (CRM conversions, phone orders, store visits). Use this to import conversions that happen offline but originated from Google Ads clicks. You must have the GCLID (Google Click ID) for each conversion. Args: customer_id: Customer ID (without hyphens) conversion_action_id: Conversion action ID (must be IMPORT origin) conversions: List of conversion dictionaries with: - gclid: Google Click ID (required) - conversion_date_time: When conversion occurred (required) Format: "YYYY-MM-DD HH:MM:SS+TZ" (e.g., "2025-12-16 14:30:00-08:00") - conversion_value: Conversion value (optional) - currency_code: Currency code (optional, e.g., "USD") Returns: Upload success message with count Example: google_ads_upload_offline_conversions( customer_id="1234567890", conversion_action_id="12345", conversions=[ { "gclid": "Cj0KCQiA...", "conversion_date_time": "2025-12-15 10:30:00-08:00", "conversion_value": 150.00, "currency_code": "USD" }, { "gclid": "Cj0KCQiB...", "conversion_date_time": "2025-12-15 14:20:00-08:00", "conversion_value": 200.00, "currency_code": "USD" } ] ) GCLID Capture: Add {lpurl}?gclid={gclid} to landing page URLs to capture GCLID. """ with performance_logger.track_operation('upload_offline_conversions', customer_id=customer_id): try: client = get_auth_manager().get_client() conversion_manager = ConversionManager(client) result = conversion_manager.upload_offline_conversions( customer_id, conversion_action_id, conversions ) # Audit log audit_logger.log_api_call( customer_id=customer_id, operation="upload_offline_conversions", resource_type="conversion_action", resource_id=conversion_action_id, action="update", result="success", details={'count': result['uploaded']} ) output = f"✅ Offline conversions uploaded!\n\n" output += f"**Conversions Uploaded**: {result['uploaded']}\n" output += f"**Conversions Processed**: {result['results']}\n\n" if result['partial_failure_error']: output += f"⚠️ **Partial Failure**:\n{result['partial_failure_error']}\n\n" output += f"**Processing Time**: 2-6 hours\n" output += f"**Data Visibility**: Within 24 hours\n\n" output += f"**Common Issues**:\n" output += f"- Invalid GCLID (must match actual click)\n" output += f"- Conversion time outside attribution window\n" output += f"- Duplicate conversions (already uploaded)\n" return output except Exception as e: error_msg = ErrorHandler.handle_error(e, context="upload_offline_conversions") return f"❌ Failed to upload offline conversions: {error_msg}" @mcp.tool() def google_ads_upload_call_conversions( customer_id: str, conversion_action_id: str, call_conversions: List[Dict[str, Any]] ) -> str: """ Upload call conversion data for phone calls that converted. Args: customer_id: Customer ID (without hyphens) conversion_action_id: Call conversion action ID call_conversions: List with: - caller_id: Phone number that called (E.164 format: +12345678900) - call_start_date_time: When call started - conversion_date_time: When call qualified as conversion - conversion_value: Optional conversion value - currency_code: Optional currency Returns: Upload success message Example: google_ads_upload_call_conversions( customer_id="1234567890", conversion_action_id="12345", call_conversions=[ { "caller_id": "+12025551234", "call_start_date_time": "2025-12-15 10:30:00-08:00", "conversion_date_time": "2025-12-15 10:35:00-08:00", "conversion_value": 500.00, "currency_code": "USD" } ] ) """ with performance_logger.track_operation('upload_call_conversions', customer_id=customer_id): try: client = get_auth_manager().get_client() conversion_manager = ConversionManager(client) result = conversion_manager.upload_call_conversions( customer_id, conversion_action_id, call_conversions ) # Audit log audit_logger.log_api_call( customer_id=customer_id, operation="upload_call_conversions", resource_type="conversion_action", resource_id=conversion_action_id, action="update", result="success", details={'count': result['uploaded']} ) output = f"✅ Call conversions uploaded!\n\n" output += f"**Call Conversions Uploaded**: {result['uploaded']}\n" output += f"**Conversions Processed**: {result['results']}\n\n" if result['partial_failure_error']: output += f"⚠️ **Partial Failure**:\n{result['partial_failure_error']}\n\n" return output except Exception as e: error_msg = ErrorHandler.handle_error(e, context="upload_call_conversions") return f"❌ Failed to upload call conversions: {error_msg}" @mcp.tool() def google_ads_get_conversion_performance( customer_id: str, conversion_action_id: Optional[str] = None, date_range: str = "LAST_30_DAYS" ) -> str: """ Get conversion performance metrics. Args: customer_id: Customer ID (without hyphens) conversion_action_id: Optional specific conversion date_range: Date range Returns: Conversion performance data Example: google_ads_get_conversion_performance( customer_id="1234567890", date_range="LAST_30_DAYS" ) """ with performance_logger.track_operation('get_conversion_performance', customer_id=customer_id): try: client = get_auth_manager().get_client() conversion_manager = ConversionManager(client) conversions = conversion_manager.get_conversion_performance( customer_id, conversion_action_id, date_range ) # Audit log audit_logger.log_api_call( customer_id=customer_id, operation="get_conversion_performance", resource_type="conversion_action", action="read", result="success", details={'count': len(conversions)} ) if not conversions: return "No conversion data found for the specified period." output = f"# Conversion Performance\n\n" output += f"**Date Range**: {date_range}\n" output += f"**Conversions**: {len(conversions)}\n\n" for conv in conversions: output += f"## {conv['name']} ({conv['category']})\n\n" output += f"- **Conversions**: {conv['conversions']:.1f}\n" output += f"- **Conversion Value**: ${conv['conversions_value']:,.2f}\n" output += f"- **Cost per Conversion**: ${conv['cost_per_conversion']:.2f}\n" output += f"- **Conversion Rate**: {conv['conversion_rate'] * 100:.2f}%\n" output += f"- **Value per Conversion**: ${conv['value_per_conversion']:.2f}\n" output += f"- **All Conversions**: {conv['all_conversions']:.1f}\n\n" return output except Exception as e: error_msg = ErrorHandler.handle_error(e, context="get_conversion_performance") return f"❌ Failed to get conversion performance: {error_msg}" @mcp.tool() def google_ads_set_attribution_model( customer_id: str, conversion_action_id: str, attribution_model: str ) -> str: """ Set attribution model for a conversion action. Attribution models determine how credit for conversions is assigned to touchpoints in the customer journey. Args: customer_id: Customer ID (without hyphens) conversion_action_id: Conversion action ID attribution_model: Attribution model to use Returns: Success message Example: google_ads_set_attribution_model( customer_id="1234567890", conversion_action_id="12345", attribution_model="DATA_DRIVEN" ) Attribution Models: - LAST_CLICK: 100% credit to last click (default) - FIRST_CLICK: 100% credit to first click - LINEAR: Equal credit across all clicks - TIME_DECAY: More credit to recent clicks - POSITION_BASED: 40% first, 40% last, 20% middle - DATA_DRIVEN: Google's ML model (recommended, requires sufficient data) Recommendation: Use DATA_DRIVEN for accounts with 300+ conversions/month. """ with performance_logger.track_operation('set_attribution_model', customer_id=customer_id): try: client = get_auth_manager().get_client() conversion_manager = ConversionManager(client) try: model = AttributionModel[attribution_model.upper()] except KeyError: valid = [m.value for m in AttributionModel] return f"❌ Invalid attribution model. Valid: {', '.join(valid)}" result = conversion_manager.set_attribution_model( customer_id, conversion_action_id, model ) # Audit log audit_logger.log_api_call( customer_id=customer_id, operation="set_attribution_model", resource_type="conversion_action", resource_id=conversion_action_id, action="update", result="success", details={'model': attribution_model} ) output = f"✅ Attribution model updated!\n\n" output += f"**Conversion ID**: {result['conversion_action_id']}\n" output += f"**New Model**: {result['attribution_model']}\n\n" if model == AttributionModel.DATA_DRIVEN: output += f"**Data-Driven Attribution**:\n" output += f"- Uses machine learning to assign credit\n" output += f"- Requires 300+ conversions and 3,000+ ad interactions/month\n" output += f"- Most accurate attribution model\n" output += f"- Falls back to LINEAR if insufficient data\n" return output except Exception as e: error_msg = ErrorHandler.handle_error(e, context="set_attribution_model") return f"❌ Failed to set attribution model: {error_msg}" @mcp.tool() def google_ads_upload_store_sales( customer_id: str, conversion_action_id: str, store_sales: List[Dict[str, Any]] ) -> str: """ Upload store sales data (in-store purchases from online clicks). This is a specialized form of offline conversion upload for retail businesses tracking in-store purchases that originated from online ads. Args: customer_id: Customer ID (without hyphens) conversion_action_id: Store sales conversion action ID store_sales: List of sales with gclid, timestamp, value Returns: Upload success message Example: google_ads_upload_store_sales( customer_id="1234567890", conversion_action_id="12345", store_sales=[ { "gclid": "Cj0KCQiA...", "conversion_date_time": "2025-12-15 15:45:00-08:00", "conversion_value": 85.50, "currency_code": "USD" } ] ) Note: This uses the same upload mechanism as offline conversions. """ # Store sales use the same upload method as offline conversions return google_ads_upload_offline_conversions( customer_id, conversion_action_id, store_sales ) # Additional tools (9, 10) for comprehensive conversion management @mcp.tool() def google_ads_conversion_summary_report( customer_id: str, date_range: str = "LAST_30_DAYS" ) -> str: """ Get account-wide conversion summary. Args: customer_id: Customer ID (without hyphens) date_range: Date range Returns: Summary of all conversions Example: google_ads_conversion_summary_report( customer_id="1234567890", date_range="LAST_30_DAYS" ) """ # Get all conversion performance and aggregate return google_ads_get_conversion_performance( customer_id, None, # All conversions date_range ) @mcp.tool() def google_ads_update_conversion_action( customer_id: str, conversion_action_id: str, conversion_value: Optional[float] = None, status: Optional[str] = None ) -> str: """ Update conversion action settings. Args: customer_id: Customer ID (without hyphens) conversion_action_id: Conversion action ID to update conversion_value: New default value status: New status (ENABLED, PAUSED, REMOVED) Returns: Success message Example: google_ads_update_conversion_action( customer_id="1234567890", conversion_action_id="12345", conversion_value=75.00, status="ENABLED" ) """ with performance_logger.track_operation('update_conversion_action', customer_id=customer_id): try: client = get_auth_manager().get_client() conversion_action_service = client.get_service("ConversionActionService") conversion_action_operation = client.get_type("ConversionActionOperation") conversion_action = conversion_action_operation.update conversion_action.resource_name = conversion_action_service.conversion_action_path( customer_id, conversion_action_id ) field_paths = [] if conversion_value is not None: conversion_action.value_settings.default_value = conversion_value field_paths.append("value_settings.default_value") if status: conversion_action.status = client.enums.ConversionActionStatusEnum[status.upper()] field_paths.append("status") if not field_paths: return "❌ No updates specified. Provide conversion_value or status." client.copy_from( conversion_action_operation.update_mask, client.get_type("FieldMask", version="v17")(paths=field_paths) ) conversion_action_service.mutate_conversion_actions( customer_id=customer_id, operations=[conversion_action_operation] ) # Audit log audit_logger.log_api_call( customer_id=customer_id, operation="update_conversion_action", resource_type="conversion_action", resource_id=conversion_action_id, action="update", result="success", details={'fields': field_paths} ) return f"✅ Conversion action updated successfully!\n\nUpdated fields: {', '.join(field_paths)}" except Exception as e: error_msg = ErrorHandler.handle_error(e, context="update_conversion_action") return f"❌ Failed to update conversion action: {error_msg}"

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