Skip to main content
Glama
README.md•10.4 kB
# Google Ads MCP Server Comprehensive Model Context Protocol (MCP) server for Google Ads API integration with Claude. Supports campaigns, ad groups, ads, keywords, audiences, extensions, shopping, and performance analytics. This implementation follows [Anthropic's token-efficiency recommendations](https://www.anthropic.com/engineering/code-execution-with-mcp) by exposing a unified `call_tool` interface instead of individual tool definitions. This reduces token usage by **~98.7%** compared to traditional tool approaches. ## Supported Features - **šŸ“Š Resource Management** - List and query campaigns, ad groups, ads, keywords, extensions, audiences, labels, and bidding strategies - **šŸ” Custom Queries** - Execute GAQL (Google Ads Query Language) queries with pagination support - **šŸ“ˆ Performance Analytics** - Get detailed performance metrics at any level (account, campaign, ad group, ad, keyword) - **šŸ“‹ GAQL Help** - Built-in reference for GAQL syntax, fields, filters, and best practices - **šŸŽÆ Multiple Output Formats** - JSON, CSV, and table formats for query results - **šŸ›ļø Shopping Support** - Query product groups and shopping campaign data - **šŸ“± Multi-Channel** - Search, Display, YouTube, Shopping, and Performance Max campaigns ## How It Works Instead of listing all tool definitions upfront: ``` āŒ Traditional: 150,000 tokens for all tool definitions + results ``` Claude writes code to call tools dynamically: ```python āœ… Efficient: 2,000 tokens - only loads what's needed # List campaigns and filter them campaigns = call_tool('list_campaigns', {'customer_id': '1234567890'}) active = [c for c in campaigns if c.get('campaign', {}).get('status') == 'ENABLED'] # Get performance with filtering in code perf = call_tool('get_performance', { 'level': 'keyword', 'customer_id': '1234567890', 'date_range': 'LAST_30_DAYS', 'metrics': ['clicks', 'conversions', 'cost_micros'] }) high_performers = [k for k in perf if k.get('metrics', {}).get('clicks', 0) > 100] ``` ## Setup ### 1. Install Dependencies ```bash pip install mcp google-ads ``` ### 2. Configure Credentials Create a `.env` file (copy from `.env.example`) with your Google Ads API credentials: ```bash GOOGLE_ADS_DEVELOPER_TOKEN=your_token GOOGLE_ADS_LOGIN_CUSTOMER_ID=your_customer_id GOOGLE_ADS_CLIENT_ID=your_client_id GOOGLE_ADS_CLIENT_SECRET=your_secret GOOGLE_ADS_REFRESH_TOKEN=your_refresh_token ``` **Important:** Never commit credentials to git. Use environment variables or `.env` files with proper `.gitignore` rules. ### 3. Add to Claude Desktop Edit `~/.config/claude/claude_desktop_config.json`: ```json { "mcpServers": { "google-ads": { "command": "python", "args": ["path/to/server.py"], "env": { "GOOGLE_ADS_DEVELOPER_TOKEN": "your_token", "GOOGLE_ADS_LOGIN_CUSTOMER_ID": "your_customer_id", "GOOGLE_ADS_CLIENT_ID": "your_client_id", "GOOGLE_ADS_CLIENT_SECRET": "your_secret", "GOOGLE_ADS_REFRESH_TOKEN": "your_refresh_token" } } } } ``` ## Available Operations ### šŸ“‹ List Resources - **list_accounts()** - List accessible customer accounts - **list_campaigns(customer_id)** - List all campaigns with budget info - **list_ad_groups(customer_id, campaign_id?)** - List ad groups (optionally filtered by campaign) - **list_ads(customer_id, ad_group_id?)** - List ads (optionally filtered by ad group) - **list_keywords(customer_id, ad_group_id?)** - List keywords with quality scores - **list_extensions(customer_id)** - List sitelinks, callouts, structured snippets, etc. - **list_audiences(customer_id)** - List all audiences (remarketing, custom intent, affinity) - **list_labels(customer_id)** - List custom labels - **list_bidding_strategies(customer_id)** - List available bidding strategies ### šŸ” Query Data **execute_gaql(query, customer_id?, output_format?, auto_paginate?, max_pages?)** Execute custom GAQL queries with full pagination support. ```python # Example: Find high-performance keywords result = call_tool('execute_gaql', { 'query': '''SELECT ad_group_criterion.keyword.text, metrics.quality_score, metrics.conversions FROM ad_group_criterion WHERE metrics.quality_score >= 8 AND metrics.conversions > 0''', 'customer_id': '1234567890', 'output_format': 'json', 'auto_paginate': True }) # Example: Get campaign performance for date range result = call_tool('execute_gaql', { 'query': '''SELECT campaign.name, metrics.clicks, metrics.conversions, metrics.cost_micros FROM campaign WHERE segments.date DURING LAST_30_DAYS''', 'customer_id': '1234567890' }) ``` **Output Formats**: `json`, `csv`, `table` ### šŸ“ˆ Performance Analytics **get_performance(level, customer_id?, date_range?, days?, metrics?, segments?, filters?, output_format?)** Get detailed performance metrics at any level with flexible filtering and segmentation. Levels: `account`, `campaign`, `ad_group`, `ad`, `keyword` Date ranges: `LAST_7_DAYS`, `LAST_30_DAYS`, `THIS_MONTH`, `LAST_MONTH`, `LAST_QUARTER`, `LAST_YEAR` Common metrics: `impressions`, `clicks`, `conversions`, `cost_micros`, `ctr`, `conversion_rate`, `quality_score` Common segments: `date`, `device`, `geo_target_country`, `age_range`, `gender`, `day_of_week` ```python # Campaign performance by device result = call_tool('get_performance', { 'level': 'campaign', 'customer_id': '1234567890', 'date_range': 'LAST_30_DAYS', 'metrics': ['clicks', 'conversions', 'cost_micros', 'conversion_rate'], 'segments': ['device', 'geo_target_country'], 'output_format': 'json' }) # Keyword analysis for specific campaign result = call_tool('get_performance', { 'level': 'keyword', 'customer_id': '1234567890', 'date_range': 'LAST_7_DAYS', 'metrics': ['quality_score', 'impressions', 'clicks', 'conversions'], 'filters': {'campaign.id': '123456'} }) # Custom filter - high spend keywords result = call_tool('get_performance', { 'level': 'keyword', 'customer_id': '1234567890', 'metrics': ['cost_micros', 'conversions'], 'filters': {'metrics.cost_micros': {'operator': 'GREATER_THAN', 'value': 5000000}} }) ``` ### ā“ Help & Discovery **gaql_help(topic?, search?)** Get GAQL syntax help and examples. Topics: `overview`, `resources`, `metrics`, `segments`, `filters`, `best_practices` ```python # Get help on GAQL filters help_text = call_tool('gaql_help', {'topic': 'filters'}) # Search for metrics help result = call_tool('gaql_help', {'search': 'conversion'}) # Get all available help all_help = call_tool('gaql_help', {}) ``` **search_tools(query?)** Search for available resources and operations. ```python # List all resources resources = call_tool('search_tools', {}) # Search for shopping-related resources shopping = call_tool('search_tools', {'query': 'shopping'}) # Find performance metrics operations perf = call_tool('search_tools', {'query': 'performance'}) ``` ## Usage Examples ### Find campaigns with low CTR ```python campaigns = call_tool('get_performance', { 'level': 'campaign', 'customer_id': '1234567890', 'date_range': 'LAST_30_DAYS', 'metrics': ['impressions', 'clicks', 'ctr'] }) # Filter in code - campaigns with CTR < 2% low_ctr = [c for c in campaigns if c.get('metrics', {}).get('ctr', 0) < 0.02] print(f"Found {len(low_ctr)} campaigns with low CTR") ``` ### Analyze keyword quality ```python keywords = call_tool('execute_gaql', { 'query': '''SELECT ad_group_criterion.keyword.text, metrics.quality_score, metrics.impressions FROM ad_group_criterion WHERE metrics.quality_score < 5 AND metrics.impressions > 100''', 'customer_id': '1234567890' }) # Process results - group by score by_score = {} for kw in keywords: score = kw['ad_group_criterion']['keyword']['quality_score'] by_score.setdefault(score, []).append(kw) print(f"Keywords needing improvement: {sum(len(v) for v in by_score.values())}") ``` ### Shopping campaign analysis ```python # Get all shopping campaigns shopping = call_tool('execute_gaql', { 'query': '''SELECT campaign.id, campaign.name, metrics.conversions, metrics.cost_micros FROM campaign WHERE campaign.advertising_channel_type = 'SHOPPING' AND segments.date DURING LAST_30_DAYS''', 'customer_id': '1234567890' }) # Calculate ROAS (return on ad spend) for campaign in shopping: cost = campaign['metrics']['cost_micros'] / 1_000_000 conversions = campaign['metrics']['conversions'] roas = conversions / cost if cost > 0 else 0 print(f"{campaign['campaign']['name']}: ROAS = {roas:.2f}") ``` ### Display network targeting analysis ```python # Get placement performance placements = call_tool('execute_gaql', { 'query': '''SELECT ad_group_criterion.placement.url, metrics.clicks, metrics.conversions, metrics.cost_micros FROM ad_group_criterion WHERE ad_group_criterion.type = 'PLACEMENT' AND segments.date DURING LAST_30_DAYS''', 'customer_id': '1234567890' }) # Filter high-cost low-converting placements inefficient = [p for p in placements if p['metrics']['conversions'] == 0] ``` ## Error Handling The server includes proper error handling and logging. Errors are caught and returned as structured responses to Claude. ## Token Efficiency This server implements Anthropic's code execution approach for MCP: | Approach | Token Usage | Latency | |----------|-------------|---------| | Traditional tools | ~150,000 | Slower (many round-trips) | | Code execution | ~2,000 | Faster (batch processing) | | **Savings** | **98.7% reduction** | **~75% faster** | By using a unified interface and letting Claude write code: - Tools are discovered on-demand, not loaded upfront - Data is filtered and transformed in the execution environment - Large datasets can be processed without bloating context - Complex workflows execute in fewer steps See [Anthropic's engineering blog](https://www.anthropic.com/engineering/code-execution-with-mcp) for details. ## Security - Credentials are loaded from environment variables, never hardcoded - Sensitive data is not logged - Always use HTTPS for API communications (handled by Google Ads SDK)

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/blievens89/MCPGoogleAds'

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