谷歌广告API集成服务器

一个用于Google Ads API集成的Model Context Protocol(MCP)服务器,允许AI助手通过标准化的MCP工具与Google广告数据进行交互。

  • by ameydabhade
  • TypeScript
  • 本地部署
  • 1 星标
  • 更新于
在 GitHub 查看 ameydabhade/google-ads-mcp

使用说明

MCP Google Ads Server

A Model Context Protocol (MCP) server for Google Ads API integration. This server allows AI assistants like Claude to interact with Google Ads data through standardized MCP tools.

Features

  • Campaign Management: Retrieve campaigns with performance metrics
  • Ad Groups & Keywords: Fetch ad groups, keywords, and search terms
  • Performance Analytics: Geographic, demographic, and time-based performance data
  • Account Management: List accounts, get customer details
  • Asset Management: Access ads, creatives, and assets
  • Write Operations: Create and update budgets, campaigns, ad groups, keywords and ads — opt-in, with dry-run and spend caps
  • Dual Transport: Supports both HTTP and stdio modes

Quick Start

# Clone the repository
git clone https://github.com/ameydabhade/google-ads-mcp.git
cd google-ads-mcp

# Install dependencies
npm install

# Configure credentials
cp .env.example .env
# Edit .env with your Google Ads API credentials

# Build and start
npm run build
npm run start:server

Prerequisites

Before using this MCP server, you need:

  1. Google Cloud Project with Google Ads API enabled
  2. OAuth 2.0 Credentials (Client ID and Secret)
  3. Google Ads Developer Token (Test or Production)
  4. Google Ads Account to query

Setup Guide

Step 1: Create Google Cloud Project

  1. Go to Google Cloud Console
  2. Create a new project or select an existing one
  3. Enable the Google Ads API:
    • Navigate to "APIs & Services" > "Library"
    • Search for "Google Ads API"
    • Click "Enable"

Step 2: Create OAuth 2.0 Credentials

  1. Go to "APIs & Services" > "Credentials"
  2. Click "Create Credentials" > "OAuth 2.0 Client IDs"
  3. Select "Web application" as the application type
  4. Under "Authorized redirect URIs", add http://localhost:8085 (this is where the helper script in Step 4 receives the authorization code)
  5. Note your Client ID and Client Secret

Step 3: Get Developer Token

  1. Sign in to Google Ads
  2. Go to "Tools & Settings" > "API Center"
  3. If you don't have a developer token, apply for one
  4. For testing, use the "Test Account" developer token
  5. For production, apply for Basic or Standard access

Step 4: Generate Refresh Token

A developer token on its own is not enough to call the Google Ads API — every request also needs an OAuth token, even for a single-user setup. This is a one-time step: you generate one refresh token, put it in .env, and reuse it indefinitely.

Put your client ID and secret in .env first, then run:

npm run oauth:generate

The script opens your browser, captures the authorization code on http://localhost:8085, exchanges it, and prints the refresh token to paste into .env. If port 8085 is taken, set OAUTH_HELPER_PORT to a free port (and add the matching redirect URI in the Google Cloud console).

Doing it manually
  1. Build an authorization URL (the redirect URI must match one registered on your OAuth client):
https://accounts.google.com/o/oauth2/v2/auth?client_id=YOUR_CLIENT_ID&redirect_uri=http://localhost:8085&scope=https://www.googleapis.com/auth/adwords&response_type=code&access_type=offline&prompt=consent
  1. Visit it and authorize access
  2. Copy the code query parameter off the URL you land on
  3. Exchange it for tokens:
curl -X POST https://oauth2.googleapis.com/token \
  -d "code=YOUR_AUTH_CODE" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "redirect_uri=http://localhost:8085" \
  -d "grant_type=authorization_code"
  1. Save the refresh_token from the response

access_type=offline and prompt=consent are both required — without them Google returns an access token but no refresh token. Note that the older out-of-band flow (urn:ietf:wg:oauth:2.0:oob) was discontinued in 2022 and no longer works.

Step 5: Configure Environment

