Provides comprehensive tools for managing Google Ads campaigns, ad groups, ads, keywords, audiences, and extensions, with support for custom GAQL queries, performance analytics across multiple levels (account, campaign, ad group, ad, keyword), and multi-channel campaigns (Search, Display, YouTube, Shopping, Performance Max).
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Google Ads MCP Servershow me campaign performance for the last 30 days"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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 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 + resultsClaude writes code to call tools dynamically:
β
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
pip install mcp google-ads2. Configure Credentials
Create a .env file (copy from .env.example) with your Google Ads API credentials:
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_tokenImportant: 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:
{
"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.
# 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
# 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
# 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.
# 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
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
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
# 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
# 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 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)