gam-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@gam-mcplist orders from last week"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
gam-mcp
A security-first MCP server for Google Ad Manager — least-privilege by default, gated writes, and a path to per-user OAuth that existing GAM MCP servers don't offer.
(한국어 설명은 아래에 있습니다 / Korean version below.)
English
What this is
gam-mcp is a self-hosted Model Context Protocol server that lets an AI client (Claude Code, Claude Desktop, etc.) read and — with explicit confirmation — write Google Ad Manager data through the Ad Manager API (Beta) REST.
It is built for an enterprise posture where billions in ad spend are at stake: the service-account key and access tokens stay inside the server process and are never exposed to the model, reads and writes are separated by OAuth scope, and every mutation requires a deliberate two-step confirmation.
Why another GAM MCP server? (the gap)
Ad Manager MCP servers already exist, but they share one architectural choice that doesn't fit a security-sensitive, multi-user org:
Project | Auth model | Transport | Gap for enterprise use |
Single shared service account ( | stdio + HTTP | One "master key" for the whole network; every action attributes to the service account, so per-user accountability is lost | |
Vendor-hosted managed proxy | Hosted HTTP | Credentials are entrusted to a third-party vendor | |
googleads/google-ads-mcp (official) | Per-user OAuth, on-behalf-of | stdio + Cloud Run | For Google Ads (advertiser), not Google Ad Manager (publisher) — different product/API |
In short: the per-user OAuth on-behalf-of pattern — where each call runs against the caller's own GAM permissions and stays fully auditable — exists for Google Ads but not for Google Ad Manager. Every off-the-shelf GAM MCP server is a shared-service-account ("master key") design.
gam-mcp fills that gap. It starts as a least-privilege single-user server and is deliberately structured (transport- and auth-agnostic) to grow into per-user OAuth on-behalf-of for central deployment — the model the existing GAM servers don't provide.
Security model
Layer | Control | Where |
1 | Least-privilege token — the read-only OAuth scope ( |
|
2 | Read-only kill-switch — write tools aren't even registered. |
|
3 | Network allowlist — every tool re-checks the network code against |
|
4 | Propose → confirm gate — |
|
5 | Append-only audit log — every call is recorded with redacted args before the result returns. |
|
The service-account key and access tokens live in this process only and are never placed in a tool result. Claude Code's own permission prompt gates each tool call as a separate, outer layer.
Authentication modes
The client is auth-agnostic (AuthStrategy), so the same tools work under any of:
service_account— one shared identity. Simplest for a local, single-operator setup. This is the "master key" model every off-the-shelf GAM MCP server uses.user_oauth— per-user identity. Each operator runsnpm run loginonce to authorize with their own Google account; the server then calls GAM as that user, so their own GAM role bounds every action and the audit trail attributes to a real person. Works over stdio today. Only a refresh token (never an access token) is cached, atGAM_TOKEN_STORE.OBO (roadmap) — central multi-tenant on-behalf-of, where an incoming authenticated user maps to their stored per-user credential. Requires the HTTP transport; the
AuthStrategyinterface is the drop-in point.
Set the mode with GAM_AUTH_MODE. For user_oauth:
GAM_AUTH_MODE=user_oauth
GAM_OAUTH_CLIENT_ID=xxxx.apps.googleusercontent.com
GAM_OAUTH_CLIENT_SECRET=xxxx
npm run build && npm run login # opens a browser, caches the refresh tokenTools
Read (always on): get_network, list_orders, get_order, list_line_items, get_line_item, run_report.
Write (only when GAM_READ_ONLY=false): propose_update_line_item → confirm_write.
Prerequisites (one-time, in the GAM + GCP consoles)
Shared, both modes:
Enable the API — GAM → Admin → Global settings → Network settings → turn on API access. Note your network code (the number in
admanager.google.com/<code>#home).GCP project — enable the Google Ad Manager API.
Then, depending on GAM_AUTH_MODE:
service_account— create a service account, download a JSON key (never commit it), and add the service-account email as a GAM user with a least-privilege role (start read-only).user_oauth— create an OAuth 2.0 Client ID (type: Desktop app) and configure the consent screen. No key file and no extra GAM user needed — each operator just has to already be a GAM user. Runnpm run loginto authorize.
Install
npm install
cp .env.example .env # fill in credentials path + network code(s)
npm run buildConfigure (.env)
GOOGLE_APPLICATION_CREDENTIALS=/absolute/path/to/service-account.key.json
GAM_NETWORK_ALLOWLIST=1234567
GAM_READ_ONLY=true # flip to false only after validating readsRegister with Claude Code / Claude Desktop
{
"mcpServers": {
"gam": {
"command": "node",
"args": ["/absolute/path/to/gam-mcp/dist/index.js"],
"env": {
"GOOGLE_APPLICATION_CREDENTIALS": "/absolute/path/to/service-account.key.json",
"GAM_NETWORK_ALLOWLIST": "1234567",
"GAM_READ_ONLY": "true"
}
}
}
}API surface & gaps
Uses the Ad Manager API (Beta) REST (https://admanager.googleapis.com/v1). Not every mutating operation exists in Beta yet — some remain SOAP-only. Where a write endpoint isn't live, confirm_write surfaces the GAM error verbatim; a SOAP fallback is future work.
Roadmap
Per-user OAuth identity for local/stdio (
GAM_AUTH_MODE=user_oauth)Central multi-tenant on-behalf-of (needs HTTP transport + IdP)
Streamable HTTP transport
SOAP fallback for operations not yet in Beta REST
Rate limiting and budget/impression caps on writes
Related MCP server: Google MCP Server
한국어
개요
gam-mcp는 AI 클라이언트(Claude Code, Claude Desktop 등)가 Ad Manager API (Beta) REST를 통해 Google Ad Manager 데이터를 읽고, 명시적 확인을 거쳐 쓰도록 해주는 self-hosted MCP 서버입니다.
수십억 규모의 광고 집행을 다루는 보안 민감 환경을 전제로 설계했습니다 — 서비스 계정 키와 액세스 토큰은 서버 프로세스 안에만 존재하며 모델에 노출되지 않고, 읽기/쓰기는 OAuth scope로 분리되며, 모든 변경은 2단계 확인을 거쳐야 합니다.
왜 또 다른 GAM MCP 서버인가? (채우는 공백)
Ad Manager용 MCP 서버는 이미 있지만, 전부 보안 민감·다중 사용자 조직에 맞지 않는 하나의 설계를 공유합니다:
프로젝트 | 인증 모델 | 전송 | 엔터프라이즈 관점의 공백 |
단일 공유 서비스 계정 + HTTP bearer | stdio + HTTP | 네트워크 전체가 하나의 "마스터 키" → 모든 액션이 서비스 계정에 귀속되어 사용자별 추적성 상실 | |
벤더 호스팅 관리형 프록시 | 호스티드 HTTP | 자격증명을 외부 벤더에 위탁 | |
per-user OAuth, on-behalf-of | stdio + Cloud Run | Google Ads(광고주) 용, Ad Manager(퍼블리셔) 아님 — 다른 제품/API |
요약하면, 각 호출이 호출자 본인의 GAM 권한으로 실행되고 완전히 감사 가능한 per-user OAuth on-behalf-of 패턴은 Google Ads에는 있지만 Google Ad Manager에는 없습니다. 기성 GAM MCP 서버는 전부 공유 서비스 계정("마스터 키") 방식입니다.
gam-mcp가 그 공백을 메웁니다. 최소 권한 단일 사용자 서버로 시작하되, 중앙 배포용 per-user OAuth on-behalf-of로 확장할 수 있도록 transport·auth-agnostic하게 설계했습니다 — 기존 GAM 서버가 제공하지 않는 모델입니다.
보안 모델
계층 | 통제 | 위치 |
1 | 최소 권한 토큰 — |
|
2 | 읽기 전용 kill-switch — 쓰기 도구를 아예 등록하지 않음 |
|
3 | 네트워크 allowlist — 모든 도구가 네트워크 코드를 재검증 |
|
4 | propose → confirm 게이트 — |
|
5 | append-only 감사 로그 — 모든 호출을 redaction 후 기록 |
|
키·토큰은 서버 프로세스에만 존재하고 도구 결과에 절대 담기지 않습니다. Claude Code 자체 permission 프롬프트가 별도의 바깥 계층으로 각 호출을 게이트합니다.
인증 모드
클라이언트가 auth-agnostic(AuthStrategy)이라 아래 어느 방식이든 같은 도구가 동작합니다:
service_account— 단일 공유 신원. 로컬 단일 운영자에게 가장 단순. 기성 GAM MCP가 모두 쓰는 "마스터 키" 모델.user_oauth— 사용자별 신원. 각 운영자가npm run login으로 자기 Google 계정을 1회 인증하면, 서버가 그 사용자로서 GAM을 호출 → 본인의 GAM role이 모든 액션의 한도가 되고 감사 로그가 실제 사람에게 귀속됩니다. 지금 stdio에서 동작하며, refresh token만(액세스 토큰은 절대 저장 안 함)GAM_TOKEN_STORE에 캐시됩니다.OBO (로드맵) — 중앙 멀티테넌트 on-behalf-of. 인증된 사용자를 그의 저장된 자격증명에 매핑. HTTP transport 필요하며,
AuthStrategy인터페이스가 그 확장 지점입니다.
GAM_AUTH_MODE로 선택. user_oauth 예:
GAM_AUTH_MODE=user_oauth
GAM_OAUTH_CLIENT_ID=xxxx.apps.googleusercontent.com
GAM_OAUTH_CLIENT_SECRET=xxxx
npm run build && npm run login # 브라우저 인증 → refresh token 캐시도구
읽기(상시): get_network, list_orders, get_order, list_line_items, get_line_item, run_report.
쓰기(GAM_READ_ONLY=false일 때만): propose_update_line_item → confirm_write.
사전 준비 (GAM + GCP 콘솔, 1회)
공통 (두 모드 모두):
API 활성화 — GAM → Admin → Global settings → Network settings → API access 켜기. 네트워크 코드(
admanager.google.com/<코드>#home의 숫자) 확인.GCP 프로젝트 — Google Ad Manager API 활성화.
그다음 GAM_AUTH_MODE에 따라:
service_account— 서비스 계정 생성 → JSON 키 다운로드(커밋 금지) → 서비스 계정 이메일을 GAM 사용자로 추가하고 최소 권한 role 부여(읽기 전용으로 시작).user_oauth— OAuth 2.0 Client ID(유형: 데스크톱 앱) 생성 + consent 화면 설정. 키 파일·추가 GAM 사용자 불필요 — 각 운영자가 이미 GAM 사용자이기만 하면 됨.npm run login으로 인증.
설치 · 설정 · 등록
위 English 섹션의 명령/설정과 동일합니다.
API 범위와 한계
Ad Manager API (Beta) REST(https://admanager.googleapis.com/v1)를 사용합니다. 일부 변경 작업은 아직 Beta에 없고 SOAP 전용입니다. REST 엔드포인트가 없는 경우 confirm_write가 GAM 오류를 그대로 전달하며, SOAP 폴백은 향후 과제입니다.
License
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
Google Ads MCP server — manage campaigns, keywords, and metrics.
Google Ads MCP with 20,000+ account peer context and staged approve-then-execute writes.
Hosted Google Ads MCP with OAuth, bounded reads, and prepare/confirm writes.
MCP server for querying and analyzing data from ad platforms, analytics tools, and spreadsheets
Related MCP Servers
- AlicenseBqualityAmaintenanceAn MCP server that gives your AI assistant read + write access to Google Ads and GA4 — with safety guardrails that prevent accidental spend.91264MIT
- AlicenseNot gradedqualityDmaintenanceA unified MCP server that gives AI assistants direct access to Google Analytics 4, Google Search Console, Google Ads and Google Merchant Center data using OAuth2 user credentials.MIT
- FlicenseNot gradedqualityCmaintenanceEnables authorized users to securely connect to and manage their Google Ads accounts through MCP clients, with support for campaigns, ad groups, ads, keywords, reporting, and billing. Runs as a remote multi-user server on Cloudflare Workers with per-user authentication and safety controls.-
- AlicenseAqualityBmaintenanceAn MCP server that extends the official Google Ads MCP with safe, confirmed campaign administration across manager accounts, featuring immutable mutation plans, multi-step approvals, and post-write verification.8Apache 2.0