cp .env.example .env

Edit .env with your credentials:

GOOGLE_ADS_CLIENT_ID=your_client_id.apps.googleusercontent.com
GOOGLE_ADS_CLIENT_SECRET=your_client_secret
GOOGLE_ADS_DEVELOPER_TOKEN=your_developer_token
GOOGLE_ADS_REFRESH_TOKEN=your_refresh_token
GOOGLE_ADS_CUSTOMER_ID=1234567890

Installation

# Install dependencies
npm install

# Build the project
npm run build

# Start the server (HTTP mode)
npm run start:server

# Or run in development mode
npm run dev:server

Usage

HTTP Server Mode

The server exposes an HTTP endpoint at http://localhost:3000/mcp that accepts JSON-RPC requests.

# Start the server
npm run start:server

# Test with curl
curl -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tools/list",
    "id": 1
  }'

Stdio Mode (Claude Desktop)

For use with Claude Desktop, add to your config:

{
  "mcpServers": {
    "google-ads": {
      "command": "node",
      "args": ["/path/to/mcp-google-ads/dist/index.js"],
      "env": {
        "GOOGLE_ADS_CLIENT_ID": "your_client_id",
        "GOOGLE_ADS_CLIENT_SECRET": "your_client_secret",
        "GOOGLE_ADS_DEVELOPER_TOKEN": "your_developer_token",
        "GOOGLE_ADS_REFRESH_TOKEN": "your_refresh_token",
        "GOOGLE_ADS_CUSTOMER_ID": "1234567890",
        "GOOGLE_ADS_ENABLE_WRITES": "false"
      }
    }
  }
}

Set GOOGLE_ADS_ENABLE_WRITES to "true" to expose the write tools — see Write Operations.

Available Tools

Read Tools

Tool Description
get_accounts List all accessible Google Ads accounts
get_campaigns Get campaigns with performance metrics
get_ad_groups Get ad groups with metrics
get_keywords Get keywords with quality scores
get_search_terms Get search queries that triggered ads, with the matching keyword and its criterion ID
get_auction_insights Competitor domains in the same auctions (impression share, overlap, outranking)
get_geographic_performance Performance by location
get_audience_demographics Age and gender performance
get_ad_schedule_performance Performance by day/hour
get_account_summary Overall account metrics
get_customer_details Account configuration
get_campaign_details Single campaign config
get_ad_group_details Single ad group config
get_ad_details Ad creative details
get_asset_by_id Asset (image/video) details
get_user_list_details Audience list details
get_conversion_action_details Conversion tracking config
get_constants Reference data (geo, language, etc.)
healthcheck Test API connectivity

Write Tools

These change live campaigns and spend real money. They are disabled by default — see Write Operations.

Tool Description
create_campaign_budget Create a campaign budget
update_campaign_budget Change a budget's amount, name or delivery method
create_campaign Create a campaign against an existing budget
update_campaign Change name, status, dates, budget or bidding targets
remove_campaigns Permanently remove campaigns
create_ad_group Create an ad group in a campaign
update_ad_group Change name, status or default CPC bid
remove_ad_groups Permanently remove ad groups
add_keywords Add positive keywords to an ad group
update_keywords Change keyword status or bids
remove_keywords Permanently remove keywords
add_negative_keywords Add negative keywords at campaign or ad group level
create_responsive_search_ad Create a responsive search ad
update_ad_status Enable, pause or remove ads

Auction Insights

get_auction_insights returns the same competitor view as the Auction Insights report in the Google Ads UI, via segments.auction_insight_domain.

{
  "name": "get_auction_insights",
  "arguments": {
    "date_range": { "start_date": "2026-01-01", "end_date": "2026-01-31" },
    "level": "campaign",
    "sort_by": "impression_share"
  }
}

Rows are grouped by competitor domain, averaging each metric across the campaigns (or ad groups) the domain appeared in; appears_in keeps the per-campaign breakdown. Metrics come back as 0-1 fractions, with the same figures as percentages under metrics_percent.

