MCP server for Google Ads keyword planning, Search campaign management, reporting, and basic optimization workflows.
This server runs over stdio and is intended to be launched by an MCP client such as Claude Cowork or any other client that supports local stdio MCP servers.
- Keyword discovery and historical metrics
- Forecasting for keyword sets
- Search campaign creation and updates
- Ad group and keyword management
- Negative keyword management at the campaign, ad group, shared-list, and account levels
- Responsive search ad creation and replacement-style updates
- Search term and performance reporting
Mutation tools return structured results. Reporting tools return markdown tables.
- Python
>=3.11 uv- A Google Ads API-enabled Google Cloud project
- Google Ads API credentials
- A Google Ads customer ID
- Optional MCC login customer ID
Copy .env.example to .env and fill in:
GOOGLE_ADS_DEVELOPER_TOKEN=
GOOGLE_ADS_CLIENT_ID=
GOOGLE_ADS_CLIENT_SECRET=
# Optional at startup if you will use the `authorize` MCP tool
GOOGLE_ADS_REFRESH_TOKEN=
GOOGLE_ADS_CUSTOMER_ID=
# GOOGLE_ADS_LOGIN_CUSTOMER_ID=You need four values to boot the server in OAuth mode, and a fifth once you complete authorization:
GOOGLE_ADS_DEVELOPER_TOKENGOOGLE_ADS_CLIENT_IDGOOGLE_ADS_CLIENT_SECRETGOOGLE_ADS_CUSTOMER_ID
After first-time authorization, you will also have:
GOOGLE_ADS_REFRESH_TOKEN
Optional:
GOOGLE_ADS_LOGIN_CUSTOMER_IDfor MCC / manager-account access
In your Google Ads account:
- Open
Tools and settings. - Open
API Center. - Copy your developer token.
Use that value for GOOGLE_ADS_DEVELOPER_TOKEN.
In Google Cloud:
- Create or select a Google Cloud project.
- Enable the Google Ads API for that project.
- Open
APIs & Services->Credentials. - Create an OAuth client ID.
- For local use, a Desktop app client is usually the simplest option.
- Copy the client ID and client secret.
Use those values for:
GOOGLE_ADS_CLIENT_IDGOOGLE_ADS_CLIENT_SECRET
For OAuth, the server can now start with just:
GOOGLE_ADS_CLIENT_IDGOOGLE_ADS_CLIENT_SECRETGOOGLE_ADS_DEVELOPER_TOKENGOOGLE_ADS_CUSTOMER_ID
Once the MCP server is running, call:
authorize
That tool will:
- open a Google authorization URL in your browser
- complete the local callback flow
- save
GOOGLE_ADS_REFRESH_TOKENinto your.env - make future MCP runs use the saved token automatically
GOOGLE_ADS_CUSTOMER_ID: the Google Ads account the server should operate onGOOGLE_ADS_LOGIN_CUSTOMER_ID: the manager account to authenticate through, if you are using an MCC
You can copy these from the Google Ads UI. The server accepts IDs with or without dashes and normalizes them internally.
GOOGLE_ADS_DEVELOPER_TOKEN=your-developer-token
GOOGLE_ADS_CLIENT_ID=your-oauth-client-id
GOOGLE_ADS_CLIENT_SECRET=your-oauth-client-secret
# Optional until you run the `authorize` tool
GOOGLE_ADS_REFRESH_TOKEN=your-refresh-token
GOOGLE_ADS_CUSTOMER_ID=1234567890
GOOGLE_ADS_LOGIN_CUSTOMER_ID=0987654321Install dependencies:
uv syncRun locally:
uv run google-ads-mcpIf you are using OAuth and have not authorized yet, start the MCP server and call authorize.
If your MCP client supports stdio servers with environment variables, configure this repo with a command like:
{
"mcpServers": {
"google-ads": {
"command": "uv",
"args": ["run", "google-ads-mcp"],
"cwd": "/absolute/path/to/google-ads",
"env": {
"GOOGLE_ADS_DEVELOPER_TOKEN": "your-developer-token",
"GOOGLE_ADS_CLIENT_ID": "your-client-id",
"GOOGLE_ADS_CLIENT_SECRET": "your-client-secret",
"GOOGLE_ADS_REFRESH_TOKEN": "your-refresh-token",
"GOOGLE_ADS_CUSTOMER_ID": "1234567890",
"GOOGLE_ADS_LOGIN_CUSTOMER_ID": "0987654321"
}
}
}
}If your client loads environment variables from the repo automatically, you can omit the env block and rely on the local .env file instead.
Notes:
cwdshould point at this repository root.GOOGLE_ADS_CUSTOMER_IDandGOOGLE_ADS_LOGIN_CUSTOMER_IDmay include or omit dashes; the server normalizes them.- For manager-account access, set
GOOGLE_ADS_LOGIN_CUSTOMER_ID.
.
├── .env.example
├── pyproject.toml
├── README.md
├── src/google_ads_mcp/
│ ├── client.py
│ ├── config.py
│ ├── formatters.py
│ ├── models.py
│ └── server.py
├── tests/
│ ├── test_client.py
│ └── test_server.py
└── uv.lock
File summary:
src/google_ads_mcp/server.py: FastMCP server and tool registrationsrc/google_ads_mcp/client.py: Google Ads API wrapper and mutation/report logicsrc/google_ads_mcp/models.py: typed request and structured response modelssrc/google_ads_mcp/formatters.py: markdown formatting for report toolssrc/google_ads_mcp/config.py: environment loading and validationtests/test_client.py: request-construction and client behavior teststests/test_config.py: environment-loading and OAuth bootstrap teststests/test_server.py: MCP tool registration and output-shape tests
check_auth_statusauthorizereauthorize
generate_keyword_ideasget_keyword_historical_metricsgenerate_keyword_forecast
create_search_campaignupdate_search_campaignset_campaign_geo_targetsset_campaign_ad_scheduleset_campaign_device_bid_adjustmentslist_negative_keywords_in_campaignadd_negative_keywords_to_campaignupdate_negative_keywords_in_campaignremove_negative_keywords_from_campaigncreate_ad_groupupdate_ad_groupadd_keywords_to_ad_groupupdate_keywordsremove_keywordslist_negative_keywords_in_ad_groupadd_negative_keywords_to_ad_groupupdate_negative_keywords_in_ad_groupremove_negative_keywords_from_ad_group
create_shared_negative_keyword_listupdate_shared_negative_keyword_listlist_shared_negative_keyword_listslist_keywords_in_shared_negative_listadd_keywords_to_shared_negative_listremove_keywords_from_shared_negative_listapply_shared_negative_keyword_list_to_campaignsremove_shared_negative_keyword_list_from_campaignsget_account_negative_keyword_listapply_shared_negative_keyword_list_to_accountremove_shared_negative_keyword_list_from_account
create_responsive_search_adupdate_responsive_search_ad
create_campaign_sitelink_assetcreate_campaign_callout_assetcreate_campaign_structured_snippet_assetcreate_campaign_call_asset
create_conversion_actionupdate_conversion_action
get_search_term_reportget_performance_report
- This server performs live Google Ads mutations.
- New campaigns, ad groups, keywords, and RSAs default to
PAUSEDunless you explicitly requestENABLED. - Campaign assets and conversion actions are durable Google Ads resources. Treat them as production-impacting operations.
- RSA creative updates are implemented as replace-and-remove because Google Ads treats most RSA creative fields as immutable.
Run tests with:
uv run python -m unittest discover -s tests -v