If you live in a terminal or an editor, there's a good chance you also end up answering "how are the ads doing?" now and then. This tutorial wires Google Ads and Meta Ads into Claude Code and Cursor through the Model Context Protocol (MCP), so you can ask that question without opening any ad dashboard.
The server used here is MCP Ads, which runs as a remote MCP server (with an MIT-licensed self-host option). The key property: you never create or paste an API key. Auth happens with OAuth in your browser.
What you'll need
- Admin or standard access to at least one ad account (Google Ads, Meta Ads, LinkedIn Ads or TikTok Ads).
- Billing enabled on that account only if you plan to launch campaigns. Reading data doesn't need it.
- Claude Code or Cursor.
- An MCP Ads account with your platforms connected (step 1).
Step 1: Connect the ad platforms (in the browser)
Sign up, then connect each platform from the dashboard. Every connection goes through that platform's own OAuth screen, so your Google or Meta credentials are never typed into MCP Ads or into a chat.
Once you've approved access, the dashboard lists the specific ad accounts each connection can reach. If an account is missing, that's a permissions issue on the platform side.
Why this matters for developers: Google Ads API access normally needs a developer token that Google reviews, and Meta's ads_management / ads_read permissions need App Review. On the hosted server those approvals are already in place. That's what "no API keys" really saves you.
Step 2a: Add it to Claude Code
One command. The transport is HTTP because this is a remote server, not a local process:
claude mcp add --transport http mcp-ads https://mcp-ads.com/mcp-slim
mcp-ads is just a local label, so name it whatever you like. The entry goes into ~/.claude.json at user level, so you add it once per machine, not once per project.
Check that it's registered:
claude mcp list
The first tool call opens a browser window for the OAuth grant. Approve it once and it persists. Any Claude Code session that was already open before you added the server won't see the tools until you restart it.
Step 2b: Add it to Cursor
Cursor reads MCP servers from a JSON file. Use ~/.cursor/mcp.json for user level, or .cursor/mcp.json in a project root:
{
"mcpServers": {
"mcp-ads": {
"url": "https://mcp-ads.com/mcp-slim"
}
}
}
It's a remote entry, so it takes a url rather than a command. There's no package to install and no API key field. (The MCP Ads homepage shows the same block with "type": "http" added, the generic form many MCP clients accept.)
Then:
- Fully restart Cursor. MCP servers are only read at startup.
- Open Settings → MCP. The
mcp-adsentry should be green with a tool count. - Ask the agent anything that needs a tool. Cursor opens a browser tab on mcp-ads.com where you sign in and approve the grant.
The browser is the only place credentials are ever entered. Nothing about your ad accounts is stored in mcp.json or in Cursor's settings.
Step 3: Smoke test
Start with a prompt that just lists what's connected:
Using mcp-ads, list the platforms I have connected and the accounts on each.
An empty list means the server is reachable but no platform is connected yet. Go back to the dashboard, connect one, and ask again.
Example prompts
Be specific. Naming the account, the metric and the period gets you a useful answer on the first try. All of these come from the project's docs and README:
Show me wasted spend across all my Google Ads campaigns this month.
What changed in my Meta Ads performance week over week?
Compare Meta and Google CPA for last week against GA4 conversions.
Which search terms spent over $50 with no conversions last month?
Add the worst ten as exact-match negatives.
Build a paused Search campaign for 'emergency plumber' with three ad
groups and a $50 daily budget.
What are my competitors running on Facebook and Instagram right now?
Some editor-specific uses that work well in Cursor: reading the search terms that will point at a landing page while you build it, or wiring up conversion tracking with the GA4 and GTM tools open next to the code.
How the tool surface stays small
At the time of writing, the hosted build registers 3,363 actions across Google Ads, Meta, GA4, Search Console, Tag Manager, TikTok, LinkedIn, Microsoft Ads, Merchant Center and more. Loading thousands of tool definitions into a context window would be a disaster, so the server exposes one dispatcher per platform family plus a list_actions tool. The agent discovers actions first, then calls one:
1. list_actions(category="meta_ads_action", search="budget")
2. meta_ads_action(action="<name from step 1>", params={...})
Your agent loads about two dozen tool definitions instead of thousands. (A --surface full mode registers every action as its own tool for programmatic clients. It's not something you want in a chat client.)
The approval-before-change design
An agent that can read your ad account can usually write to it too, and writes cost real money. The README documents several layers of protection:
1. MCP tool annotations. Every dispatcher family that contains any write action is marked readOnlyHint: false and destructiveHint: true. The check fails closed, so a hidden write action still flags the whole family. Clients like Claude and ChatGPT use those hints to ask you before the call runs. Client behaviour varies, so check how yours handles destructive tools.
2. Server instructions. The server also tells the model to state any write plainly and get your confirmation before it touches live spend or public content. In practice, the agent shows you a list like "add negative keyword X, change budget from A to B" and waits.
3. Paused by default. Campaign, ad set, ad group and ad creation default to PAUSED on Google Ads and Meta. A campaign "built from one sentence" doesn't spend a cent until you enable it.
4. Role gating. Write tools call require_editor(), which refuses the viewer role. A name-based heuristic fails closed for write verbs missing from the explicit WRITE_TOOLS list. On the hosted service, viewer seats can't change anything.
5. Deletes need an explicit yes. Deletions exist, but the assistant has to say exactly what will be removed and get your explicit yes first. It also suggests pausing instead, because a pause can be undone.
6. Audit log. Every call is written to an audit log.
The pattern is worth copying even if you build your own MCP server: annotate honestly, fail closed on anything that looks like a write, and make the safe state the default state.
Troubleshooting
| Symptom | Likely cause |
|---|---|
| Server missing in Cursor after restart | File in the wrong place or invalid JSON (watch for trailing commas). Cursor only reports parse errors in its MCP log. |
| OAuth window never opens | Popup blocker or non-default browser. Cursor prints the auth URL in the MCP output panel, so copy it into any browser. |
| "A server with this URL already exists" | Same URL defined at both user and project level. Keep one. |
| Red status or zero tools | URL must be exactly https://mcp-ads.com/mcp-slim, with no trailing slash. Check that the domain is reachable on corporate networks. |
| Every call fails with an auth error | Grant revoked or expired. Remove the entry, restart, add it back, and approve again. |
| "No tools available" in Claude | The session started before the server was added. Start a new conversation. |
Self-hosting instead
The server is open source (MIT) at RoyAzran/mcp-ads on GitHub. You can run it locally over stdio with your own platform credentials:
git clone https://github.com/RoyAzran/mcp-ads.git
cd mcp-ads
pip install -r requirements.txt
cp .env.example .env # fill in the platforms you use
python server.py doctor # shows what's connected
{
"mcpServers": {
"mcp-ads": {
"command": "python",
"args": ["/absolute/path/to/mcp-ads/server.py"]
}
}
}
The honest trade-off: self-hosting means you hold your own keys. GA4, Search Console and GTM take minutes. Google Ads needs a reviewed developer token, typically 1–3 weeks. Meta needs App Review for anyone beyond the app's own admins and testers. The self-host build also has no read-only config switch yet. The README says to set the self-host principal's role to "viewer" to block all writes.
Wrap-up
Two minutes of config gets you Google Ads and Meta Ads, plus GA4 and Search Console, in the same agent session as your code. Start with read-only questions, get comfortable with the approval prompts, then let the agent propose changes.
Setup guides for other clients (Windsurf, Codex, Gemini CLI, ChatGPT and others) are in the docs at mcp-ads.com.
Top comments (0)