gads-write-mcp
Provides guardrailed management of Google Ads accounts, with per-user OAuth authentication, role-based permissions, and planned capabilities for pausing or enabling campaigns, adjusting budgets and bids, managing keywords, and creating responsive search ads.
Click on "Install 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., "@gads-write-mcpPause the 'Summer Sale' campaign and show me the preview before applying."
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.
gads-write-mcp
A guardrailed write MCP server for Google Ads, for the marketing team to use from Claude web and desktop.
This server can spend real money. Every design decision here is downstream of that fact.
Separate repo, separate process, separate hostname (adswrite.indiraivf.in)
from the read-only googleads/google-ads-mcp already on this box. Google's
code is not forked or modified.
Current state: Phase 1 complete, awaiting verification
Phase 1 is the skeleton: config validation, Google OAuth, caller identity,
role resolution, and one health_check tool.
There is no Google Ads client in this phase. The google-ads library is
not even a dependency — it is added in Phase 3. Nothing in this codebase can
currently touch an ad account.
Phase | Scope | State |
1 | Skeleton: settings, OAuth, | built |
2 | Safety core against a fake executor, no API calls | not started |
3 | Reads: per-user client, accounts, performance, search terms | not started |
4 | First mutation ( | not started |
5 | Budget, bids, negatives, keywords, RSA | not started |
6 | Rollout: runbook, log shipping, alerting, rollback | not started |
Related MCP server: Google Ads MCP
How safety is layered
Five independent things must all agree before a single field changes. Any one of them says no, nothing happens.
Google's own permissions. Every Ads call uses the calling user's OAuth token. No static refresh token exists anywhere. Remove someone from the MCC and they lose access immediately — no redeploy, no config edit here.
The kill switch.
GADS_WRITE_ENABLED=falsemakes the whole server read-only. One env change, one restart.Role tier.
config/roles.yamlmaps email toreadonly/operator/lead. Unlisted people getnone.Policy.
config/policy.yamlholds the account allowlist and spend limits, checked at draft time and again at confirm time.Two-step confirm. Writes return a preview and a
plan_idand do nothing else. A separate call applies it.
Phase 1 implements 1–3. Layers 4 and 5 arrive in Phase 2.
Local setup
python3 -m venv .venv
.venv/bin/pip install -e '.[dev]' # Windows: .venv\Scripts\pip
cp .env.example .env # then fill it in
.venv/bin/python -m pytest # 15 tests, no network neededNote for the Windows dev box: ops/run.sh and ops/nginx.conf are for the
Ubuntu server. Locally you only need python -m gads_write.server, and even
that needs a .env with real OAuth credentials to be useful.
Configuration
Three files, and only these three, decide what this server can do:
File | Controls | Committed? |
| credentials, port, kill switch | no |
| account allowlist, spend limits | yes |
| who has which tier | yes |
No customer ID, budget limit, or email address may be hardcoded in Python.
The server validates all of this at boot and refuses to start if anything
is missing or malformed — reporting every problem at once, not one per
restart. Try it: unset GADS_DEVELOPER_TOKEN and start the server.
Deploying (Ubuntu EC2)
1. Google Cloud console
Create an OAuth 2.0 Web application client (or reuse the existing project — a new client, so this server's sessions are independent of the read-only one). Set:
Authorised JavaScript origin:
https://adswrite.indiraivf.inAuthorised redirect URI:
https://adswrite.indiraivf.in/auth/callback
Scopes requested are openid, userinfo.email, and adwords. The adwords
scope is requested from Phase 1 even though nothing uses it until Phase 3 —
adding a scope later forces every user to re-consent.
2. DNS and TLS
Point adswrite.indiraivf.in at the box, then:
sudo cp ops/nginx.conf /etc/nginx/sites-available/adswrite.indiraivf.in
sudo ln -s /etc/nginx/sites-available/adswrite.indiraivf.in /etc/nginx/sites-enabled/
sudo certbot --nginx -d adswrite.indiraivf.in
sudo nginx -t && sudo systemctl reload nginxThe Nginx config disables response buffering and raises the read timeout to 300s. Both are required: MCP streamable HTTP delivers server-sent events, and Nginx's defaults would buffer them and cut the connection at 60s.
3. Application
git clone <repo> /home/ubuntu/gads-write-mcp && cd $_
python3 -m venv .venv
.venv/bin/pip install -e .
cp .env.example .env && $EDITOR .env # keep GADS_WRITE_ENABLED=false
# set cwd in ops/ecosystem.config.js to this directory
pm2 start ops/ecosystem.config.js
pm2 save
pm2 logs gads-write-mcpPort 8081, so it does not collide with the read-only server on 8000.
instances: 1 is deliberate and must stay — Phase 2 holds draft plans in
process memory, and a second worker would not see plans drafted by the first.
4. Connect from Claude
Add a custom connector pointing at https://adswrite.indiraivf.in/mcp.
Phase 1 verification
Do these in order. Do not proceed to Phase 2 until all four pass.
Boot fails loudly on bad config. Comment out
GADS_DEVELOPER_TOKENin.env, runpm2 restart gads-write-mcp, checkpm2 logs. Expect a refusal listing the problem, not a running server. Put it back.You see yourself. Connect from Claude web, run
health_check. Expect your own email,tier: lead, andwrite_enabled: false.Someone else sees themselves. A second person connects and runs
health_check. Expect their email — not yours, not a shared identity. This is the one that actually proves per-user OAuth. If both of you see the same email, stop; something is badly wrong.An unlisted person is fenced out. Someone not in
config/roles.yamlconnects and runshealth_check. Expecttier: noneand the "ask a lead to add you" note.
Worth also checking in step 2: credentials.google_token_available should be
true. That proves the Phase 3 credential path already works, without the
token ever leaving auth/identity.py.
Where things live
config/ policy.yaml, roles.yaml — all limits and permissions
src/gads_write/
server.py FastMCP app, tool registration
settings.py boot validation, fails fast
auth/ identity.py (who), roles.py (what tier)
ads/ phase 3+ — executor.py is the ONLY mutate call site
safety/ phase 2 — guards, policy, plans, validators, audit
tools/ phase 3+ — one module per tool group
tests/
ops/ ecosystem.config.js, nginx.conf, run.shMoney is in micros
Google Ads expresses currency in millionths of the unit. ₹500/day is
500_000_000 micros. A missing conversion is a 1,000,000× error that
type-checks perfectly and passes review.
Rule: every variable holding money carries its unit in the name —
budget_micros, budget_rupees — and conversion happens in exactly one
place. Never a bare budget.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Run Google, Meta, Microsoft, TikTok and LinkedIn Ads from Claude or ChatGPT. Writes need approval.
Google Ads MCP with 20,000+ account peer context and staged approve-then-execute writes.
Run Google Ads, Meta Ads, GA4 and Search Console from chat: read, audit and launch campaigns.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceEnables comprehensive management of Google Ads campaigns through natural language, including campaign creation, ad group management, keyword operations, Performance Max campaigns, conversion tracking, and performance insights with support for multiple accounts.4
- AlicenseAqualityBmaintenanceEnables managing Google Ads campaigns through an AI assistant with read-only reporting, recommendations, and gated write operations for bids, budgets, and statuses, all backed by preview and audit logging.311MIT
- AlicenseNot gradedqualityAmaintenanceA Google Ads MCP server that enables safe, auditable management of ad accounts through natural language, including proposing, reviewing, applying, and rolling back changes with guardrails and dry-runs.MIT
- AlicenseNot gradedqualityCmaintenanceEnables full read/write control of Google Ads accounts—managing campaigns, ad groups, ads, keywords, Performance Max, budgets, targeting, and performance reporting through natural language. Supports Search, Display, Video, and Demand Gen campaign types with flexible GAQL querying and comprehensive reporting.1Apache 2.0
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/workAjayvadadre/gads-write-MCP'
If you have feedback or need assistance with the MCP directory API, please join our Discord server