Metric Meaning
impression_share Share of available impressions that competitor won
overlap_rate How often they appeared when you also appeared
position_above_rate How often they ranked above you when both appeared
outranking_share How often you ranked above them, or showed when they didn't
top_of_page_rate How often their ad appeared above the organic results
absolute_top_of_page_rate How often their ad was the very first ad

Constraints worth knowing: Auction Insights covers Search and Shopping campaigns only, and your own account shows up as one of the domains. Google restricts which segments can be combined with auction_insight_domain, so this tool deliberately does not segment by date.

Finding and excluding wasted spend

get_search_terms reports the keyword that matched each search term, which pairs with the write tools:

  1. get_search_terms — find terms with cost and no conversions. Each term carries a keywords array with keyword_text, match_type and criterion_id, ranked by impressions.
  2. add_negative_keywords — exclude the bad terms, campaign- or ad-group-wide.
  3. update_keywords — or pause the matching keyword outright using the criterion_id from step 1.

Because the query is segmented by keyword, a single search term can be matched by several keywords; all of them appear in keywords, while the scalar keyword_text / match_type fields resolve to whichever drove the most impressions.

Write Operations

Writes are opt-in. With GOOGLE_ADS_ENABLE_WRITES unset or false the write tools are not advertised in tools/list at all, and calling one returns a WRITE_DISABLED error.

# Required to expose the write tools
GOOGLE_ADS_ENABLE_WRITES=true

# Optional: make every write a dry run unless dry_run=false is passed
GOOGLE_ADS_WRITE_DRY_RUN_DEFAULT=false

# Optional spend ceilings in micros (1 unit = 1,000,000 micros)
GOOGLE_ADS_MAX_BUDGET_MICROS=100000000
GOOGLE_ADS_MAX_BID_MICROS=10000000

Toggling GOOGLE_ADS_ENABLE_WRITES takes effect on the next client reconnect, since MCP clients cache the tool list.

Safety model

  • Off by default. Nothing can be mutated until you opt in.
  • Dry run. Every write tool accepts dry_run: true, which maps to the Google Ads API's validate_only flag: the change is validated server-side but not applied. Dry runs return no resource names — that is the API's behaviour, not an error.
  • Atomic batches. partial_failure is always false, so a batch either applies cleanly or fails entirely. You never get half a change.
  • Paused by default. create_campaign, create_ad_group and create_responsive_search_ad create PAUSED entities unless you explicitly ask for ENABLED, so nothing starts serving as a side effect.
  • Spend caps. GOOGLE_ADS_MAX_BUDGET_MICROS / GOOGLE_ADS_MAX_BID_MICROS reject over-limit budgets and bids locally, before the API call.
  • Tool annotations. Write tools carry readOnlyHint: false; the irreversible ones (remove_*, update_ad_status) carry destructiveHint: true so clients can prompt for confirmation.

Amounts

Monetary fields accept either micros or currency units — pass one, not both:

{ "amount_micros": 50000000 }
{ "amount": 50.00 }

Examples

Pause a campaign:

{
  "method": "tools/call",
  "params": {
    "name": "update_campaign",
    "arguments": { "campaign_id": "123456789", "status": "PAUSED" }
  }
}

Validate a budget increase without applying it:

{
  "method": "tools/call",
  "params": {
    "name": "update_campaign_budget",
    "arguments": { "budget_id": "987654321", "amount": 75.00, "dry_run": true }
  }
}

Build a paused search campaign end to end:

{ "name": "create_campaign_budget", "arguments": { "name": "Q1 Budget", "amount": 50.00 } }
{ "name": "create_campaign", "arguments": { "name": "Q1 Search", "budget_id": "<from above>",
    "bidding_strategy": { "type": "TARGET_CPA", "target_cpa": 25.00 } } }
{ "name": "create_ad_group", "arguments": { "campaign_id": "<from above>", "name": "Shoes", "cpc_bid": 1.50 } }
{ "name": "add_keywords", "arguments": { "ad_group_id": "<from above>",
    "keywords": [{ "text": "running shoes", "match_type": "PHRASE" }] } }
{ "name": "create_responsive_search_ad", "arguments": { "ad_group_id": "<from above>",
    "final_urls": ["https://example.com"],
    "headlines": ["Running Shoes", "Free Shipping", "Shop Today"],
    "descriptions": ["Top brands at great prices.", "Free returns within 30 days."] } }

