npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

google-ads-full-readwrite-mcp

v0.3.0

Published

MCP server for Google Ads with full read and write access — manage campaigns, ads, assets, budgets, and keywords from any MCP host.

Readme

google-ads-full-readwrite-mcp

A Model Context Protocol (MCP) server that exposes the Google Ads API as a set of LLM-callable tools. Read and write surface covers campaigns, ad groups, ads, assets, Performance Max asset groups, budgets, bidding strategies, keywords, recommendations, conversion-action listing, and arbitrary GAQL queries.

Why this exists

Managing Google Ads campaigns by hand in the web UI is slow and clicky. This MCP lets any MCP-aware host (Claude Desktop, IDE agents, etc.) operate Google Ads from natural-language prompts: build a campaign, set budgets, add keywords, write ads, attach assets, and review performance, all from chat.

Existing MCP options for Google Ads are either read-only, proprietary, or incomplete on the write surface. This package is open-source (MIT), Node-packageable, write-capable across the routine surface of the Ads API, and installable via npx with no SaaS gateway or paid hosting.

Requirements

  • Node.js 18 or newer.
  • A Google Ads manager (MCC) account with a developer token at Explorer level or higher.
  • A Google Ads operating customer account linked to that MCC.
  • A Google Cloud project (free; no billing required) with the Google Ads API enabled and an OAuth 2.0 client of type Desktop application.
  • A refresh token minted via the bundled --login flow.

If you don't have all of these yet, the One-time setup section below walks through each one from scratch.

One-time setup

The pre-flight checklist has seven steps. The first one (developer token approval) takes the longest, so start it first.

1. Apply for a Google Ads developer token

The developer token lets your code call the Google Ads API at all. It is issued to a manager (MCC) account, not to an individual user.

  1. If you do not yet have an MCC, create one at https://ads.google.com/home/tools/manager-accounts/.
  2. Sign into the MCC. Tools & Settings → API Center → Apply for a token.
  3. Fill in the application form. For non-production work against test accounts only, you can request a Test access token (issued instantly). For real Google Ads accounts you need at minimum Explorer access (entry-level production tier). Google reviews production-tier applications and typically responds in 1–2 business days.

Record the token value for GOOGLE_ADS_DEVELOPER_TOKEN.

2. Link your operating customer account to the MCC

The customer account whose campaigns you want to manage must be a sub-account of the MCC that owns the developer token.

  1. From the MCC, go to Sub-account settings.
  2. Click the blue + button → Link existing account, and enter the operating customer ID.
  3. Sign into the operating customer account in a separate tab and accept the invitation under Admin → Access and security → Managers (newer UI) or Tools & Settings → Setup → Account access → Managers (older UI).
  4. Back in the MCC's Sub-account settings, confirm the operating account shows as Active.

3. Create a Google Cloud project and enable the Google Ads API

  1. Open https://console.cloud.google.com. Sign in with the Google account that will own the OAuth client. (This account must also have access to the Google Ads account you want to manage.)
  2. Top bar → project picker → New Project. Name it anything (e.g. google-ads-mcp).
  3. Switch into the new project via the picker.
  4. Hamburger menu → APIs & Services → Library.
  5. Search for Google Ads API, click the result, click Enable.

No billing setup is required. The Google Ads API is free; the Cloud project is just a container for the OAuth credentials.

4. Configure the OAuth consent screen

Google requires this before issuing OAuth client credentials. Hamburger menu → APIs & Services → OAuth consent screen.

Google has been migrating between two layouts. Follow whichever you see.

Older layout (User Type radio buttons):

  1. Select External. Click Create.
  2. App name: anything (e.g. "Google Ads MCP"). User support email: your email. Developer contact email: your email. Skip everything else.
  3. Save and continue. On the Scopes page, save and continue without adding anything. (Scopes are requested at runtime by the code.)
  4. Test users page: click + Add Users, add the Google account you will authenticate with during --login. Save and continue.
  5. Leave publishing status as Testing.

Newer layout (Branding / Audience / Data Access tabs):

  1. Click Get started. Enter app name and support email. Audience: External. Contact info. Agree to the policy and Create.
  2. Open the Audience tab. Under Test users, click + Add users and add the Google account you will authenticate with during --login. Save.
  3. Leave publishing status as Testing.

5. Create the OAuth Desktop client

  1. APIs & Services → Credentials → + Create Credentials → OAuth client ID.
  2. Application type: Desktop app. Name it anything.
  3. Save the client ID and client secret. You will pass them to the MCP as GOOGLE_ADS_CLIENT_ID and GOOGLE_ADS_CLIENT_SECRET.

