Google Ads MCP Server (write fork)
Manage your Google Ads account by talking to an AI assistant (like Claude) instead of clicking through the Ads UI or a rules engine -- read performance, find wasted spend, adjust budgets and bids, pause things, build campaigns -- with every change shown to you as a plain before/after diff before it touches your account, and a one-command undo if you change your mind.
This is a fork of Google's own official googleads/google-ads-mcp (which is read-only) that adds a guardrailed write layer, a few marketer-specific reporting tools, and a local undo journal. See NOTICE for attribution.
Is this for you?
If you manage Google Ads accounts -- in an agency, in-house, or as a freelancer -- and you're comfortable typing into Claude, this is built for you specifically. You don't need to write code or touch the Google Ads API directly; the one-time setup below is a guided script, not a dev environment. If you're technical and want to self-host this for a team, skip to Advanced: hosting and other MCP clients once you've read the safety model.
What it's actually good for. Being honest about this rather than overselling it: this tool's strongest, most differentiated value is in two places. First, the search-term-review-to-negative-keyword workflow, since that's consistently the single biggest recurring time-sink in PPC account management. Second, and more importantly, the local undo journal -- no other tool in this space, including Google's own account change history, gives you a real one-command rollback for a mutation you regret. Building brand-new campaigns from scratch is not this tool's strongest use case -- Google Ads Editor already does that well, for free, and campaign creation isn't something you do often anyway. Think of this as "safely execute and undo the fixes you already decided on," not "replace your whole PPC toolkit."
What you need
- A Google Ads account you have access to (yours, your client's, or your employer's).
- A free Google Cloud project with the Google Ads API enabled. This is not optional and it is not this project's infrastructure -- it's a policy requirement (see Credentials and hosting policy below) and it takes about 10 minutes with the setup script.
- About 15-20 minutes for the one-time setup. You won't need to touch this again afterward.
- Python installed (the setup script checks for everything else,
including whether you have
gcloudand offers to install it).
Quick start (recommended path)
This runs entirely on your own computer. Nothing you set up here is shared with anyone, including us -- there is no hosted version of this tool; see why.
-
Install it. No git clone, no virtualenv to manage -- if you don't have pipx yet, install that first (
brew install pipxon macOS), then:pipx install google-ads-mcp-write
-
Run the guided setup command:
google-ads-mcp-write-setup
This walks you through everything that can be automated -- signing into
gcloud, creating a Cloud project, enabling the Google Ads API -- using real commands instead of you clicking through Google Cloud Console screens. It then opens your browser at exactly the two steps Google requires a human to click through by design (creating the OAuth client, and granting consent) and writes the result to a local.envfile in whatever directory you ran it from. At the end it tells you plainly what's still manual: applying for API access on your Cloud project, and creating a Google Ads test account if you want one for practice before touching a live account.If something goes wrong partway through, the command is safe to re-run -- it picks up from wherever you left off.
-
Add the server to Claude Desktop. Open Claude's settings, find the MCP server configuration, and add:
{ "mcpServers": { "google-ads-mcp-write": { "command": "/absolute/path/to/google-ads-mcp-write", "env": { "GOOGLE_ADS_CLIENT_ID": "YOUR_OAUTH_CLIENT_ID", "GOOGLE_ADS_CLIENT_SECRET": "YOUR_OAUTH_CLIENT_SECRET", "GOOGLE_ADS_REFRESH_TOKEN": "YOUR_REFRESH_TOKEN" } } } }
The three credential values come straight out of the
.envfile the setup command wrote. Forcommand, runwhich google-ads-mcp-writein the same terminal you installed it in and paste that path -- Claude Desktop is a separate app and may not see your shell's PATH, so the bare command name alone can fail to resolve even though it works in your terminal. If your Google Ads account sits under a manager (MCC) account, also add"GOOGLE_ADS_LOGIN_CUSTOMER_ID": "YOUR_MANAGER_CUSTOMER_ID"-- see Login Customer Id below.Other MCP clients (Claude Code, Cursor, VS Code with Copilot) use the same
mcpServersJSON block in their own settings file -- see Other MCP clients. -
Restart Claude and try it. Ask something like "what customers do I have access to?" to confirm it's connected, then jump to What you can actually do with it below for real workflows to try.
If you'd rather build from source, contribute to the project, or the command gets stuck on a step, the full manual walkthrough is in Manual setup and troubleshooting.
What you can actually do with it
These are organized by the actual job, not by tool name -- the tool names in parentheses are what's happening under the hood if you want to look them up in the full tool reference.
Find and cut wasted spend
The classic, highest-value PPC task: find search terms that are costing you money without converting, and block them.
Show me search terms that got clicks but zero conversions in the last 30 days for customer 1234567890
(get_negative_keyword_candidates) This comes back sorted by wasted
spend, and flags anything that's already an active keyword in your account
(you'd want to pause that keyword rather than also negative it). Review
the list, then:
Add "leather sofa cheap" as an exact-match negative keyword to that ad group
(add_negative_keywords) You'll see the exact change before it commits
-- nothing happens to your account until you say so.
Understand where you stand
What's the account structure for customer 1234567890?
How is my campaign performance this week?
What are my top search terms by cost?
(get_account_structure, get_campaign_performance,
get_ad_group_performance, get_keyword_performance, get_search_terms)
Check what Google itself is suggesting
What recommendations does Google have for this account?
(get_recommendations) Worth a caveat: these are Google's own
suggestions, and practitioners are often right to be skeptical of them --
treat this as one more input to judge, not an instruction to follow.
Adjust budgets, bids, and status
Raise the daily budget on campaign X to $50
Pause the "Winter Sale" campaign
Lower the CPC bid on this ad group to $1.20
(update_budget, pause/enable, update_keyword, update_ad_group)
Build something new
Create a new paused Search campaign called "Spring Launch" with a $30 daily budget
Add these keywords to the new ad group: ...
Write a responsive search ad for this ad group with these headlines and descriptions: ...
(create_campaign, create_ad_group, add_keywords,
create_responsive_search_ad) New campaigns, ad groups, and ads are
always created paused by default, so nothing spends until you
explicitly enable it.
See what changed, and undo it
This is the tool's real safety net, and it's worth using on purpose, not just when something goes wrong.
What have you changed in this account recently?
Undo that last change
(list_recent_changes, undo_change) Every commit is logged locally
before it happens. Undo re-reads the current state and reverts through the
same review-before-commit process -- it's a reviewed write too, not a
silent rollback. The one thing that can't be undone is removing a keyword
outright (remove_keywords) -- prefer pausing a keyword over removing it
if you might want it back.
How the safety model works
Every write tool follows the same four steps, always:
1. READ current state of what you're about to change
2. VALIDATE a real dry-run against the Google Ads API
3. DIFF shows you exactly what would change, before/after
4. COMMIT only after you explicitly approve -- nothing happens silently
Nothing commits on the first call. You'll always see the diff first.
Only when you (or the assistant, after you've said yes) calls the tool
again with confirm=true does anything actually change in your account.
Every commit is journaled locally -- to ~/.google-ads-mcp-write/journal.jsonl
(override with GOOGLE_ADS_MCP_JOURNAL_PATH) -- before the change is
sent, so there's always a record even if something goes wrong mid-write.
Credentials and hosting policy
This section exists because Google's Ads Developer Policies name MCP servers explicitly and prohibit operating a hosted, shared "programmatic proxy" to the Google Ads API. This project stays inside the policy's open-source carve-out, which is why setup looks the way it does:
- You bring your own Google Cloud project and your own Google Ads access. No credentials of any kind ship with this software, in examples or otherwise -- that's not a corner we cut, it's not allowed to exist any other way.
- This runs locally on your machine, under your own account, with no shared or hosted endpoint. (The FastMCP OAuth-proxy / Streamable-HTTP path documented under Advanced is for running your own private instance across your own multiple local clients -- it is not a green light to operate a shared or multi-tenant deployment of this fork's write tools. Do that and Google's Developer Secondary Interface Review requirements land on you.)
- Every write requires your explicit confirmation before it touches your account. This isn't just good UX -- it's a compliance requirement. Google's policy requires that you, the account owner, are the one authorizing changes, not a fully autonomous background process.
This is not legal advice. Get your own compliance read from the Google Ads API team before hosting any part of this for other people.
Full tool reference
Read tools
search: Retrieves information about the Google Ads account.get_resource_metadata: Retrieves metadata about a Google Ads API resource type, for example "campaign". This is useful to understand the structure of the data and what fields are available for querying.list_accessible_customers: Returns ids of customers directly accessible by the user authenticating the call.get_account_structure: Campaigns -> ad groups -> ads/keywords, names/IDs/status only. Cached for the life of the server session.get_campaign_performance,get_ad_group_performance,get_keyword_performance,get_search_terms: Shaped performance reports (impressions, clicks, cost, conversions). Default to the last 30 days, cap the number of rows returned, and convert cost fields out of the API's micros into plain currency units.get_recommendations: Google's own auto-generated account/campaign recommendations (the same ones shown in the Ads UI's "Recommendations" page), with Google's estimated impact metrics. Read-only -- applying a recommendation means using the specific write tool for the change it suggests.get_negative_keyword_candidates: The read half of the search-term-review workflow. Filtersget_search_terms-style data down to terms with clicks/spend and zero conversions (the standard PPC triage heuristic), sorted by wasted spend. A heuristic for a human to review, not an automatic verdict -- pass the ones you approve toadd_negative_keywords.
Write tools
pause,enable: Pauses/enables a campaign, ad group, ad, or keyword.update_budget: Updates a campaign's daily budget.update_campaign: Updates a campaign's name, status, linked budget, and/or bidding strategy.create_campaign: Creates a new Search campaign with its own budget, atomically (via temporary resource names). Defaults to Manual CPC bidding; also supports Target CPA, Target Spend, Maximize Conversions, Maximize Conversion Value, and Target ROAS -- the strategies that make sense for a Search campaign, out of the API's full set of 16 (most of the rest are Display/Video/Shopping-only). The Smart Bidding strategies (Target CPA/ROAS, Maximize Conversions/Value) require conversion tracking to be set up on the account -- Google rejects them with "Conversion tracking is not enabled" otherwise, which is a real account-eligibility restriction, not a bug in this tool. The Target-style strategies specifically also need the campaign itself to already have conversion history -- a brand-new campaign can't set a Target CPA/ROAS/Spend on day one, regardless of account access level.create_ad_group,update_ad_group: Creates an ad group, or updates its name/status/default CPC bid.create_responsive_search_ad: Creates a Responsive Search Ad. Ad content (headlines, descriptions, final URLs, name) is entirely immutable after creation -- confirmed against the live API -- so there is noupdate_adtool; to change ad copy, create a new ad andpausethe old one (entity_type="ad", the only field on an ad that stays mutable).add_keywords,update_keyword,remove_keywords: Adds positive keywords, updates a keyword's status/bid, or removes keywords (irreversible).add_negative_keywords: Adds negative keywords to an ad group or campaign.create_conversion_action,update_conversion_action: Creates or updates a website (Google tag) conversion action. Required before the Smart Bidding strategies (Target CPA/ROAS, Maximize Conversions/Value) above will work -- Google rejects those with "Conversion tracking is not enabled" otherwise.
Safety tools
list_recent_changes: Lists this server's own recent writes, from its local mutation journal.undo_change: Reverts a previously committed write, looked up by the id fromlist_recent_changes. Reconstructs and runs the inverse of that write through the same preview/confirm pipeline -- it does not erase or edit the original journal entry, it adds a new one.
Every write tool runs a dry-run validate_only call against the real API
and returns a before/after diff on its first call. It only commits when
called again with confirm=true -- never set confirm=true without first
showing the diff to the user and getting their explicit approval. New
campaigns, ad groups, and ads default to status PAUSED so nothing starts
spending without an explicit enable call. create_campaign only
supports Search campaigns; RSA headlines and descriptions are immutable
once created (Google Ads requires creating a new ad instead of editing
them); remove_keywords cannot be undone even with undo_change --
re-create with add_keywords instead -- so prefer pause wherever the
semantics allow.
Error handling
Failures from the Google Ads API are mapped to actionable guidance where
possible (ads_mcp/errors.py): a missing/wrong login-customer-id, a
Cloud project that isn't approved for production access, the known
post-2026-09-09 developer-token-sunset authorization issue, hitting the
daily operation cap vs. a transient QPS limit, sending more than 10,000
operations in one mutate, and querying date segments outside the 37-month
retention window each get a specific explanation rather than just the raw
API message. Every error always leads with the request ID, since that's
the only thing Google Ads API support can act on.
Resources available
discovery-document: Retrieve the Google Ads API discovery document. Provides the discovery document for the latest version of the Google Ads API, which describes the API surface, including resources, methods, and schemas. Host LLMs should access this resource to understand the structure of the Google Ads API and discover available features.metrics: Retrieve information about the metrics available for reporting in the Google Ads API.segments: Retrieve information about the segments available for reporting in the Google Ads API.release-notes: Retrieve the release notes for the latest version of the Google Ads API.
Notes
- The MCP Server will expose your data to the Agent or LLM that you connect to it.
- If you have technical issues, please use the GitHub issue tracker.
- To help us collect usage data, you will notice an extra header has been added to your API calls: this data is used to improve the product.
Manual setup and troubleshooting
Configure Python
The Quick start above already covers the
pipx install google-ads-mcp-write path most people want, including a
pinned version if you need one:
pipx run --spec "google-ads-mcp-write==X.Y.Z" google-ads-mcp-write
If you're contributing to the project or want to run from a local checkout instead:
git clone https://github.com/iachi/google-ads-mcp-write.git
cd google-ads-mcp-write
python3 -m venv .venv
source .venv/bin/activate
pip install -e .
google-ads-mcp-write
An editable install (pip install -e .) also gives you
google-ads-mcp-write-setup and google-ads-mcp-write-get-refresh-token
pointed at your local checkout, so you can test changes to the setup flow
itself.
Configure Developer Token (usually not needed)
Developer tokens were sunset on 2026-09-09. Access level is now derived from the Cloud project that owns your OAuth client, not from a separate developer token. Don't request or set one unless you know your specific setup still requires it.
We recommend applying for Basic access (15,000 operations/day, now auto-reviewed within minutes) on your Cloud project rather than relying on Explorer access (2,880 ops/day) -- an agent session burns through Explorer's quota quickly, though Explorer is enough to get started and already allows production reads and writes. See Access levels and permissible use.
Known upstream issue: a Cloud project still on the Free Trial, or with suspended/disabled billing, gets rejected for Basic or Explorer access even after brand verification succeeds. If your access application is denied for no clear reason, check your project's billing status first -- enable billing (a paid account, not just a valid payment method on a trial) and re-apply.
If your setup still requires a legacy developer token, follow the instructions for Obtaining a Developer Token.
Your developer token must have at least Explorer access to query production accounts. New tokens may be automatically upgraded to Explorer access; if not, you can apply through the API Center. See the access levels documentation for details.
If you see the error "The developer token is only approved for use with test accounts", your token does not yet have access to production accounts. See the access levels documentation for how to request the access level you need.
Enable APIs in your project
Follow the instructions to enable the following APIs in your Google Cloud project:
Configure Credentials
Option 1: Standalone OAuth client + refresh token (what the setup command does)
This is the most common path for running this server locally over stdio
against your own account, and needs no gcloud setup. Create an OAuth 2.0
client ID (Desktop app type) in the Google Cloud project that has the Google
Ads API enabled, then run google-ads-mcp-write-get-refresh-token yourself
to obtain a refresh token for the https://www.googleapis.com/auth/adwords
scope -- it opens your own browser for you to sign in and grant access with
your own Google account, and prints the values below:
google-ads-mcp-write-get-refresh-token \
--client-id YOUR_CLIENT_ID \
--client-secret YOUR_CLIENT_SECRET
Then set:
GOOGLE_ADS_CLIENT_ID: The OAuth 2.0 Client ID from that Cloud project.GOOGLE_ADS_CLIENT_SECRET: The OAuth 2.0 Client Secret from that Cloud project.GOOGLE_ADS_REFRESH_TOKEN: The refresh token obtained from that client's consent flow.
These are checked before falling back to Application Default Credentials, so
you don't need to touch utils.py or run gcloud auth application-default login. Note that developer tokens were sunset on 2026-09-09 -- do not
set GOOGLE_ADS_DEVELOPER_TOKEN unless your setup specifically still
requires one; access level now derives from the Cloud project that owns the
OAuth client.
Option 2: Application Default Credentials
Configure your Application Default Credentials (ADC). Make sure the credentials are for a user with access to your Google Ads accounts or properties.
Credentials must include the Google Ads API scope:
https://www.googleapis.com/auth/adwords
Check out Manage OAuth Clients for how to create an OAuth client.
Here are some sample gcloud commands you might find useful:
-
Set up ADC using user credentials and an OAuth desktop or web client after downloading the client JSON to
YOUR_CLIENT_JSON_FILE.gcloud auth application-default login \ --scopes https://www.googleapis.com/auth/adwords,https://www.googleapis.com/auth/cloud-platform \ --client-id-file=YOUR_CLIENT_JSON_FILE
-
Set up ADC using service account impersonation.
gcloud auth application-default login \ --impersonate-service-account=SERVICE_ACCOUNT_EMAIL \ --scopes=https://www.googleapis.com/auth/adwords,https://www.googleapis.com/auth/cloud-platform
When the gcloud auth application-default command completes, copy the
PATH_TO_CREDENTIALS_JSON file location printed to the console in the
following message. You will need this for a later step!
Credentials saved to file: [PATH_TO_CREDENTIALS_JSON]
Option 3: Google Ads API Python client library config
Follow the instructions to setup and configure the Google Ads API Python client library.
If you have already done this and have a working google-ads.yaml, you can reuse this file!
In the utils.py file, change get_googleads_client() to use the load_from_storage() method.
Configure your MCP client
Antigravity / Antigravity IDE
-
Install Antigravity or Antigravity IDE.
-
Configure your server. Refer to the docs at https://antigravity.google/docs/mcp for details on setting up MCP servers.
-
Option 1: the standalone OAuth client + refresh token method (recommended)
{ "mcpServers": { "google-ads-mcp-write": { "command": "/absolute/path/to/google-ads-mcp-write/.venv/bin/google-ads-mcp-write", "env": { "GOOGLE_ADS_CLIENT_ID": "YOUR_OAUTH_CLIENT_ID", "GOOGLE_ADS_CLIENT_SECRET": "YOUR_OAUTH_CLIENT_SECRET", "GOOGLE_ADS_REFRESH_TOKEN": "YOUR_REFRESH_TOKEN" } } } }
-
Option 2: the Application Default Credentials method
This remains a supported alternative, but it provides less credential isolation than the standalone OAuth method above. The MCP client starts the server and its configuration contains the ADC file path.
Replace
PATH_TO_CREDENTIALS_JSONwith the path you copied in the previous step. We also recommend adding aGOOGLE_CLOUD_PROJECTattribute to theenvobject -- replaceYOUR_PROJECT_IDwith the project ID of your Google Cloud project.{ "mcpServers": { "google-ads-mcp-write": { "command": "/absolute/path/to/google-ads-mcp-write/.venv/bin/google-ads-mcp-write", "env": { "GOOGLE_APPLICATION_CREDENTIALS": "PATH_TO_CREDENTIALS_JSON", "GOOGLE_PROJECT_ID": "YOUR_PROJECT_ID" } } } }
-
Option 3: the Python client library method
{ "mcpServers": { "google-ads-mcp-write": { "command": "/absolute/path/to/google-ads-mcp-write/.venv/bin/google-ads-mcp-write", "env": { "GOOGLE_PROJECT_ID": "YOUR_PROJECT_ID" } } } }
Login Customer Id
If your access to the customer account is through a manager account, you will need to add the customer ID of the manager account to the settings file.
See here for details.
The final file will look like this:
{
"mcpServers": {
"google-ads-mcp-write": {
"command": "/absolute/path/to/google-ads-mcp-write/.venv/bin/google-ads-mcp-write",
"env": {
"GOOGLE_ADS_CLIENT_ID": "YOUR_OAUTH_CLIENT_ID",
"GOOGLE_ADS_CLIENT_SECRET": "YOUR_OAUTH_CLIENT_SECRET",
"GOOGLE_ADS_REFRESH_TOKEN": "YOUR_REFRESH_TOKEN",
"GOOGLE_ADS_LOGIN_CUSTOMER_ID": "YOUR_MANAGER_CUSTOMER_ID"
}
}
}
}
Other MCP clients
The mcpServers block format is the same across all MCP clients. Add the configuration shown above to the appropriate settings file for your client (e.g., ~/.claude/settings.json for Claude Code, .cursor/mcp.json for Cursor, .vscode/mcp.json for VS Code with Copilot).
Configuring and Namespacing Tools
The Google Ads MCP server uses the tools_config.yaml to let you selectively enable or disable individual tools or tool categories (namespaces) and customize their namespace prefixes.
A default tools_config.yaml with all tools enabled is bundled with the package, so the server works out of the box with no extra setup. To customize your installation, the server resolves the configuration in the following order:
- An explicit path set via the
GOOGLE_ADS_MCP_TOOLS_CONFIGenvironment variable. - A
tools_config.yamlfile in the current working directory. - The default
tools_config.yamlbundled with the package.
If an explicitly requested configuration file (via the environment variable) is missing, or any resolved file is invalid, the server raises an error and fails to start.
Configuration Example:
namespaces:
# Option 1: Enable category 'customers' with default prefix -> "customers_list_accessible_customers"
customers: true
# Option 2: Enable category 'search' with a custom prefix -> "query_search"
search: "query"
# Option 3: Fine-grained control over tools in a category
metadata:
enabled: true
prefix: "metadata"
enabled_tools:
- get_resource_metadata: true
Advanced: hosting and other MCP clients
Most users should stop at Quick start above -- this section is for running the server as a shared local endpoint across several of your own clients, or self-hosting for a team. Re-read Credentials and hosting policy first: this still has to run under your own access and can't become a shared multi-tenant service for other people.
Local WSL and Podman deployment
This deployment has been tested with rootless Podman in WSL and exposes a single
Streamable HTTP endpoint at http://localhost:8080/mcp. Build the image from
the repository inside WSL:
podman build --tag localhost/google-ads-mcp:latest --file Dockerfile .
Keep server credentials out of MCP client configuration. The tested Quadlet
loads Google Ads and OAuth settings from a private host-side file through
EnvironmentFile= and uses a separate named volume for persistent encrypted
OAuth state:
[Container]
Image=localhost/google-ads-mcp:latest
PublishPort=127.0.0.1:8080:8080
EnvironmentFile=/absolute/host/path/google-ads-mcp.env
Volume=google-ads-mcp-oauth.volume:/var/lib/google-ads-mcp:rw
ReadOnly=true
NoNewPrivileges=true
DropCapability=all
The environment file and the OAuth-state volume serve different purposes: the
volume does not contain the .env file. Keep the environment file outside the
repository, restrict it to the service owner, and never commit it. Antigravity
and Codex then need only the MCP endpoint and their own OAuth authorization;
they do not need the server's Google Ads developer token, OAuth client secret,
or signing and storage keys. Publish port 8080 only on the loopback interface
when the server is intended for local agents.
The endpoint deliberately keeps stateful Streamable HTTP enabled. It supports
legacy MCP 2025 clients that use Mcp-Session-Id and GET SSE as well as MCP
2026 clients that use sessionless POST requests and subscriptions/listen.
Do not enable FastMCP's stateless_http option on this shared endpoint; doing
so removes the legacy GET channel.
The server runs on FastMCP 4 (fastmcp>=4.0.3) paired with mcp[cli]==2.0.0. The Docker build also applies a version-guarded
OAuth metadata workaround for Codex CLI 0.146. It stops advertising the RFC
9207 authorization-response iss parameter as mandatory while FastMCP still
includes it in redirects. The build fails if the expected FastMCP version or
patch location changes, so upgrades require explicit interoperability tests.
For Codex, configure and authenticate the server as described in the official Codex MCP documentation:
codex mcp add google_ads --url http://localhost:8080/mcp
codex mcp login google_ads
For Antigravity, configure the same URL as serverUrl in its MCP configuration.
This key is required for Streamable HTTP in Antigravity 2.8.1 and Antigravity
IDE 2.5.5; httpUrl is not accepted by those versions. After authentication,
both clients should list these namespaced tools:
customers_list_accessible_customersmetadata_get_resource_metadatasearch_search
Using FastMCP OAuth Proxy
The server supports FastMCP's OAuth proxy feature for dynamic user authentication. This is useful when running the server as a web service for your own multiple clients.
To enable it, set the following environment variables:
GOOGLE_ADS_MCP_OAUTH_CLIENT_ID: Your Google Cloud OAuth 2.0 Client ID.GOOGLE_ADS_MCP_OAUTH_CLIENT_SECRET: Your Google Cloud OAuth 2.0 Client Secret.GOOGLE_ADS_MCP_BASE_URL: (Optional) The base URL where the server is accessible (defaults tohttp://localhost:8080).GOOGLE_ADS_MCP_JWT_SIGNING_KEY: (Optional) Secret key used to sign FastMCP JWT tokens across multiple server instances or deployments.GOOGLE_ADS_MCP_STORAGE_TYPE: (Optional) Storage backend for OAuth state (filetree,redis,firestore, ormemory).GOOGLE_ADS_MCP_STORAGE_PATH: (Optional) Directory path forfiletreepersistent storage.GOOGLE_ADS_MCP_STORAGE_REDIS_URL: (Optional) Redis URL forredispersistent storage.GOOGLE_ADS_MCP_STORAGE_FIRESTORE_PROJECT: (Optional) Google Cloud project forfirestorepersistent storage. Defaults to the project inferred from Application Default Credentials. Setting it selects thefirestorebackend even ifGOOGLE_ADS_MCP_STORAGE_TYPEis unset.GOOGLE_ADS_MCP_STORAGE_FIRESTORE_DATABASE: (Optional) Firestore database name forfirestorepersistent storage. Defaults to(default).GOOGLE_ADS_MCP_STORAGE_ENCRYPTION_KEY: (Optional) Encryption key for stored OAuth tokens.GOOGLE_ADS_MCP_STORAGE_DISABLE_ENCRYPTION: (Optional) Set totrueto disable token encryption.
The redis and firestore backends need their storage library installed
alongside the server: pip install py-key-value-aio[redis] and
pip install google-ads-mcp[firestore] respectively.
Once this is enabled, you can authenticate to the API through your MCP client.
When these variables are set, the server automatically switches to the
streamable-http transport instead of stdio.
You will need to run the server as a separate process and configure your MCP
client to connect to the Streamable HTTP endpoint (for example,
http://localhost:8080/mcp), e.g.:
{
"mcpServers": {
"google-ads-mcp": {
"serverUrl": "http://localhost:8080/mcp"
}
}
}
Deployment to Google Cloud Platform
Instead of hosting this MCP server locally, you can host it on Google Cloud Run or on any other cloud-based infrastructure, for your own use across your own clients. This only supports authentication with an OAuth Client ID and Client Secret pair through the OAuth proxy above.
Prerequisites
- A Google Cloud project.
- The
gcloudCLI installed, authenticated, and active project set.gcloud config set project YOUR_PROJECT_ID
Step 1: Build and Push Docker Image
You can use Cloud Build to build and push the image to Artifact Registry without needing Docker installed locally.
- Create a repository in Artifact Registry:
gcloud artifacts repositories create mcp-servers --repository-format=docker --location=us-central1
- Build and submit the image:
gcloud builds submit --tag us-central1-docker.pkg.dev/YOUR_PROJECT_ID/mcp-servers/google-ads-mcp:latest .
ReplaceYOUR_PROJECT_IDwith your Google Cloud project ID.
Step 2: Deploy to Google Cloud Run
Make sure to set the required environment variables:
-
GOOGLE_PROJECT_ID: Your Google Cloud project ID. -
GOOGLE_ADS_MCP_OAUTH_CLIENT_ID: The OAuth Client ID you want the MCP server to use. -
GOOGLE_ADS_MCP_OAUTH_CLIENT_SECRET: The OAuth Client secret you want the MCP server to use. -
GOOGLE_ADS_MCP_BASE_URL: The base URL where your MCP server is accessible: this will be automatically assigned by Google Cloud Run after your first deployment. You can update the environment variables after deployment. -
GOOGLE_ADS_MCP_JWT_SIGNING_KEY: (Recommended for production) Persistent JWT signing key across Cloud Run instances. -
GOOGLE_ADS_MCP_STORAGE_TYPE: (Recommended for production) Storage backend to persist OAuth tokens across instances. Set it tofirestoreto use Firestore through Application Default Credentials, which needs no VPC connector, or toredisalong withGOOGLE_ADS_MCP_STORAGE_REDIS_URL.Using
firestorerequires three things: build the image with the extra installed (change the Dockerfile touv pip install --system .[firestore]), create a Firestore database in the project, since one is not provisioned automatically, and grant the Cloud Run service accountroles/datastore.user. Note that entries are not expired automatically: the store filters expired entries on read but never deletes them, andexpires_atis written as a string, so a Firestore TTL policy cannot collect them either. Plan on a periodic cleanup job for long-running deployments. Redis expires entries on its own. -
FASTMCP_HOST: Set this to0.0.0.0to allow FastMCP to accept connections from all IP addresses. -
GOOGLE_ADS_LOGIN_CUSTOMER_ID: Required if your access to the customer account is through a manager account. Set it to the customer ID of the manager account. See Login Customer Id above for details.
gcloud run deploy google-ads-mcp \
--image us-central1-docker.pkg.dev/YOUR_PROJECT_ID/mcp-servers/google-ads-mcp:latest \
--platform managed \
--region us-central1 \
--allow-unauthenticated \
--set-env-vars="GOOGLE_PROJECT_ID=YOUR_PROJECT_ID,GOOGLE_ADS_MCP_OAUTH_CLIENT_ID=YOUR_CLIENT_ID,GOOGLE_ADS_MCP_OAUTH_CLIENT_SECRET=YOUR_CLIENT_SECRET,GOOGLE_ADS_MCP_BASE_URL=YOUR_BASE_URL,GOOGLE_ADS_MCP_JWT_SIGNING_KEY=YOUR_JWT_SIGNING_KEY,GOOGLE_ADS_MCP_STORAGE_TYPE=firestore,FASTMCP_HOST=0.0.0.0"
Step 3: Configure MCP Client
Once deployed, update your MCP client configuration (refer to the docs at https://antigravity.google/docs/mcp) to use the Cloud Run URL.
{
"mcpServers": {
"google-ads-mcp": {
"httpUrl": "https://your-cloud-run-url.a.run.app/mcp"
}
}
}
Contributing
Contributions welcome! See the Contributing Guide. Project maintainers can find the Trusted Publishing and release procedure in the release guide.
Release files for google-ads-mcp-write 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| google_ads_mcp_write-0.1.0.tar.gz | 92.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| google_ads_mcp_write-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 178.6 kB
Release files / google_ads_mcp_write-0.1.0.tar.gz
| Download URL | google_ads_mcp_write-0.1.0.tar.gz |
|---|---|
| Size | 92.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f7ff527d66485e9204211c4242bfb1479d0e348d046c3fbebf169f6ceea01035
|
|
BLAKE2b-256 checksum How to use checksums |
27504e49d82b25dba3f14987a002ffa24bfb167ef7110cf27696ced0a7567151
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.
Transparency logRelease files / google_ads_mcp_write-0.1.0-py3-none-any.whl
| Download URL | google_ads_mcp_write-0.1.0-py3-none-any.whl |
|---|---|
| Size | 86.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f5420c67e3cf22f254645ab1ef3e1a90e7e64a86285fc07a96859b66f7b140e6
|
|
BLAKE2b-256 checksum How to use checksums |
912a56da2a77a1c138e57083bc9f38504ed93bd038c14021a201e13b5265b2a2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.
Transparency log