内容
# 谷歌广告 MCP
> 通过 AI 助手安全地管理谷歌广告活动,每次写入操作都经过预览和审计日志。
[](https://github.com/LucasSantana-Dev/google-ads-mcp/actions/workflows/test.yml)
[](https://www.python.org/downloads/)
[](LICENSE)
一个 [模型上下文协议](https://modelcontextprotocol.io) 服务器,暴露谷歌广告 API v24 操作,作为 Claude(或任何 MCP 客户端)的工具。读取活动指标、搜索词和建议;对出价、预算、状态和创意进行受控更改 — 所有操作都从单个对话中完成。
---
## 功能
五个功能层的 31 个工具:
### 只读报告
| 工具 | 功能 |
|------|-------------|
| `list_accessible_customers` | 列出 MCC 下的所有账户 |
| `get_campaigns` | 列出活动状态和频道类型 |
| `get_campaign_performance` | 点击量、展示量、花费、转化率、点击率 |
| `get_ad_groups` | 列出广告组状态 |
| `get_keywords` | 关键词匹配类型和状态 |
| `get_search_terms` | 实际搜索查询和性能指标 |
| `get_change_events` | 账户变更历史 |
| `run_gaql_query` | 执行任何只读 GAQL 查询(最多 10,000 行) |
| `get_segments_metadata` | 可用的 GAQL 分段 |
| `get_metrics_metadata` | 可用的 GAQL 指标 |
| `get_resource_metadata` | 任意 GAQL 资源字段 |
### 建议和规划
| 工具 | 功能 |
|------|-------------|
| `get_recommendations` | 账户或活动的活跃谷歌广告建议 |
| `generate_keyword_ideas` | 从种子关键词或 URL 生成关键词想法 |
| `get_forecast_metrics` | 出价模拟和预测数据 |
| `apply_recommendation` | 应用建议(受控) |
| `dismiss_recommendation` | 驳回建议(受控) |
### 状态写入(受控)
| 工具 | 功能 |
|------|-------------|
| `pause_campaign` / `enable_campaign` | 切换活动状态 |
| `pause_ad_group` / `enable_ad_group` | 切换广告组状态 |
| `pause_keyword` / `enable_keyword` | 切换关键词状态 |
| `pause_ad` / `enable_ad` | 切换广告状态 |
### 出价和预算写入(受控 + 限制)
| 工具 | 功能 |
|------|-------------|
| `update_keyword_bid` | 设置关键词最大每次点击出价 — 默认情况下上限为 ±25% |
| `update_ad_group_bid` | 设置广告组默认每次点击出价 — 限制 |
| `update_campaign_budget` | 设置每日预算 — 默认情况下上限为 ±20% |
### 实体创建(受控)
| 工具 | 功能 |
|------|-------------|
| `create_campaign` | 创建活动 + 共享预算原子操作(开始时暂停) |
| `create_ad_group` | 在活动下创建广告组 |
| `create_keyword` | 向广告组添加关键词 |
| `create_ad` | 创建响应式搜索广告(开始时暂停) |
---
## 安全模型
每次写入操作都经过四个顺序关卡:
```
1. 允许名单 — customer_id 必须在 GOOGLE_ADS_MUTATE_ALLOWLIST 中(默认为拒绝所有)
2. 限制 — 出价/预算更改超过配置的百分比将被直接阻止
3. 预览 — confirm=False(默认为)运行 validate_only;账户中不会发生任何更改
4. 审计 — 确认的突变被追加到仅追加的 JSONL 日志(chmod 0600)
```
新实体(活动、广告组、关键词、广告)始终以 **暂停** 状态开始。
瞬时配额错误(`RESOURCE_TEMPORARILY_EXHAUSTED`)会自动重试,指数退避和抖动(可通过 `GOOGLE_ADS_MAX_RETRIES` 配置,默认为 3)。
---
## 设置
### 先决条件
- Python 3.10+
- [uv](https://docs.astral.sh/uv/getting-started/installation/)
- 谷歌广告开发者令牌和管理账户(MCC)
### 安装
```bash
git clone https://github.com/LucasSantana-Dev/google-ads-mcp
cd google-ads-mcp
uv sync --extra dev
```
### 凭证
```bash
cp .env.example .env
```
| 变量 | 描述 |
|----------|-------------|
| `GOOGLE_ADS_CLIENT_ID` | OAuth 2.0 桌面应用程序客户端 ID |
| `GOOGLE_ADS_CLIENT_SECRET` | OAuth 2.0 桌面应用程序客户端密钥 |
| `GOOGLE_ADS_DEVELOPER_TOKEN` | 谷歌广告开发者令牌 |
| `GOOGLE_ADS_LOGIN_CUSTOMER_ID` | MCC 账户 ID(仅数字,无连字符) |
| `GOOGLE_ADS_REFRESH_TOKEN` | 长寿命 OAuth 刷新令牌(见下文) |
| `GOOGLE_ADS_MUTATE_ALLOWLIST` | 允许写入的客户 ID 逗号分隔列表 |
| `GOOGLE_ADS_AUDIT_LOG` | 审计日志路径(默认为 `audit-log.jsonl`) |
| `GOOGLE_ADS_MAX_BID_CHANGE_PCT` | 最大出价更改分数(默认为 `0.25`) |
| `GOOGLE_ADS_MAX_BUDGET_CHANGE_PCT` | 最大预算更改分数(默认为 `0.20`) |
| `GOOGLE_ADS_MAX_RETRIES` | 配额重试尝试(默认为 `3`) |
#### 生成刷新令牌
```bash
GOOGLE_ADS_CLIENT_ID=... GOOGLE_ADS_CLIENT_SECRET=... \
uv run python scripts/get_refresh_token.py
```
浏览器将打开以进行 OAuth 同意。复制打印的刷新令牌到 `.env`。
---
## Claude 桌面集成
添加到 `~/Library/Application Support/Claude/claude_desktop_config.json`:
```json
{
"mcpServers": {
"google-ads": {
"command": "/Users/<you>/.local/bin/uv",
"args": [
"run",
"--directory", "/path/to/google-ads-mcp",
"--env-file", "/path/to/google-ads-mcp/.env",
"python", "-m", "google_ads_mcp.server"
]
}
}
}
```
重启 Claude 桌面。31 个工具将自动出现。
---
## 示例对话
```
# 报告
"显示账户 123-456-7890 中所有活动,本周花费 > $100"
"哪些搜索词触发了我们的品牌关键词在过去 7 天内?"
" '项目管理软件' 的关键词想法?"
"我的账户有哪些谷歌建议?"
# 写入操作 — 始终先预览;使用 confirm=true 应用
"暂停活动 9876543,它正在消耗预算"
"将广告组 222 中的关键词 111 的每次点击出价设置为 $1.50"
"创建一个新的搜索活动 'Brand Q3',预算为 $20/天"
"应用活动 555 的 '添加关键词' 建议"
```
---
## 开发
```bash
uv run pytest # 102 个测试,89% 覆盖率
uv run ruff check src/ tests/ # lint
uv run mypy src/ # 类型检查
```
每次推送和拉取请求都会运行 CI。
---
## 架构
```
src/google_ads_mcp/
├── server.py # FastMCP 入口点,工具注册
├── config.py # GoogleAdsClient 工厂(读取 .env)
├── gaql.py # GAQL 执行,验证器,行序列化,重试
├── mutate.py # 写入安全防护(允许名单 → 限制 → 预览 → 审计)
├── retry.py # 指数退避处理配额错误
├── errors.py # 工具处理程序包装器 → 任意异常的 {success, error}
├── testing.py # FakeGoogleAdsClient — 无网络或凭证的单元测试
└── tools/
├── accounts.py # list_accessible_customers
├── campaigns.py # get_campaigns, get_campaign_performance
├── adgroups.py # get_ad_groups
├── keywords.py # get_keywords, get_search_terms
├── changes.py # get_change_events
├── query.py # run_gaql_query
├── metadata.py # get_*_metadata(3 个工具)
├── writes_status.py # pause/enable 活动/广告组/关键词/广告(8 个工具)
├── writes_value.py # 更新关键词出价,广告组出价,活动预算(3 个工具)
├── creates.py # 创建活动,广告组,关键词,广告(4 个工具)
└── planning.py # 建议,关键词想法,预测(5 个工具)
```
**传输:** 仅限标准输入输出 — 无 HTTP 端口,无公共暴露。
**身份验证:** OAuth 2.0 桌面应用程序 + 刷新令牌。凭证保留在本地计算机上。
---
## 许可证
MIT