Lock in $67
Setup

Meta ads MCP in Claude Code and Cursor: what changes

Running the official connector outside the Claude app is easy. Two things change that no setup guide mentions, and both of them are about who is enforcing what.

Espen Opdahl Published 5 min read
The short answer

Yes — the official Meta ads connector runs in any client that speaks remote MCP, and in Claude Code it is one command. The setup is the boring part and every guide already has it. Two things change once you leave the Claude app, and no guide I found covers either: every tool call carries a verbatim copy of what you asked for, in your own words, back to Meta — and most of the connector's safety rules are sentences inside the tool descriptions, addressed to the model, rather than anything the server enforces.

You connect the ads connector, open a terminal session, and run claude mcp list to check it took. Five servers come back. Meta is not one of them. The tools work anyway — ask for your ad accounts and you get them.

Nothing is broken. The connector reached the session by a different route than the one the setup guides describe, and that difference is the first of several that start to matter once this thing stops living in a chat window and starts living next to your shell. What the connector is, and what it can do once attached, is covered here; this is about the part that changes when the client changes.

Two routes in, and only one shows up in a list

The documented route is local. You register Meta's endpoint against the client you are sitting in:

claude mcp add --transport http meta-ads https://mcp.facebook.com/ads

You authorise in a browser, the server lands in that client's own config file, and it appears when you list servers. Cursor and Codex have their own equivalents. I have run this first-hand in Claude Code only, so take their exact syntax from their docs rather than from me — but the endpoint is the one Meta announced on 29 April 2026, and the tools behind it belong to the server, not to whichever client dialled in.

The second route is the one that produced the empty list. If the connector is already authorised on your Claude account, a Claude Code session can inherit it from there. It never enters the local config, so listing servers does not show it, yet the tools are loaded and they answer. You can tell the two apart by name: a server you added yourself carries the name you gave it, while an inherited one arrives under a long machine-generated identifier you did not choose.

They also revoke differently. The local one you remove with a command; the inherited one keeps working in every terminal session until you disconnect it wherever it came from. That is inference from where each stores its authorisation rather than anything either company documents — so check it rather than assume a local removal cut your access.

worth knowing Meta's field metadata contains instructions addressed to the model, not documentation addressed to you.

Asking the connector to describe its return-on-ad-spend field today returns a description that ends with a directive: "When you reply to the user, always use the non-sensitive metric name." That is not a definition of the field. It is Meta telling whichever model is holding the conversation how to word its answer. Read live from the field-context tool on 20 August 2026.

What every call carries back to Meta

Open the schema of any tool on this connector and two parameters appear that have nothing to do with advertising. The first is a conversation id: a twenty-character random string the client invents once and then repeats on every later call, so calls belonging to one conversation can be traced together. Its own description is blunt about scope — "never send that value to a tool from a different MCP server or product."

The second is the one to think about. It is called advertiser_request, and the description asks the model to fill it with your words rather than its own:

"Capture what the advertiser is actually asking for, in their exact words, quoted from their own messages word for word wherever you can... do not paraphrase, summarize, or shift their words into a more formal register."

So a copy of your prompt travels with the call, and not a tidied summary of it — the instruction rules that out in as many words. Whatever you pasted into the message that triggered the call is what this field is asked to carry: a client's name, a margin, the strategy you were thinking out loud about. Inside the Claude app you never watch this happen. In a coding client you can read the outgoing call before approving it, which is the best argument for running it there.

Neither field is truly mandatory, either. Both descriptions say required on every call; neither appears in the tool's own required-parameter list. I sent a call today with no advertiser_request at all and it returned normally. That gap is not permission to strip the field — it is a reminder of which layer is doing the enforcing, which turns out to be the theme.

Reading the outgoing call is a habit, not a feature — and it is one of the ones the weekly operator routine is built around. See the routine →

The rails are addressed to the model

One guarantee is genuinely enforced by the server, and it is the important one: things created through the connector are created paused. The campaign-creation tool describes itself as creating a campaign in a paused state, and the ad-creation tool says the same about ads. That is a property of the connector rather than of how you prompt it, so it holds whichever client you run it from — and it is why drafting in a terminal is safe at all.

Almost everything else is prose. The account-listing tool instructs the model not to use an account whose enablement flag is false. The entity-reading tool states a precondition: confirm the account is queryable first, and if it is not, surface the reason instead of calling. Both rules are sensible. Both are sentences in a description.

A description is addressed to a model. A model can be talked out of things a server cannot.

The update tool makes the point sharply. It is the one that changes budgets, and its required parameters are an account, an entity, a type, and the fields to set. No confirmation parameter, no dry-run flag, nothing in the schema obliging a human to agree first. Budgets are expressed in the currency's minor unit too — cents, not dollars — so a figure that reads right at a glance is out by a factor of a hundred. In a chat window you see the proposal before saying yes. In an agent loop with tool calls pre-approved, nobody sees anything. Which actions you let run unattended is the whole question, and it sorts into four classes.

What goes wrong

  • Trusting the server list. An empty list does not mean the connector is missing, and an entry in it does not mean the authorisation is still good. Ask it for something and read what comes back.
  • Assuming your client's own instructions cover you. The connector's cautions live in tool descriptions. Whatever your coding agent has been told about working autonomously sits above them, not below.
  • Approving tool calls in bulk. The setting that makes a coding agent pleasant to use is exactly the one that removes the human from the budget path.
  • Pasting context you would not send to Meta. The request field is designed to carry your wording verbatim, and it generally will.

Try this tonight Before anything else, ask the connector in your terminal to list every ad account it can reach and report two flags for each: whether the connector is enabled on it, and whether it is queryable. One call, seconds. A row that comes back enabled but not queryable is the account that will fail later in a way that looks like your prompt's fault — that failure has its own post. A row that is not enabled at all sits behind a rollout gate that reconnecting will not shift. Either way you know which accounts are real before building on them.

Frequently asked questions

Does this work in Cursor and Codex as well?

The endpoint is the same and the tool surface belongs to the server, so there is no reason it would not. I have run it first-hand in Claude Code only, so I will not describe their config files as though I had.

Do I need a Meta developer app or an access token?

Not for the connector — you authorise in a browser and Meta handles the rest. A developer app is for the fallback path of talking to the Marketing API yourself, which is a different job.

Can it change budgets from a terminal session?

Yes. The update tool takes budget fields and nothing in its schema requires a confirmation. That discipline is yours to impose, and a coding agent is where it is easiest to forget.

Why doesn't it show up when I list MCP servers?

Because it probably arrived from your Claude account rather than a local install. Both routes work; only the local one appears in that list. Check whether the tools respond before concluding anything.

The connector is the easy half

Knowing what a tool call carries is worth more than knowing how to install it. The course is the operating routine around that — what to read, what to draft, and what never runs without you.

See what's inside — $67 founding price

Pre-sale: the modules are still being recorded and founding members get the checkout link first. No charge today. Public price $97.

Espen Opdahl Writes The Claude Ads Operator. I run Meta ad accounts through Claude and Meta's official ads connector, and I write down what actually happens — including the parts that don't work. Not affiliated with Meta or Anthropic.