LinkedIn Ads MCP server: give Claude your Campaign Manager data

linkedin-ads-mcp is an open-source MCP server for LinkedIn Campaign Manager, built by Walma. It reads accounts, campaigns, ads, performance and audience demographics, and can build campaigns as drafts that a person launches. How to get Advertising API access, set it up for Claude Code, Claude Desktop and Cursor, and what to ask it.

Walma Engineering·Updated 10 October 2026·8 min read

LinkedIn is where B2B budgets go when the buyer is a job title rather than a search query, and Campaign Manager is where the answers to "is it working?" sit: spend, leads, cost per lead, and which seniorities and company sizes actually responded. It is also a slow place to ask questions. linkedin-ads-mcp lets Claude, Cursor or any other MCP client read it, so "which campaign brought in leads from IT managers at companies over 200 people, and what did they cost?" becomes one question.

LinkedIn has no MCP server of its own, so we built one for our own ads and then for customers. The code is open source at github.com/Walma-Labs/linkedin-ads-mcp under the MIT licence. It is unofficial and not affiliated with LinkedIn.

What it can read

ToolWhat it returns
list_ad_accountsThe ad accounts your LinkedIn user has a role on, with currency, status, serving status (for example a billing hold) and your role
list_campaignsCampaigns and campaign groups with status, objective, daily and total budgets and bids
get_performanceImpressions, clicks, cost, landing page clicks, website conversions and Lead Gen Form leads, with CTR, CPC, CPM and cost per lead computed
compare_periodsTwo date ranges side by side with deltas, account-wide and per campaign
list_creativesThe ads in an account or campaign, with status and review state
search_targetingTargeting values: locations, job titles, seniorities, company sizes, industries and more

get_performance pivots by account, campaign group, campaign, ad or conversion, and by audience: job function, seniority, industry, company, company size, country and job title. That last group is the reason to use LinkedIn at all, and the server labels job functions and seniorities in plain words instead of urn:li:function:13. LinkedIn hides small audience segments for privacy, so demographic rows are approximate and do not always add up to the campaign total.

What it can build, and only as drafts

If you sign in with the rw_ads scope, four more tools appear: create_campaign_group, create_campaign, create_ad and delete_draft. The agent can then turn a brief into a campaign structure: look up the targeting with search_targeting, create the group and the campaigns with budgets, schedule and audience, and attach single-image ads with your copy and a landing page or a Lead Gen Form.

Everything it creates is a draft. There is no tool that activates, pauses or edits a live campaign, whatever the prompt says, and delete_draft refuses anything that is not a draft. A person opens Campaign Manager, reviews the drafts and launches them. No money can be spent from a chat.

Two LinkedIn rules are built in:

  • The EU political-ads statement. LinkedIn requires every campaign to declare whether it is political advertising and requires tools to show the advertiser the statement. create_campaign refuses until the user has confirmed that the ads are not political, and only then sends politicalIntent: NOT_POLITICAL.
  • Ads are posted as your company page. Sponsored Content is a post by the page linked to the ad account, created as a "dark" post that does not appear on the page's feed.

Setup

1. Get Advertising API access. Create an app at developer.linkedin.com, link it to your company page and request the Advertising API product. You describe your use case in a short form; approval for the Development tier usually takes a few days. Under Auth, add the redirect URL http://localhost:8790/callback. To build drafts, also add each ad account under Products → Advertising API (the Development tier allows five).

2. Make sure your user has a role. The server sees exactly the ad accounts your LinkedIn user has a role on in Campaign Manager: Viewer is enough to read, Campaign Manager or higher to build drafts.

3. Install. The package is not on npm yet, so clone and build it (Node 20 or newer):

git clone https://github.com/Walma-Labs/linkedin-ads-mcp.git
cd linkedin-ads-mcp
npm install

4. Sign in once. This opens LinkedIn in the browser and stores the token in ~/.config/linkedin-ads-mcp/token.json, readable only by you:

export LINKEDIN_CLIENT_ID=your-client-id
export LINKEDIN_CLIENT_SECRET=your-primary-client-secret
node dist/cli.js auth

# or, to allow draft building:
LINKEDIN_SCOPES='r_ads r_ads_reporting rw_ads' node dist/cli.js auth

5. Add it to Claude Code, with the absolute path to your clone:

claude mcp add linkedin-ads -s user \
  -e LINKEDIN_CLIENT_ID=your-client-id \
  -e LINKEDIN_CLIENT_SECRET=your-primary-client-secret \
  -- node /absolute/path/to/linkedin-ads-mcp/dist/cli.js

