内容
# google-ads-mcp
用于管理谷歌广告账户的MCP服务器。通过GAQL读取,通过两阶段预览/应用写入,全面覆盖v24 API,包含约19种工具。
> 状态:alpha(v0.0.1)。在真实账户上进行端到端使用需要您的开发令牌具有基本访问权限(从谷歌需要1-3个工作日)。
## 功能
- **GAQL读取**,带有行和字节限制,保持响应对LLM友好。
- **两阶段写入**。每个突变首先运行`validate_only=true`,返回每个操作的差异和15分钟的`mutate_id`。`apply(mutate_id)`提交;重新应用是无操作的。
- **客户ID允许列表**。服务器拒绝凭证无法访问的账户。允许列表从`ListAccessibleCustomers`和您管理器下的子账户构建。
- **仅追加审计日志**。`~/.local/share/google-ads-mcp/audit.log`(模式`0600`)。每个状态更改尝试的一行,包括失败和幂等重放。
- **第1层结果工具**,用于常见工作流程:暂停/启用广告活动、广告组、关键词;设置关键词出价;设置广告活动预算;添加否定关键词;应用谷歌的建议;生成关键词想法。
- **第2层通用调度器**,涵盖整个v24表面。`mutate`涵盖所有64种符合统一`MutateOperation` proto的服务。`call_read_rpc`和`call_mutate_rpc`涵盖长尾RPC(推荐取消、实验生命周期、转换上传、受众洞察、MCC管理、链接服务等)。
- **异步作业生命周期**。`batch_job`和`offline_user_data_job`通过单个调度器工具涵盖BatchJob和Customer Match / Store Sales生命周期。
- **通过MCP资源发现** — `gads-schema://`、`gads-rpc-catalog://`、`gads-rpc-schema://`。按需加载,无环境成本。
- **MCP工具注释** — 每个工具声明`readOnlyHint`、`destructiveHint`、`idempotentHint`,以便客户端正确渲染确认。
- **本地OAuth**。凭证存储在`~/.config/google-ads-mcp/credentials.yaml`(模式`0600`)。无SaaS,无按席位计费。
## 先决条件
在安装服务器之前设置这些。它们是谷歌的流程,不是我们的,所以我们无法自动化它们。
1. **Python 3.13** 和 [**uv**](https://docs.astral.sh/uv/getting-started/installation/).
2. **谷歌云项目**,启用 [谷歌广告API](https://console.cloud.google.com/apis/library/googleads.googleapis.com) 并配置 OAuth 2.0 "桌面应用程序" 客户端。下载客户端 JSON — 您将在设置期间指向它。云控制台大约需要 5 分钟。
3. **开发者令牌**,来自 [谷歌广告API中心](https://ads.google.com/aw/apicenter)。基本访问权限审批需要 1-3 个工作日。仅限测试的令牌可立即在 [谷歌广告测试账户](https://developers.google.com/google-ads/api/docs/best-practices/test-accounts) 上使用 — 推荐用于开发。
4. *(可选)* **管理器(MCC)账户ID**,如果您的开发令牌属于管理器,并且您要对其子账户进行操作。
## 安装
PyPI 发布正在规划中,但尚未完成 — 从源代码安装:
```sh
git clone https://github.com/ball2jh/google-ads-mcp.git
cd google-ads-mcp
uv sync
```
## 设置
### 1. 运行交互式向导
```sh
uv run google-ads-mcp init
```
`init` 将提示:
- 您的 OAuth 客户端 JSON 的路径
- 您的开发者令牌
- 您的管理器(MCC)ID(如果适用;自动去除破折号)
- 您浏览器中的 OAuth 同意 — 它会在一个空闲端口上打开一个本地主机循环访问流,并捕获生成的刷新令牌
凭证保存在 `~/.config/google-ads-mcp/credentials.yaml`(模式 `0600`)。
### 2. 验证
```sh
uv run google-ads-mcp validate
```
这会重新运行凭证检查,而无需重新进行 OAuth。如果验证失败(例如,您的云项目尚未启用 Google Ads API),请修复上游问题并再次运行 `validate` — **不要重新运行 `init`**,因为这会烧掉另一个 OAuth 刷新令牌。
## 将其连接到您的MCP客户端
将下面的 `/path/to/google-ads-mcp` 替换为您克隆此存储库的绝对路径。
### Claude 代码
```sh
claude mcp add google-ads -- uv run --directory /path/to/google-ads-mcp google-ads-mcp
```
### Codex
添加到 `~/.codex/config.toml`:
```toml
[mcp_servers.google-ads]
command = "uv"
args = ["run", "--directory", "/path/to/google-ads-mcp", "google-ads-mcp"]
```
### 其他MCP客户端
服务器通过stdio运行。将您的客户端指向相同的 `uv run --directory /path/to/google-ads-mcp google-ads-mcp` 调用,其配置格式由客户端期望决定。
## 工具表面
| 工具 | 层 | 描述 |
|---|---|---|
| `gaql(customer_id, query)` | 2 | 运行任何GAQL `SELECT`。限制响应大小以保持对LLM友好。 |
| `mutate(customer_id, operations)` | 2 | 通过 `GoogleAdsService.Mutate` 进行通用写入(64种服务)。返回可预览的 `mutate_id`。 |
| `call_read_rpc(customer_id, service, method, params)` | 2 | 用于长尾的通用读取RPC — 关键词想法、到达率预测、受众洞察、基准、建议、发票列表等。 |
| `call_mutate_rpc(customer_id, service, method, params)` | 2 | 通用变异RPC — 推荐应用/取消、实验生命周期、MCC管理、转换上传等。 |
| `apply(mutate_id)` | 2 | 提交预览的变异(操作或RPC)。幂等。 |
| `pause_campaign` / `enable_campaign(customer_id, campaign_id)` | 1 | 预览暂停/启用广告活动。 |
| `pause_ad_group` / `enable_ad_group(customer_id, ad_group_id)` | 1 | 在广告活动级别以下精细暂停/启用。 |
| `pause_keyword` / `enable_keyword(customer_id, criterion_resource_name)` | 1 | 暂停/启用单个广告组条件。 |
| `set_keyword_bid(customer_id, criterion_resource_name, cpc_usd)` | 1 | 更新关键词的最大CPC。内部将美元转换为微元。 |
| `set_campaign_budget(customer_id, budget_id, daily_amount_usd)` | 1 | 预览每日预算更改。内部将美元转换为微元。 |
| `add_negative_keyword(customer_id, scope, ref_id, text, match_type)` | 1 | 预览添加广告活动或广告组级别的否定关键词。 |
| `apply_recommendation(customer_id, recommendation_resource_name)` | 1 | 应用谷歌广告建议。一次性 — 谷歌已经验证过。 |
| `generate_keyword_ideas(customer_id, seed_type, ...)` | 1 | 搜索引擎营销关键词研究。返回谷歌的关键词扩展建议,包括平均搜索量、竞争程度和建议出价。 |
| `batch_job(customer_id, action, ...)` | 1 | 异步批量生命周期:`create` → `add_operations` → `run` → `status` → `results`。 |
| `offline_user_data_job(customer_id, action, ...)` | 1 | 客户匹配/商店销售上传生命周期:`create` → `add_operations` → `run` → `status`。 |
| `ping()` | — | 连接性检查。返回 `"pong"`。 |
资源:
- `gads-account://accessible` — 凭证可操作的客户ID。
- `gads-schema://{resource_type}` — 每个GAQL资源的可选择/可筛选/可排序字段。
- `gads-rpc-catalog://` — v24 SDK中所有公开的RPC,带有`read_only` / `supports_validate_only`提示。
- `gads-rpc-schema://{service}/{method}` — 按方法请求的proto字段。
## 架构
在单个SDK边界后面有三层。**第1层** 有大约13个结果形状的工具,封装了 **第2层** 的五个通用逃生阀(`gaql`、`mutate`、`call_read_rpc`、`call_mutate_rpc`、`apply`)。`ads/` 包是唯一导入 `google.ads.googleads.*` 的地方。模式、账户和RPC发现是MCP资源,不是工具 — 它们不计入环境上下文。总工具数量保持不变,谷歌添加服务时也是如此。
完整结构计划:参见 `plan.md`。
## 安全模型
服务器强制执行 *不变性*,而非您的账户 *策略*:
1. **两阶段写入**。`mutate(...)` (或任何第1层写入工具)调用API时带有 `validate_only=true`,渲染每个操作的差异,存储在带有15分钟TTL的 `mutate_id` 下。`apply(mutate_id)` 提交。重新应用相同的ID返回缓存结果并 **不** 重新调用API。
2. **客户ID允许列表**,由真实OAuth授予构建。虚构ID被拒绝。
3. **追加审计日志**,记录每次尝试 — 成功、验证失败、API错误、过期、未找到、缓存重放。
4. **MCP `ToolAnnotations`**,在每个工具上,以便客户端正确渲染确认提示。
服务器故意不强制执行CPC上限、预算上限或批量上限 — 这些取决于您的垂直领域(保险行业通常出价200美元;电子商务在5美元时达到收益递减点)。两阶段预览是实际的安全机制:新值在提交前在差异中,LLM和人类都可以看到。
## 可观察性
三种日志,每种面向不同的受众:
| 日志 | 路径 | 格式 | 记录内容 |
|---|---|---|---|
| **审计** | `~/.local/share/google-ads-mcp/audit.log` | JSONL,模式 `0600` | 每次状态更改尝试。对于“LLM是否执行了X?”的取证答案。 |
| **活动** | `~/.local/share/google-ads-mcp/activity.log` | JSONL | 每次工具/资源调用:名称、参数摘要、持续时间(毫秒)、结果。包括读取操作。 |
| **诊断** | 标准错误输出 | 文本 | 服务器生命周期和面向操作员的警告。 |
审计和活动日志每次写入一行(POSIX追加原子操作,最大4KB)。诊断日志可通过 `log_level` 配置;审计和活动日志始终开启。
**审计模式**(每行一个JSON对象):
```json
{
"timestamp": "2026-04-28T18:30:15.123456+00:00",
"phase": "preview" | "apply",
"outcome": "ok" | "guardrail_rejection" | "validation_failed"
| "api_error" | "expired" | "not_found" | "cached_replay",
"mutate_id": "...",
"customer_id": "1234567890",
"payload_kind": "operations" | "rpc_call" | null,
"operations": [{...}] | null, // payload_kind=operations
"rpc_call": {"service":"...", "method":"...", "params":{...}} | null, // payload_kind=rpc_call
"result": {"resource_names": [...]} | null,
"error": {"type": "...", "message": "...", "request_id": "..."} | null
}
```
**活动模式**:
```json
{
"timestamp": "...",
"kind": "tool" | "resource",
"name": "pause_campaign",
"args_summary": {...},
"duration_ms": 123,
"outcome": "ok" | "error",
"error": {"type": "...", "message": "..."} | null
}
```
## 配置
`GOOGLE_ADS_MCP_`前缀的环境变量覆盖编译的默认值。
| 设置 | 默认值 | 备注 |
|---|---|---|
| `credentials_path` | `~/.config/google-ads-mcp/credentials.yaml` | XDG-aware. |
| `audit_log_path` | `~/.local/share/google-ads-mcp/audit.log` | XDG-aware. |
| `activity_log_path` | `~/.local/share/google-ads-mcp/activity.log` | XDG-aware. |
| `gaql_max_rows` | `1000` | GAQL行限制。 |
| `gaql_max_response_bytes` | `256000` | 返回给LLM的近似响应大小限制。 |
| `mutate_id_ttl_seconds` | `900` (15 分钟) | 预览变体的TTL。 |
| `log_level` | `INFO` | 诊断stderr级别。 |
## 开发
```sh
git clone <此存储库>
cd google-ads-mcp
uv sync --group dev
uv run pytest # 100个单元测试
uv run ruff check .
uv run pyright src tests # 严格模式
```
测试套件在没有凭证的情况下运行:任何高于 `ads/` SDK边界的内容都可以使用模拟存根进行测试。
## 许可证
MIT。参见 `LICENSE`。