6. Mint a refresh token

Run the bundled login flow. From a shell with the client ID and secret in env vars:

export GOOGLE_ADS_CLIENT_ID=...
export GOOGLE_ADS_CLIENT_SECRET=...

npx -y google-ads-full-readwrite-mcp --login

On PowerShell, set env vars with $env:GOOGLE_ADS_CLIENT_ID = "..." instead of export.

The flow opens Google's consent screen in your default browser, captures the authorization code on a loopback redirect (http://127.0.0.1:<random-port>/oauth2callback), exchanges it for a refresh token, and prints the refresh token to stdout.

You will see a warning along the lines of "Google hasn't verified this app." That is expected when the consent screen is in Testing mode (which it is by default). Click Advanced → Go to (unsafe) → Continue and grant the requested scopes. You are the developer of this OAuth client, so this is safe in your own setup.

Copy the printed refresh token into your MCP host config as GOOGLE_ADS_REFRESH_TOKEN.

If you prefer to persist the refresh token to disk, run npx -y google-ads-full-readwrite-mcp --login --save. The token is written to ${LOCALAPPDATA}\google-ads-full-readwrite-mcp\auth.json on Windows or ~/.config/google-ads-full-readwrite-mcp/auth.json elsewhere, mode 0600. The server reads that file as a fallback when GOOGLE_ADS_REFRESH_TOKEN is not in the environment.

7. Note the two customer IDs

The MCP needs two ten-digit IDs, both with dashes removed.

  • MCC ID (GOOGLE_ADS_LOGIN_CUSTOMER_ID) is shown in the top-right of any MCC view. 123-456-7890 becomes 1234567890.
  • Operating account ID (GOOGLE_ADS_CUSTOMER_ID) is shown in the top-right when the operating account is selected, or in the MCC's Sub-account settings under the Account column. Same dash-stripping rule.

Configuration

All configuration is via environment variables. Nothing is baked into the package.

| Variable | Required | Purpose | |---|---|---| | GOOGLE_ADS_DEVELOPER_TOKEN | yes | Developer token issued to your MCC. | | GOOGLE_ADS_CLIENT_ID | yes | OAuth 2.0 client ID (Desktop app). | | GOOGLE_ADS_CLIENT_SECRET | yes | OAuth client secret. | | GOOGLE_ADS_REFRESH_TOKEN | yes | Refresh token from --login. | | GOOGLE_ADS_LOGIN_CUSTOMER_ID | yes | MCC customer ID (no dashes). | | GOOGLE_ADS_CUSTOMER_ID | yes for write tools | Operating customer ID (no dashes). Defaults to LOGIN_CUSTOMER_ID. | | GOOGLE_ADS_MCP_CONFIRM_WRITES | optional | false to skip confirm:true requirement on destructive ops. Default true. | | GOOGLE_ADS_MCP_DRY_RUN | optional | true makes every mutate tool log + return success without calling the API. | | GOOGLE_ADS_MCP_MAX_BUDGET_MICROS | optional | Soft ceiling on create_budget/update_budget. Default 100000000000 (≈ $100,000/day). | | GOOGLE_ADS_MCP_LOG_LEVEL | optional | error, warn, info, debug. Default info. |

Security and credential handling

The MCP requires six credentials, listed in Configuration. Treat all six as sensitive. In particular, the refresh token is a long-lived bearer credential: anyone who holds all six values can call the Google Ads API against your account and spend real money up to your configured daily budgets.

What not to do

Do not place any of the six credentials in:

  • A git repository, public or private. Commit a .env.example with empty values instead, and keep the real file out of source control.
  • A cloud-synced folder such as OneDrive, Dropbox, Google Drive, iCloud Drive, or Box. Anything in those folders syncs to every device your account is logged in on, plus the provider's servers and backups.
  • A shared team workspace, ticket tracker, chat thread, support email, or AI-assistant transcript.
  • A file readable by other user accounts on the same machine. On POSIX systems, chmod 600 the file before writing anything sensitive into it. On Windows, remove inherited permissions and grant your own user account only.

Recommended patterns

