A production-ready wrapper around the Google Ads API with 36 tools covering campaign creation, keyword management, and GAQL reporting. Ships read-only by default; you flip GOOGLE_ADS_MCP_WRITE to expose mutating operations. Everything creates in paused state with a label prefix so you can review in the Ads UI before going live. Built for agencies: it detects client context from your working directory and supports MCC accounts managing multiple customer IDs. Includes circuit breakers, retry logic, and pre-flight validation that catches RSA character limits before hitting the API. The newest release adds end-to-end Demand Gen campaign support with image asset uploads and multi-asset ad creation.
Public tool metadata for what this MCP can expose to an agent.
GOOGLEADS_ADD_OR_REMOVE_TO_CUSTOMER_LISTAddOrRemoveToCustomerList Tool will add a contact to a customer list in Google Ads. Note: It takes 6 to 12 hours for changes to be reflected in the customer list.3 paramsAddOrRemoveToCustomerList Tool will add a contact to a customer list in Google Ads. Note: It takes 6 to 12 hours for changes to be reflected in the customer list.
emailsarrayoperationstringcreate · removedefault: createresource_namestringGOOGLEADS_CREATE_CUSTOMER_LISTCreateCustomerList Tool will create a customer list in Google Ads.2 paramsCreateCustomerList Tool will create a customer list in Google Ads.
namestringdescriptionstringGOOGLEADS_GET_CAMPAIGN_BY_IDGetCampaignById Tool will return details of a campaign in Google Ads.1 paramsGetCampaignById Tool will return details of a campaign in Google Ads.
idstringGOOGLEADS_GET_CAMPAIGN_BY_NAMEGetCampaignByName Tool will run a SQL GetCampaignByName in Google Ads.1 paramsGetCampaignByName Tool will run a SQL GetCampaignByName in Google Ads.
namestringGOOGLEADS_GET_CUSTOMER_LISTSGetCustomerLists Tool will list all customer lists in Google Ads.GetCustomerLists Tool will list all customer lists in Google Ads.
No parameter schema in public metadata yet.
An MCP (Model Context Protocol) server for the Google Ads API with built-in safeguards for review before changes go live. Production-proven with MCC (Manager Account) support, 36 tools for campaign management, reporting, and optimization. v1.2.0 adds Demand Gen campaign creation end-to-end.
You need:
Use the Google OAuth playground or run:
pip install google-ads
google-ads-auth
npm install mcp-google-ads
Or clone and build from source:
git clone https://github.com/mharnett/mcp-google-ads.git
cd mcp-google-ads
npm install
npm run build
Security: Never share your .mcp.json file or commit it to git -- it may contain API credentials. Add .mcp.json to your .gitignore.
cp config.example.json config.json
Edit config.json with your credentials:
{
"google_ads": {
"developer_token": "YOUR_DEVELOPER_TOKEN",
"client_id": "YOUR_CLIENT_ID.apps.googleusercontent.com",
"client_secret": "YOUR_CLIENT_SECRET",
"refresh_token": "YOUR_REFRESH_TOKEN",
"mcc_customer_id": "123-456-7890"
},
"clients": {
"my-client": {
"customer_id": "111-222-3333",
"name": "My Client",
"folder": "/path/to/client/workspace"
},
"another-client": {
"customer_id": "444-555-6666",
"name": "Another Client",
"folder": "/path/to/another/workspace"
}
},
"defaults": {
"create_paused": true,
"label_prefix": "claude-",
"require_approval_for_enable": true
}
}
Alternatively, set credentials via environment variables (these override config.json):
| Variable | Required | Description |
|---|---|---|
GOOGLE_ADS_DEVELOPER_TOKEN | Yes | Google Ads API developer token |
GOOGLE_ADS_CLIENT_ID | Yes | OAuth 2.0 client ID |
GOOGLE_ADS_CLIENT_SECRET | Yes | OAuth 2.0 client secret |
GOOGLE_ADS_REFRESH_TOKEN | Yes | OAuth 2.0 refresh token |
GOOGLE_ADS_MCP_WRITE | No | Set to true to expose mutating tools (create/update/pause/enable/remove/apply). Default: read-only. |
The server ships read-only. Mutating tools (anything that creates, updates,
pauses, enables, removes, links, or applies) are hidden from the tool list
until you set GOOGLE_ADS_MCP_WRITE=true in the MCP server environment.
If a write tool is somehow invoked without that flag, the server returns a
clear error pointing at the env var.
This is deliberate: a casual chat message like "activate the Fundraising campaign" should not move live ad spend without an explicit opt-in.
Add to your Claude Code MCP settings (~/.claude/settings.json or project settings):
{
"mcpServers": {
"google-ads": {
"command": "node",
"args": ["node_modules/mcp-google-ads/dist/index.js"]
}
}
}
Or if installed from source:
{
"mcpServers": {
"google-ads": {
"command": "node",
"args": ["/path/to/mcp-google-ads/dist/index.js"]
}
}
}
Restart Claude Code.
Claude Desktop: Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows).
1. cd into client folder → auto-detects account context
2. Ask Claude to create campaigns/ads → all created PAUSED
3. Review in Google Ads UI or Editor
4. Tell Claude to enable approved items
5. Claude enables (requires your approval prompt)
| Tool | Description |
|---|---|
google_ads_get_client_context | Detect which account from working directory |
google_ads_list_campaigns | List all campaigns with status and metrics |
google_ads_list_ad_groups | List ad groups in a campaign |
google_ads_list_pending_changes | Show paused items with claude- label |
google_ads_list_conversion_actions | List conversion actions |
| Tool | Description |
|---|---|
google_ads_create_campaign | Create campaign (PAUSED). Supports SEARCH + DEMAND_GEN channels, richer bidding (MANUAL_CPC / MAXIMIZE_CLICKS / MAXIMIZE_CONVERSIONS / TARGET_CPA), geo + language targeting, start/end dates |
google_ads_create_ad_group | Create ad group (PAUSED). type accepts SEARCH_STANDARD (default) or DEMAND_GEN_MULTI_ASSET_AD_GROUP |
google_ads_create_responsive_search_ad | Create RSA with validation (PAUSED) |
google_ads_create_image_asset | Upload PNG/JPG/GIF image asset (validates ≤5MB, ≥600×314) for use in Demand Gen ads |
google_ads_create_demand_gen_multi_asset_ad | Create a Demand Gen multi-asset ad (PAUSED) — validates char/count caps before API call, fails fast if ad_group isn't DG |
google_ads_create_keywords | Create keywords (PAUSED) |
google_ads_validate_ad | Validate RSA without creating |
google_ads_enable_items | Enable items (make LIVE) — requires approval |
google_ads_pause_items | Pause active items |
google_ads_pause_keywords | Pause specific keywords |
google_ads_update_campaign_budget | Update campaign daily budget |
| Tool | Description |
|---|---|
google_ads_get_campaign_tracking | Get tracking templates and URL parameters |
google_ads_update_campaign_tracking | Update tracking templates |
| Tool | Description |
|---|---|
google_ads_create_shared_set | Create shared negative keyword list |
google_ads_link_shared_set | Link shared set to campaign |
google_ads_unlink_shared_set | Unlink shared set from campaign |
google_ads_add_shared_negatives | Add keywords to shared negative list |
google_ads_remove_shared_negatives | Remove keywords from shared list |
google_ads_add_campaign_negatives | Add campaign-level negatives |
google_ads_remove_campaign_negatives | Remove campaign-level negatives |
google_ads_remove_adgroup_negatives | Remove ad group-level negatives |
| Tool | Description |
|---|---|
google_ads_keyword_performance | Keyword metrics with quality score |
google_ads_keyword_performance_by_conversion | Keyword metrics by conversion action |
google_ads_ad_performance | Ad-level performance metrics |
google_ads_ad_performance_by_conversion | Ad metrics by conversion action |
google_ads_search_term_report | Search term query report |
google_ads_search_term_report_by_conversion | Search terms by conversion action |
google_ads_search_term_insights | Search term category insights |
google_ads_search_term_insight_terms | Terms within insight categories |
google_ads_keyword_volume | Keyword planner volume estimates |
| Tool | Description |
|---|---|
google_ads_gaql_query | Run raw GAQL queries |
# Check which account you're working with
"What Google Ads account am I connected to?"
# List campaigns
"Show me all campaigns in this account"
# Create a new campaign
"Create a Search campaign for brand terms with $50/day budget"
# Check what's pending review
"What changes are pending my review?"
# After reviewing in Google Ads UI
"Enable the approved ads in the Brand campaign"
# Performance analysis
"Show me keyword performance for the last 30 days, sorted by cost"
# Run custom GAQL
"Run a GAQL query to get all ad groups with CTR below 2%"
# 1. Campaign: $75/day, DEMAND_GEN channel, MAXIMIZE_CONVERSIONS default,
# targeting Alaska (21134) + Maine (21141) in English
google_ads_create_campaign({
name: "DG - Spring Promo",
daily_budget: 75,
channel_type: "DEMAND_GEN",
geo_target_ids: ["21134", "21141"],
start_date: "2026-05-01",
end_date: "2026-06-30"
})
# → campaign_id: 555123
# 2. Ad group: DEMAND_GEN_MULTI_ASSET_AD_GROUP
google_ads_create_ad_group({
campaign_id: "555123",
name: "DG AG 1",
type: "DEMAND_GEN_MULTI_ASSET_AD_GROUP"
})
# → ad_group_id: 555456
# 3. Image assets (PNG/JPG/GIF, ≥600×314, ≤5MB). Returns {asset_id, ...}
google_ads_create_image_asset({ name: "hero-landscape", file_path: "/abs/path/hero.png" })
# → asset_id: 42001
google_ads_create_image_asset({ name: "hero-square", file_path: "/abs/path/square.png" })
# → asset_id: 42002
google_ads_create_image_asset({ name: "logo", file_path: "/abs/path/logo.png" })
# → asset_id: 42003
# 4. Demand Gen multi-asset ad (PAUSED). Validates char + count caps first.
google_ads_create_demand_gen_multi_asset_ad({
ad_group_id: "555456",
final_urls: ["https://example.com/spring"],
business_name: "Example Org",
call_to_action: "LEARN_MORE",
marketing_image_asset_ids: ["42001"], // 1.91:1 landscape, ≥1 required
square_marketing_image_asset_ids: ["42002"], // 1:1 optional
logo_image_asset_ids: ["42003"], // logo optional
headlines: ["Spring Sale Now On", "Save 20% Today"], // max 5, ≤40 chars each
long_headlines: ["A longer pitch under ninety characters."], // max 5, ≤90 chars
descriptions: ["Shop the latest looks.", "Free returns."] // max 5, ≤90 chars each
})
# → resource_name: customers/.../adGroupAds/555456~67890000
After all four calls the campaign, ad group, and ad all live in your account in PAUSED state and are labeled Claude-MM-DD-YY. Review in the Google Ads UI, then enable via google_ads_enable_items.
claude-pending labelenable_items tool requires explicit approval in Claude CodeEdit config.json to add clients. Map each client to a working directory:
{
"clients": {
"client-slug": {
"customer_id": "123-456-7890",
"name": "Client Name",
"folder": "/path/to/client/workspace"
}
}
}
No server restart needed — config is read on each request.
clients entriesMIT — see LICENSE for details.
GOOGLE_ADS_CLIENT_ID*OAuth client ID
GOOGLE_ADS_CLIENT_SECRET*secretOAuth client secret
GOOGLE_ADS_REFRESH_TOKEN*secretOAuth refresh token
GOOGLE_ADS_DEVELOPER_TOKEN*secretGoogle Ads API developer token
com.mcparmory/google-sheets
domdomegg/google-sheets-mcp
henilcalagiya/google-sheets-mcp
cct15/war-dashboard-data
moooonad/mcp-google-sheets-full
io.github.br0ski777/csv-to-json