The **Model Context Protocol (MCP)** is an open standard that lets large
language models (LLMs) securely interact with external data and applications.
The **Google Ads MCP server** provides a standardized bridge to the Google Ads API. It lets
AI agents retrieve and analyze account data, create assets, upload videos, and
manage labels by using natural language.

## Community resources and support

- **GitHub repository:** Find demos and examples, report bugs, or suggest
  features in the [google-ads-mcp repository](https://github.com/googleads/google-ads-mcp).

  Use the [Issues tab](https://github.com/googleads/google-ads-mcp/issues) for bug reports and feature requests.
- **Community:** Join the `#ads-api-ai-tools` channel on the [Google
  Advertising Community Discord](https://goo.gle/google-ads-discord).

## Technical overview

Integrating the Google Ads MCP server removes the need to write custom code for
Google Ads API authentication, resource fetching, data parsing, and supported asset or
label mutations. The server exposes callable **tools** and reference
**resources** (see [Core capabilities](https://developers.google.com/google-ads/api/docs/developer-toolkit/mcp-server.md.txt#core-capabilities-tools)) that an LLM
can inspect and invoke.

### Key specifications

- **Protocol:** MCP (Model Context Protocol)
- **Mode:** Read and partial mutate (asset creation, video uploads, and label management with [propose-and-confirm validation](https://developers.google.com/google-ads/api/docs/developer-toolkit/mcp-server.md.txt#propose-and-confirm), or [configurable read-only mode](https://developers.google.com/google-ads/api/docs/developer-toolkit/mcp-server.md.txt#configure-tools))
- **Language:** Python 3.10 or later
- **Transport:** Standard input/output (`stdio`) or Streamable HTTP (`streamable-http` on Cloud Run)
- **Authentication:** Application Default Credentials (OAuth 2.0 user credentials or service account) for local `stdio`, or OAuth 2.0 Web application credentials for remote HTTP

### How the interaction loop works

1. **Request:** You submit a prompt such as *"How is my campaign performance
   this week?"* or *"Create a callout asset for our summer sale"*.
2. **Discovery:** The LLM inspects its available tools and resources and selects a matching `google-ads-mcp` tool.
3. **Execution or dry-run validation:** Read tools query the Google Ads API directly. Mutate tools first run in propose mode (`validate_only=True`) to validate inputs without committing changes (see [Propose-and-confirm safety
   workflow](https://developers.google.com/google-ads/api/docs/developer-toolkit/mcp-server#propose-and-confirm)).
4. **Context injection:** The MCP server returns structured query results, or proposed `change_items` entries and a verification `checksum` digest, to the LLM's context window.
5. **Response and confirmation:** The LLM presents an answer or asks you to confirm the proposed changes. After you approve, the LLM calls the mutate tool again with `validate_only=False` and the matching `checksum` value to commit the change.

## Get started

Follow these steps to configure and run the Google Ads MCP server locally. To deploy
a shared remote service instead, see [Deployment on Google
Cloud](https://developers.google.com/google-ads/api/docs/developer-toolkit/mcp-server#gcp-deployment).

### Prerequisites

Before you configure the server, complete the following prerequisites in your
local environment and the [Google Cloud console](https://developers.google.com/google-ads/api/docs/get-started/introduction.md.txt):

- **Google Cloud project:** Create or select a Google Cloud project with the Google Ads API enabled. Enabling the API grants **Test access** for testing read and mutate workflows against [test accounts](https://developers.google.com/google-ads/api/docs/best-practices/test-accounts.md.txt). To access production accounts, check the [Google Ads API overview page](https://console.cloud.google.com/google/ads-apis/overview) for Explorer, Basic, or Standard access, or [apply for one of these access
  levels](https://developers.google.com/google-ads/api/docs/api-policy/access-levels#access-levels). Otherwise, production calls fail with an `AuthorizationError.CLOUD_PROJECT_NOT_APPROVED_FOR_PRODUCTION` error. Google sunset [developer tokens](https://developers.google.com/google-ads/api/docs/api-policy/developer-token.md.txt) (`GOOGLE_ADS_DEVELOPER_TOKEN`) on September 9, 2026. The Google Cloud project that owns your OAuth client or service account determines your API access level.
- **Credentials:** Local `stdio` mode authenticates with [Application Default
  Credentials (ADC)](https://cloud.google.com/docs/authentication/application-default-credentials) from an OAuth 2.0 client secret JSON file or a service account in your Cloud project. Set the `GOOGLE_CLOUD_PROJECT` environment variable when needed to specify your default quota or ADC project. Remote `streamable-http` deployments instead require an OAuth 2.0 Web application Client ID and Client secret (see [Deploy to Google Cloud
  Run](https://developers.google.com/google-ads/api/docs/developer-toolkit/mcp-server#gcp-deploy)).
- **Local software (for `stdio` mode):** Install [Python 3.10 or
  later](https://www.python.org/downloads/), [`pipx`](https://pipx.pypa.io/), and the [`gcloud` command-line
  tool](https://cloud.google.com/cli) (used to generate user ADC files).

### Configuration

1. Generate [Application Default Credentials (ADC)](https://cloud.google.com/docs/authentication/application-default-credentials) using an OAuth
   client from your API-enabled Google Cloud project and include the Google Ads API
   scope:

   ```bash
   gcloud auth application-default login \
     --scopes=https://www.googleapis.com/auth/adwords,https://www.googleapis.com/auth/cloud-platform \
     --client-id-file=PATH_TO_CLIENT_SECRET_JSON
   ```

   Replace the following:
   - `PATH_TO_CLIENT_SECRET_JSON`: the path to your OAuth 2.0 client secret JSON file.

   This command prints `Credentials saved to file: [PATH_TO_CREDENTIALS_JSON]`
   (such as `~/.config/gcloud/application_default_credentials.json` on Linux
   and macOS). To authenticate with a service account instead, skip this step
   and point `GOOGLE_APPLICATION_CREDENTIALS` to your service account key JSON
   file, or pass `--impersonate-service-account` to `gcloud auth
   application-default login`.
2. Add the server to your host's MCP configuration file (such as
   `~/.gemini/config/mcp_config.json`, `~/.gemini/settings.json`, or
   `~/.claude/settings.json`):

   ```json
   {
     "mcpServers": {
       "google-ads-mcp": {
         "command": "pipx",
         "args": [
           "run",
           "--spec",
           "google-ads-mcp==0.0.6",
           "google-ads-mcp"
         ],
         "env": {
           "GOOGLE_CLOUD_PROJECT": "PROJECT_ID",
           "GOOGLE_APPLICATION_CREDENTIALS": "PATH_TO_CREDENTIALS_JSON"
         }
       }
     }
   }
   ```

   Replace the following:
   - `PROJECT_ID`: your Google Cloud project ID.
   - `PATH_TO_CREDENTIALS_JSON`: the path to the ADC JSON file printed in step 1, or to your service account key JSON file. You can omit `GOOGLE_APPLICATION_CREDENTIALS` when using the default `gcloud` ADC file location.

   To access client accounts through a manager account, set
   `GOOGLE_ADS_LOGIN_CUSTOMER_ID` (10 digits, without hyphens) in `env`, or
   pass the `login_customer_id` parameter on individual tool calls.

> [!TIP]
> **Tip:** For faster startup, install the package once with `pipx install
> google-ads-mcp` and set `"command": "google-ads-mcp"` (with `"args": []`). When a new Google Ads API version such as v26.2 is released, run `pipx upgrade
> google-ads-mcp` (or `pipx run --no-cache`) to update the bundled `google-ads` Python client library to `35.x+`.

### Optional: Equip your agent with skills and the Developer Assistant

The Google Ads MCP server gives your AI client live access to account reporting
data along with asset creation, video upload, and label management tools. Pair
the MCP server with the following companion tools to help your agent construct
valid [Google Ads Query Language (GAQL)](https://developers.google.com/google-ads/api/docs/query/overview.md.txt) queries and diagnose account
performance shifts. These tools also generate client library code, such as
scripts to link created assets to campaigns or perform other unsupported
mutations:

- **Google Ads API agent skills:** Portable workflow modules (including
  `google-ads-api-mcp-setup`, `google-ads-api-account-diagnostics`, and
  `google-ads-api-quickstart`) that help your agent use the Google Ads MCP server
  with lower token overhead. Run the following command to install them
  (requires [Node.js](https://nodejs.org/)), or see the [Google Ads API agent skills
  guide](https://developers.google.com/google-ads/api/docs/developer-toolkit/agent-skills) for Antigravity, Claude Code, Codex, and Cursor setup:

  ```bash
  npx skills add google/skills/skills/ads
  ```
- **Google Ads API Developer Assistant:** A modular plugin for Google Antigravity and
  Claude Code that provides local Protobuf schema inspection, GAQL validation,
  client library code generation, and offline conversion troubleshooting. Read
  [What is the Google Ads API Developer Assistant?](https://developers.google.com/google-ads/api/docs/developer-toolkit/what-is-developer-assistant.md.txt) or follow the
  [installation guide](https://developers.google.com/google-ads/api/docs/developer-toolkit/ai-assistant.md.txt).

## Core capabilities

The following sections describe the server's read tools, partial mutate tools,
and reference resources. Starting in `v0.0.6`, tools register by default with
their category namespace prefix (such as `search_search`). When upgrading
prompts or allowlists from unprefixed releases, update tool names or set an
empty prefix (`""`) in `tools_config.yaml` (see [Configure tool namespaces and
read-only mode](https://developers.google.com/google-ads/api/docs/developer-toolkit/mcp-server#configure-tools)).

### Read tools

- **`customers_list_accessible_customers`** (tool `list_accessible_customers`): Returns the Google Ads customer IDs directly accessible to the authenticated user.
- **`search_search`** (tool `search`): Builds and runs [GAQL](https://developers.google.com/google-ads/api/docs/query/overview.md.txt) `SearchStream` queries from structured parameters (`customer_id`, `resource`, and `fields`, plus optional `conditions`, `orderings`, `limit`, and `login_customer_id`) rather than a raw GAQL string. Every query appends `PARAMETERS omit_unselected_resource_names=true` to fetch resource attributes, metrics, segments, budgets, and status cleanly.
- **`metadata_get_resource_metadata`** (tool `get_resource_metadata`): Retrieves selectable, filterable, and sortable attributes, metrics, and segments for a Google Ads API resource type (for example, `"campaign"`). Use this metadata to discover valid query fields---including metrics and segments added in minor releases such as v26.2---before calling the `search_search` tool.

### Mutate tools (partial support)

- **`assets_create_asset`** (tool `create_asset`): Creates standalone [Google Ads
  assets](https://developers.google.com/google-ads/api/docs/assets/working-with-assets) with dedicated parameters for `TEXT`, `IMAGE`, `YOUTUBE_VIDEO`, `SITELINK`, `CALLOUT`, and `STRUCTURED_SNIPPET` asset types. Pass the `extra_params` dictionary for other mutable `AssetService` types (such as `PRICE`, `PROMOTION`, `CALL`, or `BUSINESS_MESSAGE`), and include root-level `final_urls` alongside `sitelink_link_text` for `SITELINK` assets. Local file paths (`image_asset_path`) work in local `stdio` mode only. For remote HTTP deployments, pass the base64-encoded `image_asset_data` parameter with `image_asset_mime_type` set to `IMAGE_PNG`, `IMAGE_JPEG`, or `IMAGE_GIF` (up to 20 MB).
- **`assets_upload_video_asset`** (tool `upload_video_asset`): [Uploads a
  local video file](https://developers.google.com/google-ads/api/docs/assets/upload-videos) (`.3gp`, `.avi`, `.flv`, `.mkv`, `.mov`, `.mp4`, `.mpeg`, `.mpg`, `.ogg`, `.webm`, or `.wmv`) to YouTube through the Google Ads API in local `stdio` mode only. Both `video_title` and `video_description` are required parameters, and privacy defaults to `UNLISTED` (or `PUBLIC` on advertiser-owned brand channels with user OAuth). This tool returns a Google Ads `video_upload_id` value (and resource name), not the 11-character YouTube `video_id`. Query `you_tube_video_upload` with the `search_search` tool (filtering by `you_tube_video_upload.video_upload_id`) until `you_tube_video_upload.state = 'PROCESSED'`. Then pass `you_tube_video_upload.video_id` as the `youtube_video_id` parameter to `assets_create_asset` (`asset_type="YOUTUBE_VIDEO"`).
- **`labels_manage_labels`** (tool `manage_labels`): Creates, updates, and removes account labels, including name, description, and hex background color.
- **`labels_manage_label_associations`** (tool `manage_label_associations`): Supports `CREATE` and `REMOVE` label association operations (`UPDATE` is not supported) on `CAMPAIGN`, `CUSTOMER`, `AD_GROUP`, and `AD_GROUP_CRITERION` resources. For `CUSTOMER` resources, `resource_id` is optional and defaults to `customer_id`. Pass a composite `{ad_group_id}~{criterion_id}` ID for `AD_GROUP_CRITERION` resources, and remove associations by passing either `resource_id` and `label_id` or `association_resource_name`. Ad-level `AD_GROUP_AD` labels are not supported.

> [!NOTE]
> **Note:** Mutate support covers standalone asset creation, video uploads, and label management only. The server cannot link assets to campaigns, ad groups, or asset groups, or configure ad-level asset automation settings (such as `OVERLAY_TEXT_ON_VIDEOS` in v26.2). It also cannot create, modify, pause, or enable campaigns, ad groups, ads, budgets, or bids. For unsupported mutations, pair the server with companion code-generation tools (see [Equip your agent with
> skills and the Developer Assistant](https://developers.google.com/google-ads/api/docs/developer-toolkit/mcp-server#equip-agent)).

### Reference resources

The server exposes four read-only MCP resources that remain mounted regardless
of your `tools_config.yaml` settings:

- **`resource://discovery-document`:** JSON REST discovery overview of Google Ads API resources, service methods, and schemas. It complements the `metadata_get_resource_metadata` tool, which returns selectable, filterable, and sortable GAQL query fields.
- **`resource://metrics`:** HTML reference documentation for Google Ads API metrics.
- **`resource://segments`:** HTML reference documentation for Google Ads API segments.
- **`resource://release-notes`:** HTML Google Ads API release notes covering version changes and new features.

### Propose-and-confirm safety workflow

Every mutate tool (`assets_create_asset`, `assets_upload_video_asset`,
`labels_manage_labels`, and `labels_manage_label_associations`) enforces a
two-step **propose-and-confirm** workflow to help prevent unintended account
modifications:

1. **Propose (`validate_only=True`, default):** Validates inputs without committing changes. The asset and label tools execute a live Google Ads API `validate_only` dry run. Because `YouTubeVideoUploadService` has no dry-run mode, `assets_upload_video_asset` instead validates the local file and binds its size and modification timestamp. Each tool returns human-readable `change_items` entries and a stateless SHA-256 `checksum` digest bound to the `customer_id` parameter and request payload.
2. **Confirm (`validate_only=False`):** After presenting the `change_items` list and receiving your approval, the agent calls the tool again with `validate_only=False`, the identical `customer_id` parameter and arguments, and the `checksum` value from step 1. The server rejects any missing or mismatched checksum before mutating the account.

> [!NOTE]
> **Note:** The `checksum` value is an unkeyed SHA-256 digest of the request parameters that works statelessly across Cloud Run instances. It prevents accidental parameter drift or local file swaps across turns, but does not replace access control. To hard-block mutations, disable the `labels` and `assets` namespaces in `tools_config.yaml`.

### Configure tool namespaces and read-only mode

The server bundles a default `tools_config.yaml` file with all five tool
categories (`customers`, `search`, `metadata`, `labels`, and `assets`) enabled.
Customize `tools_config.yaml` to selectively enable or disable individual tools
or namespaces, change or remove namespace prefixes, or enforce a **strictly
read-only** deployment.

> [!IMPORTANT]
> **Important:** Whenever `namespaces` is non-empty, **any omitted category is
> disabled by default** , whereas an empty `namespaces: {}` mapping enables all five categories. Include every category that you want to keep enabled---a file containing only `labels: false` and `assets: false` disables the read tools too.

At startup, the server resolves `tools_config.yaml` in the following order:

1. An explicit path in the `GOOGLE_ADS_MCP_TOOLS_CONFIG` environment variable (recommended for local `stdio` hosts, whose working directory can differ from your project folder).
2. A `tools_config.yaml` file in the server's current working directory.
3. The default `tools_config.yaml` file bundled with the package.

If `GOOGLE_ADS_MCP_TOOLS_CONFIG` points to a missing file, or if any resolved
configuration file is invalid, the server raises an error at startup instead of
falling back to defaults.

The following minimal `tools_config.yaml` file enforces a strictly read-only
deployment:

```yaml
namespaces:
  customers: true
  search: true
  metadata: true
  labels: false
  assets: false
```

The following `tools_config.yaml` file customizes prefixes and filters
individual tools (for example, exposing the base64 `create_asset` tool on Cloud
Run while disabling the local-only `upload_video_asset` tool):

```yaml
namespaces:
  # Default prefix ("customers_list_accessible_customers")
  customers: true

  # Empty prefix mounts unprefixed tool names ("search")
  search: ""

  # Custom prefix ("schema_get_resource_metadata")
  metadata: "schema"

  # Enable only specific tools in a multi-tool category
  assets:
    enabled_tools:
      - create_asset
```

## Sample prompts to start

Try the following prompts in your MCP client after connecting the server.

### Ask what the server can do

    What can the google-ads-mcp server do?

### Ask about customers

    What customers do I have access to?

### Ask about campaigns

    How many active campaigns do I have?

    How is my campaign performance this week?

    Give me a report of the top spending campaigns split by device category over the last 7 days for account 1234567890

### Create assets, upload videos, and manage labels

    Create a callout asset with the text "Free Shipping" for account 1234567890

    Upload /path/to/promo.mp4 with title "Summer Sale" and description "Summer promo video" for account 1234567890

    Create a label named "Q4 Promo" with background color #34A853 and apply it to campaign 9876543210 in account 1234567890

> [!NOTE]
> **Note:** Video uploads require local `stdio` mode. Creating a new label and applying it to a campaign runs two sequential propose-and-confirm cycles so the new `label_id` value can be validated in the association request.

## Deployment on Google Cloud

To share the MCP server across multiple agents or run it as a web service, host
it on Google Cloud Run or another cloud infrastructure provider instead of
running it locally.

### Prerequisites

1. A Google Cloud project with the Google Ads API enabled (see [Prerequisites](https://developers.google.com/google-ads/api/docs/developer-toolkit/mcp-server.md.txt#prerequisites) for production access requirements).
2. The [`gcloud` command-line tool](https://cloud.google.com/cli) installed, authenticated, and
   configured with an active project:

   ```bash
   gcloud config set project PROJECT_ID
   ```

   Replace the following:
   - `PROJECT_ID`: your Google Cloud project ID.

### Build and push a Docker image

Use Cloud Build to build and push the container image to Artifact Registry
without installing Docker locally:

1. Create a repository in Artifact Registry:

   ```bash
   gcloud artifacts repositories create mcp-servers \
     --repository-format=docker --location=us-central1
   ```
2. Build and submit the image from a release tag in the GitHub repository (or
   from `.` in a local checkout if you customized `Dockerfile` or
   `tools_config.yaml`):

   ```bash
   gcloud builds submit https://github.com/googleads/google-ads-mcp \
     --git-source-revision=v0.0.6 \
     --tag=us-central1-docker.pkg.dev/PROJECT_ID/mcp-servers/google-ads-mcp:v0.0.6
   ```

   Replace the following:
   - `PROJECT_ID`: your Google Cloud project ID.

   Rebuild and redeploy the image whenever you update `google-ads-mcp` or
   upgrade the bundled `google-ads` Python client library for new Google Ads API
   releases (such as v26.2).

### Deploy to Google Cloud Run

Configure the following environment variables and secrets for your Cloud Run
service:

- `GOOGLE_ADS_MCP_OAUTH_CLIENT_ID`: The OAuth 2.0 **Web application** Client ID from your API-enabled Google Cloud project for application-level OAuth authentication. Complete the following OAuth configuration steps:
  - Add the authorized redirect URIs for any AI clients that you plan to connect (such as `https://claude.ai/api/mcp/auth_callback`, `https://chatgpt.com/connector_platform_oauth_redirect`, or `https://antigravity.google/oauth-callback`).
  - Add the `https://www.googleapis.com/auth/adwords` scope to the OAuth consent screen under **APIs \& Services \> OAuth consent screen \> Data
    Access** (**Add or remove scopes**).
  - If your OAuth consent screen publishing status is set to **Testing** (the default), add the Google Accounts connecting to the MCP server as **Test users** under **APIs \& Services \> OAuth consent screen \>
    Audience** (**Test users \> + Add users**).
- `GOOGLE_ADS_MCP_OAUTH_CLIENT_SECRET`: The OAuth Client secret corresponding to your OAuth Client ID.
- `GOOGLE_ADS_MCP_BASE_URL`: The public base URL of your MCP server (for example, `https://google-ads-mcp-xyz-uc.a.run.app`). Cloud Run assigns this URL during initial deployment, so deploy without this variable first and update the service afterward.
- `GOOGLE_ADS_MCP_JWT_SIGNING_KEY` *(recommended for multi-instance Cloud
  Run)*: A persistent secret that signs FastMCP JWTs across container restarts and horizontal scaling.
- `GOOGLE_ADS_MCP_STORAGE_TYPE` *(recommended for multi-instance Cloud Run)* : Persistent backend for OAuth client registrations and tokens (`redis` with `GOOGLE_ADS_MCP_STORAGE_REDIS_URL`, or `firestore`). Because the stock `v0.0.6` `Dockerfile` installs only the in-memory backend, install `py-key-value-aio[redis]` or `.[firestore]` in a custom `Dockerfile` first. Using `firestore` also requires a Firestore database and the `roles/datastore.user` IAM role on the Cloud Run service account. For single-instance testing with in-memory storage, pass `--max-instances=1`.
- `GOOGLE_ADS_LOGIN_CUSTOMER_ID` *(optional)* : Default 10-digit manager customer ID (without hyphens) used when tool calls omit the `login_customer_id` parameter.
- `GOOGLE_ADS_MCP_TOOLS_CONFIG` *(optional)* : Container path to a custom `tools_config.yaml` file (for example, mounted from Secret Manager at `/etc/mcp/tools_config.yaml` to enforce read-only mode without rebuilding the image). See [Configure tool namespaces and read-only
  mode](https://developers.google.com/google-ads/api/docs/developer-toolkit/mcp-server#configure-tools).

Store `GOOGLE_ADS_MCP_OAUTH_CLIENT_SECRET` and `GOOGLE_ADS_MCP_JWT_SIGNING_KEY`
in Secret Manager and deploy the service to Google Cloud Run:

```bash
gcloud run deploy google-ads-mcp \
  --image=us-central1-docker.pkg.dev/PROJECT_ID/mcp-servers/google-ads-mcp:v0.0.6 \
  --platform=managed \
  --region=us-central1 \
  --allow-unauthenticated \
  --set-env-vars="GOOGLE_ADS_MCP_OAUTH_CLIENT_ID=CLIENT_ID" \
  --set-secrets="GOOGLE_ADS_MCP_OAUTH_CLIENT_SECRET=MCP_OAUTH_CLIENT_SECRET:latest,GOOGLE_ADS_MCP_JWT_SIGNING_KEY=MCP_JWT_SIGNING_KEY:latest"
```

After Cloud Run completes the deployment, retrieve the assigned service URL and
update the service with the `GOOGLE_ADS_MCP_BASE_URL` environment variable:

```bash
gcloud run services update google-ads-mcp \
  --region=us-central1 \
  --update-env-vars="GOOGLE_ADS_MCP_BASE_URL=https://CLOUD_RUN_SERVICE_URL"
```

Replace the following:

- `PROJECT_ID`: your Google Cloud project ID.
- `CLIENT_ID`: your OAuth 2.0 Web application Client ID.
- `MCP_OAUTH_CLIENT_SECRET`: the Secret Manager secret name storing your OAuth 2.0 Client secret.
- `MCP_JWT_SIGNING_KEY`: the Secret Manager secret name storing your JWT signing key.
- `CLOUD_RUN_SERVICE_URL`: the hostname assigned to your Cloud Run service (for example, `google-ads-mcp-xyz-uc.a.run.app`).

#### Authentication and security model

Deploying with `--allow-unauthenticated` disables Cloud Run's infrastructure IAM
check (`roles/run.invoker`) so external AI clients can connect without Google
Cloud service account tokens. Authentication is delegated to the **application
layer** instead:

- When `GOOGLE_ADS_MCP_OAUTH_CLIENT_ID` and `GOOGLE_ADS_MCP_OAUTH_CLIENT_SECRET` are set, the server enforces Google OAuth 2.0 on every request and returns a `401 Unauthorized` HTTP status code to unauthenticated callers. Every tool call executes under the authenticated caller's OAuth identity.
- Omitting `--allow-unauthenticated` requires callers to pass Google Cloud OIDC identity tokens with every request. Standard AI clients (such as Claude and ChatGPT) use end-user OAuth rather than Google Cloud IAM tokens, so direct connections require `--allow-unauthenticated` paired with application-level OAuth.

> [!CAUTION]
> **Caution:** **Never** omit `GOOGLE_ADS_MCP_OAUTH_CLIENT_ID` and `GOOGLE_ADS_MCP_OAUTH_CLIENT_SECRET` when deploying with `--allow-unauthenticated`. Those environment variables switch the server from local `stdio` mode to `streamable-http` transport. Without them, the server falls back to Application Default Credentials (ADC) and exposes the container's service account credentials to unauthenticated callers.

### Configure the MCP client

After deployment, configure your MCP client with the Cloud Run service URL.
Because the server enforces OAuth 2.0, your client must support the MCP OAuth
flow or supply an authorized Bearer token:

- **OAuth-enabled clients:** In clients that support MCP OAuth discovery (such as Antigravity), connecting triggers a Google sign-in prompt to grant the `https://www.googleapis.com/auth/adwords` scope (shown as `.../auth/adwords` in the Google Cloud console).
- **Third-party AI platforms (Claude, ChatGPT):** In your client's connector settings, add a custom connector pointing to your service URL with the `/mcp` path (for example, `https://google-ads-mcp-xyz-uc.a.run.app/mcp`). Select OAuth 2.0 authentication with your OAuth Client ID and Client secret, and confirm that the client's callback URI is in your OAuth client's authorized redirect URIs.
- **Clients without OAuth support:** Clients that don't support HTTP OAuth flows receive a `401 Unauthorized` HTTP status code. For those clients, use the [local stdio configuration](https://developers.google.com/google-ads/api/docs/developer-toolkit/mcp-server.md.txt#configuration) instead.

The following example configures the `gemini` command-line tool in
`~/.gemini/settings.json` (for Google Antigravity in
`~/.gemini/config/mcp_config.json`, replace `"httpUrl"` with `"serverUrl"` or
`"url"`):

```json
{
  "mcpServers": {
    "google-ads-mcp": {
      "httpUrl": "https://CLOUD_RUN_SERVICE_URL/mcp"
    }
  }
}
```

Replace the following:

- `CLOUD_RUN_SERVICE_URL`: the hostname assigned to your Cloud Run service (for example, `google-ads-mcp-xyz-uc.a.run.app`).

## Next steps

- [Install Google Ads API agent skills](https://developers.google.com/google-ads/api/docs/developer-toolkit/agent-skills.md.txt)
- [Learn about the Google Ads API Developer Assistant](https://developers.google.com/google-ads/api/docs/developer-toolkit/what-is-developer-assistant.md.txt)
- [Install and use the Google Ads API Developer Assistant](https://developers.google.com/google-ads/api/docs/developer-toolkit/ai-assistant.md.txt)