In rough order from most secure to acceptable:

  1. OS secret manager. Store each value in your operating system's keyring (Windows Credential Manager, macOS Keychain, Linux Secret Service / gnome-keyring) and load them into environment variables at the moment you launch your MCP host. A small wrapper script that reads from the keyring and execs the host process is enough.
  2. A .env file outside any synced folder. Keep the six values in a plain .env file at a path that is not inside OneDrive, Dropbox, Drive, or similar, with file permissions restricted to your user. Load it via your MCP host's env-file support, or source it from your shell before launching the host.
  3. Inline in the MCP host's JSON config. This is the simplest pattern and is what the MCP host config example below shows. It is acceptable only if the host config file lives on a local-only path with user-only permissions, and you understand that any backup tool, sync client, or screen-share pointed at that file will carry the secrets along with it.

A note on --login --save

The --login --save flow described in step 6 of One-time setup writes the refresh token to a per-user file at mode 0600 in your local app-data directory. This is meaningfully safer for the refresh token specifically than putting it into the MCP host's JSON config, because the file lives outside the host config's backup or sync surface and is readable only by your user account.

If you take this path, omit GOOGLE_ADS_REFRESH_TOKEN from the host config env block entirely. The server falls back to the saved file. The other five credentials still need to be provided as environment variables by one of the methods above.

If a credential leaks

Act quickly and in this order:

  • Refresh token. Open https://myaccount.google.com/permissions, find your OAuth client (it appears under the app name you set on the consent screen), and click Remove Access. The next API call using the leaked token returns invalid_grant. Then re-mint a new refresh token with --login.
  • OAuth client secret. In the Google Cloud Console: APIs & Services → Credentials → your Desktop OAuth client → Reset secret. The old secret stops working immediately. Update your config and re-mint the refresh token, because resetting the secret invalidates existing refresh tokens issued under that client.
  • OAuth client ID. Treat the secret as also compromised. Delete the OAuth client, create a new one, update GOOGLE_ADS_CLIENT_ID and GOOGLE_ADS_CLIENT_SECRET, and re-mint the refresh token.
  • Developer token. Developer tokens are issued by Google to your MCC and are not user-rotatable. If you believe the token has been leaked, contact Google Ads API support via your MCC's API Center page and request rotation. While you wait, reduce blast radius by lowering daily budgets on the affected operating customer accounts and by un-linking the operating account from the MCC if practical.
  • Customer IDs. These are not secret on their own and are visible to anyone with access to the MCC or the sub-account. But if they leak together with the developer token and OAuth credentials, treat the whole bundle as compromised and rotate everything above.

Principle of least privilege

GOOGLE_ADS_CUSTOMER_ID scopes the MCP to a single operating customer account. Any tool call that passes a different customer_id is rejected at the client factory before reaching the API. Use this. Scope each MCP instance to the one operating account you accept it could spend against, and run a separate instance with a separate env block if you need to manage a second account. The scoping check is a backstop, not a substitute for choosing the target account deliberately.

MCP host config

Add to your MCP client's mcpServers block. The example below shows the six credentials as literal strings in JSON for clarity. Before pasting real values, read Security and credential handling above for what these credentials let an attacker do and for safer alternatives to inline secrets.

{
  "mcpServers": {
    "google-ads": {
      "command": "npx",
      "args": ["-y", "google-ads-full-readwrite-mcp"],
      "env": {
        "GOOGLE_ADS_DEVELOPER_TOKEN": "...",
        "GOOGLE_ADS_CLIENT_ID": "...",
        "GOOGLE_ADS_CLIENT_SECRET": "...",
        "GOOGLE_ADS_REFRESH_TOKEN": "...",
        "GOOGLE_ADS_LOGIN_CUSTOMER_ID": "1234567890",
        "GOOGLE_ADS_CUSTOMER_ID": "1234567890"
      }
    }
  }
}

Tools

Reporting

  • list_accessible_customers — customer IDs the OAuth principal can access
  • get_account_summary — name, currency, time zone, campaign/ad-group counts
  • search — arbitrary GAQL query
  • get_resource_fields — fields available on a GAQL resource
  • get_performance — convenience wrapper for typical reports

Campaigns

  • list_campaigns
  • create_search_campaign
  • create_performance_max_campaign
  • update_campaign
  • pause_campaign / enable_campaign / remove_campaign

Ad groups

  • list_ad_groups
  • create_ad_group
  • update_ad_group
  • pause_ad_group / enable_ad_group / remove_ad_group

Ads

  • list_ads
  • create_responsive_search_ad
  • update_responsive_search_ad (read-then-replace; the API replaces, not patches)
  • pause_ad / enable_ad / remove_ad