Add negative keywords across a whole campaign:

{
  "name": "add_negative_keywords",
  "arguments": {
    "campaign_id": "123456789",
    "keywords": [{ "text": "free", "match_type": "BROAD" }]
  }
}

Write response format

{
  "operation": "update_campaign",
  "dry_run": false,
  "customer_id": "1234567890",
  "requested_count": 1,
  "applied_count": 1,
  "results": [
    { "resource_name": "customers/1234567890/campaigns/123456789", "id": "123456789" }
  ],
  "metadata": { "timestamp": "2026-01-15T10:30:00.000Z" }
}

Tool Input Format

All tools accept credentials in this format:

{
  "user_credentials": {
    "refresh_token": "your_refresh_token",
    "customer_id": "1234567890"
  },
  "date_range": {
    "start_date": "2024-01-01",
    "end_date": "2024-01-31"
  }
}

If you've set GOOGLE_ADS_REFRESH_TOKEN and GOOGLE_ADS_CUSTOMER_ID in your environment, you can omit those fields.

Example Queries

Get all campaigns for last 30 days

{
  "method": "tools/call",
  "params": {
    "name": "get_campaigns",
    "arguments": {
      "date_range": {
        "start_date": "2024-12-01",
        "end_date": "2024-12-31"
      }
    }
  }
}

Get search terms with pagination

{
  "method": "tools/call",
  "params": {
    "name": "get_search_terms",
    "arguments": {
      "date_range": {
        "start_date": "2024-12-01",
        "end_date": "2024-12-31"
      },
      "paging": {
        "limit": 100,
        "offset": 0
      }
    }
  }
}

Docker Support

# Build the image
docker build -t mcp-google-ads .

# Run with environment variables
docker run -p 3000:3000 \
  -e GOOGLE_ADS_CLIENT_ID=your_client_id \
  -e GOOGLE_ADS_CLIENT_SECRET=your_client_secret \
  -e GOOGLE_ADS_DEVELOPER_TOKEN=your_developer_token \
  -e GOOGLE_ADS_REFRESH_TOKEN=your_refresh_token \
  mcp-google-ads

Development

# Run in development mode with hot reload
npm run dev:server

# Run tests
npm test

# Lint and format
npm run lint

Troubleshooting

"Invalid Customer ID"

  • Ensure the customer ID is 10 digits with no dashes
  • Verify you have access to the account

"Permission Denied"

  • Check that the OAuth user has access to the Google Ads account
  • Ensure the developer token is approved for the account level

"Authentication Failed"

  • Regenerate your refresh token
  • Verify client ID and secret are correct

"Developer Token Not Approved"

  • For production, apply for Basic or Standard access
  • Test accounts don't count against quotas

"Write operations are disabled" / write tools missing

  • Set GOOGLE_ADS_ENABLE_WRITES=true in the server's environment
  • Restart the server and reconnect the MCP client — clients cache tools/list

A dry run returned no resource names

  • Expected. validate_only requests are not applied, so the API returns no resource names and applied_count is 0. Re-run with dry_run: false to apply.

"exceeds the configured GOOGLE_ADS_MAX_BUDGET_MICROS cap"

  • The requested budget or bid is above your local ceiling. Raise or unset GOOGLE_ADS_MAX_BUDGET_MICROS / GOOGLE_ADS_MAX_BID_MICROS.
  • Remember these are micros: 100 units/day is 100000000.

API Rate Limits

Google Ads API has rate limits:

  • 10,000 requests per day (Basic)
  • 15,000 requests per day (Standard)

The server includes automatic retry logic for transient errors.

Related Projects

License

MIT

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

Support

  • Open an issue for bug reports or feature requests
  • Star the repo if you find it useful!