Skip to main content

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 gcloud and offers to install it).

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.

  1. Install it. No git clone, no virtualenv to manage -- if you don't have pipx yet, install that first (brew install pipx on macOS), then:

    pipx install google-ads-mcp-write
    
  2. 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 .env file 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.

  3. 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 .env file the setup command wrote. For command, run which google-ads-mcp-write in 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 mcpServers JSON block in their own settings file -- see Other MCP clients.

  4. 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. Filters get_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 to add_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 no update_ad tool; to change ad copy, create a new ad and pause the 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 from list_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

  1. The MCP Server will expose your data to the Agent or LLM that you connect to it.
  2. If you have technical issues, please use the GitHub issue tracker.
  3. 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

  1. Install Antigravity or Antigravity IDE.

  2. 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_JSON with the path you copied in the previous step. We also recommend adding a GOOGLE_CLOUD_PROJECT attribute to the env object -- replace YOUR_PROJECT_ID with 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:

  1. An explicit path set via the GOOGLE_ADS_MCP_TOOLS_CONFIG environment variable.
  2. A tools_config.yaml file in the current working directory.
  3. The default tools_config.yaml bundled 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_customers
  • metadata_get_resource_metadata
  • search_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 to http://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, or memory).
  • GOOGLE_ADS_MCP_STORAGE_PATH: (Optional) Directory path for filetree persistent storage.
  • GOOGLE_ADS_MCP_STORAGE_REDIS_URL: (Optional) Redis URL for redis persistent storage.
  • GOOGLE_ADS_MCP_STORAGE_FIRESTORE_PROJECT: (Optional) Google Cloud project for firestore persistent storage. Defaults to the project inferred from Application Default Credentials. Setting it selects the firestore backend even if GOOGLE_ADS_MCP_STORAGE_TYPE is unset.
  • GOOGLE_ADS_MCP_STORAGE_FIRESTORE_DATABASE: (Optional) Firestore database name for firestore persistent 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 to true to 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

  1. A Google Cloud project.
  2. The gcloud CLI 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.

  1. Create a repository in Artifact Registry:
    gcloud artifacts repositories create mcp-servers --repository-format=docker --location=us-central1
    
  2. Build and submit the image:
    gcloud builds submit --tag us-central1-docker.pkg.dev/YOUR_PROJECT_ID/mcp-servers/google-ads-mcp:latest .
    
    Replace YOUR_PROJECT_ID with 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 to firestore to use Firestore through Application Default Credentials, which needs no VPC connector, or to redis along with GOOGLE_ADS_MCP_STORAGE_REDIS_URL.

    Using firestore requires three things: build the image with the extra installed (change the Dockerfile to uv pip install --system .[firestore]), create a Firestore database in the project, since one is not provisioned automatically, and grant the Cloud Run service account roles/datastore.user. Note that entries are not expired automatically: the store filters expired entries on read but never deletes them, and expires_at is 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 to 0.0.0.0 to 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)

Source distribution for google-ads-mcp-write 0.1.0
File Size Uploaded
google_ads_mcp_write-0.1.0.tar.gz 92.6 kB

Built distribution (wheel)

Table of built distributions (wheels) for google-ads-mcp-write 0.1.0
File Interpreter ABI Platform
google_ads_mcp_write-0.1.0-py3-none-any.whl Python 3 none any

Total release size: 178.6 kB

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page