Assets and Performance Max asset groups

  • create_text_asset
  • create_image_asset (data or URL)
  • create_sitelink_asset
  • create_callout_asset
  • create_structured_snippet_asset
  • create_video_asset
  • create_asset_group
  • attach_assets_to_asset_group
  • attach_assets_to_campaign
  • list_assets

Budgets and bidding

  • create_budget / update_budget / list_budgets
  • create_bidding_strategy / update_bidding_strategy / list_bidding_strategies

Keywords

  • add_keywords
  • add_negative_keywords (AD_GROUP / CAMPAIGN / ACCOUNT scope)
  • update_keyword
  • remove_keyword
  • list_keywords

Recommendations

  • list_recommendations
  • apply_recommendation (requires confirm:true)
  • dismiss_recommendation

Conversion actions

  • list_conversion_actions (read-only in v0.1)

Safety

This MCP can spend money. Four guardrails are on by default:

  1. Default-paused. Every create_*_campaign, create_ad_group, and create_*_ad creates entities in PAUSED status. The LLM has to explicitly call enable_* to start spend.
  2. Confirmation for destructive operations. remove_campaign, remove_ad_group, remove_ad, remove_keyword, and apply_recommendation require an explicit confirm: true in the input. Without it the handler returns a "confirmation required" response describing the planned action.
  3. Budget ceiling. create_budget and update_budget reject amounts outside [1,000,000 micros, GOOGLE_ADS_MCP_MAX_BUDGET_MICROS].
  4. Customer-ID scoping. If GOOGLE_ADS_CUSTOMER_ID is set, tool calls that pass a different customer_id are rejected at the client factory. This prevents a prompt-injection from redirecting writes to the wrong account.

A GOOGLE_ADS_MCP_DRY_RUN=true env var makes every mutating tool log what it would submit and return synthetic success without calling the API. Use it the first week.

Troubleshooting

12 UNIMPLEMENTED: GRPC target method can't be resolved.

Google retires Google Ads API versions roughly 14 months after release. If you see this error, the version of google-ads-api that your install pulled in is now targeting a retired Google Ads API release. Bump the dep:

npm install -g google-ads-full-readwrite-mcp@latest

If you install via npx -y (the recommended pattern), clear the npx cache so the next launch pulls the current version of this package:

npx clear-npx-cache

invalid_grant or "auth tokens are no longer valid"

Your refresh token has been revoked. Common causes:

  • 90+ days of inactivity on the refresh token.
  • The Google account password was changed.
  • Consent was revoked from https://myaccount.google.com/permissions.
  • The Google Cloud project's OAuth client was deleted, or its consent screen was returned to Draft.

Fix: re-run --login to mint a new refresh token, and update the value in your MCP host config.

DEVELOPER_TOKEN_NOT_APPROVED / "developer token not approved for the manager"

The developer token cannot be used against the operating customer account. Three common causes:

  • Your developer token is Test access only and you're calling against a production account.
  • The operating customer account is not linked to the MCC that owns the developer token.
  • GOOGLE_ADS_LOGIN_CUSTOMER_ID is set to the wrong MCC.

Confirm in the MCC's Sub-account settings that the operating account appears as Active, and that GOOGLE_ADS_LOGIN_CUSTOMER_ID matches the MCC's ID exactly (no dashes).

"Access blocked: ... has not completed the Google verification process"

You hit Google's consent screen but your Google account is not on the OAuth client's test users list. Go back to APIs & Services → OAuth consent screen (or Audience tab in the newer layout) and add your account under Test users, then retry --login.

MetadataLookupWarning at startup

MetadataLookupWarning: received unexpected error = All promises were rejected code = UNKNOWN

google-auth-library probes the GCE metadata server as a fallback when running outside Google Cloud. The probe fails (because you're not on a GCE VM), the library moves on, and the refresh-token flow proceeds normally. Harmless.

What this does not do

  • YouTube / Display / Demand Gen creative beyond what Performance Max needs
  • Shopping campaigns or Merchant Center management
  • Creation of new conversion actions (read-only in v0.1)
  • Multi-account batch operations across unrelated MCCs in one call
  • A web UI or persistent server mode — the only interface is stdio MCP

Network traffic

The server makes outbound HTTP calls only to Google Ads and Google OAuth endpoints (*.googleapis.com, accounts.google.com, oauth2.googleapis.com). There is no telemetry, error reporting, or update check. A "no-phone-home" test in the test suite asserts this contract.

License

MIT. See LICENSE.