Claude Desktop and Cursor take the same thing as JSON, in claude_desktop_config.json or .cursor/mcp.json:

{
  "mcpServers": {
    "linkedin-ads": {
      "command": "node",
      "args": ["/Users/you/linkedin-ads-mcp/dist/cli.js"],
      "env": {
        "LINKEDIN_CLIENT_ID": "your-client-id",
        "LINKEDIN_CLIENT_SECRET": "your-primary-client-secret"
      }
    }
  }
}

Access tokens last 60 days and refresh automatically. The refresh token lasts 365 days and refreshing does not extend it, so put a reminder in the calendar to sign in again in a year. General client instructions are in our guides for Claude Code, Claude Desktop and Cursor.

What to ask it

  • "How did our LinkedIn campaigns do last month: spend, leads and cost per lead per campaign?"
  • "Compare September with August per campaign. Where did cost per lead move most?"
  • "Which seniorities and company sizes clicked on the AI Hub campaign, and which ones converted?"
  • "Which ads in the lead gen campaign have the best CTR, and which have been running for more than six weeks?"
  • "Is anything on billing hold or still in review?"
  • "Draft a lead gen campaign for IT managers and directors at Swedish companies with more than 200 employees, 400 SEK a day from the 20th."

The comparison questions are where it earns its keep alongside the other paid channels. Combine it with Google Ads, Google Analytics and HubSpot, and one session can follow a lead from the LinkedIn click to the deal and compare its cost with search.

Status and limits

linkedin-ads-mcp is in use on our own ad account. The read tools and the creation of campaign groups and campaigns as drafts have been run against the live Marketing API; create_ad has not yet been verified against a live account, so check the first draft ads in Campaign Manager. The code is covered by tests against mocked responses. Open an issue if anything does not match. Known limits:

  • Demographic pivots are approximate, because LinkedIn applies privacy thresholds and hides small groups.
  • create_ad makes single-image Sponsored Content. Lead Gen Forms, document ads, video and carousels are created in Campaign Manager; a form can then be attached to a draft ad by its ID.
  • LinkedIn retires each API version after about a year. The server pins one (LINKEDIN_API_VERSION) and is updated when it is sunset.
  • It reads advertising data only. Organic page posts, member profiles and messaging are out of scope, and so is anything LinkedIn's terms do not allow.

Running it for a team

A LinkedIn token reads every ad account its user has a role on, and with rw_ads it can build campaigns. On a laptop that is one leaked config file away from a problem, and each new colleague would need their own app access. The package also exports the server as a library for hosting centrally, with the credentials as environment variables and the draft tools off unless switched on, and it belongs behind a gateway that authenticates each user, keeps the credential out of their hands and logs every call.

That is how Walma runs it: inside the customer's own EU environment, connected once per organisation from the customer's own LinkedIn app, next to Google Ads, Google Analytics and Search Console for the marketing team. The connection is also listed in our MCP directory.

Frequently asked questions

Does LinkedIn have an official MCP server for ads?+

No. LinkedIn publishes the Marketing API (Advertising API) but no MCP server of its own. The options are third-party aggregators that route your ad data through their service, or a server you run yourself against your own developer app. linkedin-ads-mcp is the second kind: open source, and your token never leaves your machine or your own infrastructure.

What do I need to use the LinkedIn Ads MCP server?+

A LinkedIn developer app linked to your company page with the Advertising API product approved, the redirect URL http://localhost:8790/callback on the app, and a LinkedIn user with a role on the ad accounts you want to read. Approval for the Development tier usually takes a few days.

Can the LinkedIn Ads MCP server spend money?+

No. By default it only reads. If you sign in with the rw_ads scope it can also create campaign groups, campaigns and ads, but always as drafts, and there is no tool that activates, pauses or edits a live campaign. A person reviews the drafts in Campaign Manager and launches them there.

How do I add the LinkedIn Ads MCP server to Claude Code?+

Clone github.com/Walma-Labs/linkedin-ads-mcp, run npm install, sign in once with node dist/cli.js auth, then: claude mcp add linkedin-ads -s user -e LINKEDIN_CLIENT_ID=... -e LINKEDIN_CLIENT_SECRET=... -- node /absolute/path/to/linkedin-ads-mcp/dist/cli.js.

How long does the LinkedIn sign-in last?+

Access tokens last 60 days and the server refreshes them automatically. The refresh token lasts 365 days and refreshing does not extend it, so someone signs in again once a year.

Walma AI Hub

The same tools, in your EU region, under your control

A 20-minute walkthrough with an engineer. We map it to your tools, your MCP servers and your budget model.

About AI Hub