The difference is not how clever the prompt is. It is whether Claude can reach the platform. When Claude has an API connection, it can read your real numbers instead of the numbers you paste in, and it can write changes back as structured requests instead of asking you to click through a dashboard. That is the whole unlock, and it is also exactly why you scope it tightly.
You describe the campaign, Claude writes headlines and angles, you copy them into Ads Manager and set everything up by hand. Good output, but you are still the one doing every click, and Claude is guessing at performance because it cannot see your account.
Claude queries the account directly, so it argues from your real cost per conversion. It drafts the campaign as an actual API request, dry runs it, shows you the exact fields, and creates it paused for your approval. You review and enable. It reports back weekly.
Do not start with the ability to spend. Start with the ability to see. Google's own Ads team publishes a Model Context Protocol server that is read only by design: it exposes three tools, list_accessible_customers, search and get_resource_metadata, and none of them can change a bid, pause a campaign or create anything (googleads/google-ads-mcp). That is the safest possible way to find out whether this workflow is worth it for you.
claude in a folder you have made for this project. Everything below happens inside that one folder, which matters later when you write the rules file.pipx so nothing is installed globally.claude mcp list. A healthy server shows Connected. If it shows Failed to connect, the cause is almost always a wrong credentials path or a developer token that has not been approved yet. The MCP reference covers the rest.claude mcp add --transport stdio google-ads \
--env GOOGLE_PROJECT_ID=your-project-id \
--env GOOGLE_ADS_DEVELOPER_TOKEN=your-developer-token \
--env GOOGLE_APPLICATION_CREDENTIALS=/full/path/to/credentials.json \
-- pipx run --spec git+https://github.com/googleads/google-ads-mcp.git google-ads-mcp
For TikTok there is an official hosted equivalent, and it needs no credentials file at all. TikTok's Agentic Hub documentation gives two endpoints and notes that the full one is the one to use with Claude, since it loads the whole toolset at connection time (TikTok for Business MCP Server).
claude mcp add --transport http tiktok-ads https://business-api.tiktok.com/open_mcp/tt-ads-mcp-flat
/mcp inside Claude Code to see the status and finish sign in. Because this one is hosted, it exposes write tools too, which is exactly why the approval gate in step 5 matters more here than on the Google side.Once a server is connected, this is the first prompt I run. It is a pure reading exercise, and it tells you immediately whether Claude actually understands your account.
You are connected to my ad account through an MCP server. For this conversation, treat yourself as read only: query freely, but do not call any tool that creates, updates or deletes anything, even if I ask you to.
Start by listing every account I have access to and telling me which one looks like the main spending account. Then for that account, pull the last 30 days of spend, impressions, clicks, conversions and cost per conversion, broken out by campaign, and show it as a table sorted by spend.
Now interpret it for me. Which campaigns are carrying this account, which ones are quietly burning budget, and which ones have too little data to judge yet? Be explicit about the sample size behind each verdict, and say when a number is too thin to act on.
Finish with the three changes you would make if you had write access, ranked by how much money each one moves. For each change, name the exact campaign, the exact field you would set, and the evidence you would want to see before you would be comfortable making it.
This is the part everyone underestimates. Neither platform hands out API access instantly, so start the application before you need it. Here is each one from zero.
python -m pip install google-ads, per the Python client library docs. This is what your scripts will use for anything the read only MCP server cannot do.google-ads.yaml holding your developer token, client ID, client secret and refresh token, with developer_token the one field marked required (configuration guide). Keep it outside your repo and add it to .gitignore the same day you create it./open_api/v1.3/campaign/create/, passing your access token and a body containing advertiser_id, campaign_name, objective_type, budget_mode and budget. TikTok's own SDK reference shows the exact call shape, and the create a campaign guide covers the field values..env file or your OS keychain, never in a script, never in a screenshot, never in a chat message. Set the shortest expiry the platform offers and rotate it the moment a device or contractor changes.Both platforms give you a free environment where the API behaves normally but nothing serves and nothing is charged. Building your first three or four campaigns here is what turns this from a scary idea into a boring routine.
An operator with a vague brief is worse than no operator. Before any API call exists, get the whole campaign written down as a file you both work from, with the numbers that decide success stated up front. This one file is what every later prompt refers back to.
Before you touch the API, I want a full campaign spec written to a file called campaign-spec.md in this folder, so we are both working from the same document.
The campaign runs on [Google Ads or TikTok Ads] for [describe the offer and the landing page URL], selling to [describe the audience] in [countries]. The hard total budget is [$X] across [N] days, with a daily cap of [$Y], and those two numbers are ceilings, not targets.
The single metric that decides whether this worked is [cost per lead, ROAS, or cost per purchase] with a target of [number]. If it goes above [ceiling number] for two consecutive days, the campaign gets paused. Write that rule into the file in plain language.
Now write out the full structure: campaign name, objective, budget mode and amount, bidding strategy, targeting, ad group structure, and the exact ad copy variants with character counts checked against the platform limits. Flag every single field where you had to guess or invent a value, in a section called "assumptions to correct", so I can fix them before anything gets created.
This is the part that makes the whole thing safe, and both platforms support it properly. On Google Ads you set an optional validate_only boolean to true on a mutate request, and the API validates it exactly as if it were going to run, then skips execution and returns an empty response when there are no errors (API structure). You get every error you would have got, and none of the consequences.
Using campaign-spec.md as the only source of truth, write a Python script called launch_campaign.py that creates this campaign through the platform's official client library.
The script must default to a dry run. On Google Ads that means setting validate_only to true on every mutate request, creating the campaign budget resource first, then creating the campaign that references it with status set to PAUSED. Nothing real happens unless I pass a --live flag on the command line, and even with --live the campaign is still created paused.
When it runs, print a plain English summary of exactly what would be created: campaign name, objective, budget mode, budget amount, daily cap, targeting and every ad variant. Then print the raw request body too, so I can read the actual fields rather than your description of them. Stop there and wait.
Do not hardcode any credential. Read them from the config file or environment variables, never print a token or a secret to the terminal or a log, and add the config file to .gitignore if it is not already there.
Google's own campaign documentation gives the same advice as a recommendation: set the campaign to PAUSED when creating it so the ads do not immediately serve, and set it to ENABLED once targeting is in place and the ads are ready (create campaigns). Enabling is the one action you keep for yourself.
operation_status field looks like it lets you create a campaign disabled, but it is an allowlist-only feature. If you pass it without being allowlisted, TikTok ignores the field and returns no error at all, so a campaign you believed was paused is live (campaign field reference). Tell Claude to always read the campaign back after creating it, and to pause it through the /campaign/status/update/ endpoint rather than trusting the create call.You can write that last one into the project instead of relying on memory. Claude Code reads permission rules from .claude/settings.json in the project folder, and a deny rule always wins over an allow rule (configure permissions). Something like this is enough:
{
"permissions": {
"ask": [
"Bash(python launch_campaign.py *)"
],
"deny": [
"Bash(python launch_campaign.py * --live *)"
]
}
}
With that in place, the dry run always prompts you, and the live run is blocked outright until you consciously remove the deny rule. Then pin the behaviour rules alongside it in a CLAUDE.md, which Claude Code loads automatically at the start of every session in that folder (memory docs).
Write me a CLAUDE.md for this folder that hardcodes the rules we work by, because this project spends real money and I do not want to restate this every session.
The rules are: never make a create, update or delete API call without showing me the exact request body first and waiting for my explicit yes. Always dry run before a live run. Always create campaigns paused, and never enable one yourself under any circumstances. Never set a budget above the ceiling written in campaign-spec.md, and if the spec and my instruction disagree, stop and ask rather than picking one.
Add a security section: never print, echo, log or commit an access token, a refresh token or the config file, and never paste a credential into a summary.
Finish with a short table listing every script in this folder and marking each one as read only or can-spend-money, so the distinction is impossible to miss at a glance. Keep the whole file under one page, because a rules file nobody reads is a rules file nobody follows.
Once the campaign is live, the value is not the launch, it is the review you would otherwise keep skipping. This is the rhythm I would run: one prompt on a Monday, ten minutes of reading, and you approve or reject a written change list.
Pull the last 7 days of performance for every active campaign in this account and compare it with the 7 days before. Give me the numbers, not adjectives, and show them as a table.
For each campaign, report spend, the target metric named in campaign-spec.md, and whether it crossed the pause ceiling we wrote in that file. Say clearly which campaigns have enough data to judge and which ones do not, and do not make a recommendation on a campaign with a sample too small to support one.
Then write a change list into a file called changes-this-week.md: what to pause, what to raise, what to lower, and what to leave alone. For every proposed change, give the exact campaign, the exact API field and the exact new value, plus one line on the evidence behind it.
Do not execute any of it. I will read the file, delete the lines I disagree with, and tell you which ones to run. When I do, dry run them first and show me the validated request bodies before anything real happens.
Google Ads MCP server, official repo (read only, three tools)
Google Ads API, obtain a developer token
Google Ads API, access levels and daily operation limits
Google Ads API, test accounts
Google Ads API, validate_only dry runs
Google Ads API, create campaigns (the PAUSED recommendation)
TikTok for Business, Agentic Hub and MCP server
TikTok API for Business, create a campaign
TikTok API for Business, sandbox accounts
TikTok Business API SDK, official repo
Claude Code, connect tools via MCP
Claude Code, configure permissions