Skip to main content
Ads — read 20 September 2026

LinkedIn Ads MCP Server

Campaign Manager through LinkedIn's official Marketing API, on an OAuth app you register yourself: reporting over your own ad accounts, and a write half that can change budgets and delete campaigns in a live account with no preview step. OAuth 2.0 against LinkedIn's Marketing API, under a developer app you register yourself. No cookie, no scraping, no browser session.

OAuth 2.0Medium account riskStale
Last read
✓ Read from the repository, not from a directory listing✓ Write actions separated from read actions✓ Status derived from the last code change, not the maintainer's word✓ Every source URL published below
25 tools registered
10 write to LinkedIn
34 GitHub stars, 20 September 2026
4 clients documented
Where it fits

What it is built for, and the jobs it cannot do

The second card is the one a repository README never contains. Both are written from the project's own documentation and source, read on 20 September 2026.

Use it for

Teams running LinkedIn Campaign Manager who want natural-language reporting over their own ad accounts — spend, click-through rate, cost per lead, demographics by job function and seniority, period-over-period comparisons — and, if they accept the risk, campaign and creative changes without opening Campaign Manager.

Do not use it for

Anything to do with a personal LinkedIn profile or organic LinkedIn: no profile lookup, no search, no connection requests, no messaging or InMail, no post publishing, no Sales Navigator, no Recruiter, no lead data. It cannot be used without an approved Advertising API app, so it is no help to anyone who just wants to read profiles.

Publisher
Daniel Popa, performance marketing consultant, working solo — not affiliated with LinkedIn or Microsoft.
Licence
MITopen source
Version
1.0.0
Runs
Either
Transport
stdio
Homepage
adplug.app
Last read

Hosting and transport are as the project documents them: Self-hosted from source, or the author's hosted connector AdPlug, which does the OAuth for you and needs no developer app of your own.

Authentication — the thing that decides everything else

OAuth 2.0 against LinkedIn's Marketing API, under a developer app you register yourself. No cookie, no scraping, no browser session.

LinkedIn's own OAuth, against a developer app you register. The sanctioned route.

What this route cannot do, however well the server is written

It cannot search people or read another member’s profile: no permission on LinkedIn’s self-serve list grants either. Three permissions are self-serve — sign-in, email and posting on your own behalf. Everything else is approval-gated, and the Sales Navigator API is not accepting new partners.

Medium account risk

The account is exposed in one direction. Either the server reads LinkedIn automatically without writing anything, which the User Agreement prohibits but which produces no activity anyone can report; or it writes through the approved API, where the exposure is what gets published rather than whether the account survives.

What it does with the credential

You supply a client id and secret from a LinkedIn developer app you create. The README states the prerequisites: a LinkedIn Company Page to create the app at all, the Advertising API product requested and approved on the app (the README says approval takes one to five days), and a localhost redirect URL added on the Auth tab. Scopes are r_ads, r_ads_reporting, rw_ads and r_organization_social. An auth command opens the browser, completes the flow and writes a token file in your home directory; tokens last 60 days and refresh themselves. The token file is written with 0600 permissions inside a 0700 directory.

Account risk is derived from the authentication class and from whether the server writes to LinkedIn — not judged per project. The 5 classes and the rule that maps them are on the LinkedIn MCP server directory; the ceilings LinkedIn enforces on any account, automated or not, are on LinkedIn limits. What this particular server exposes, and what it does with your credentials, is below.

Exposed tools

10 of its 10 write actions land on LinkedIn under your own account

These are the tool names the server registers, as a client sees them. An assistant can call any tool the server exposes once it is connected, so the list below is the whole surface, not a feature summary.

  • list_ad_accounts
  • get_account_details
  • get_campaign_performance
  • get_creative_performance
  • get_campaign_groups
  • list_campaigns
  • get_audience_demographics
  • get_audience_reach
  • list_saved_audiences
  • get_conversion_performance
  • list_conversions
  • get_lead_gen_performance
  • list_lead_forms
  • compare_performance
  • get_daily_trends
  • create_campaign_group
  • update_campaign_group
  • delete_campaign_group
  • create_campaign
  • update_campaign
  • delete_campaign
  • create_creative
  • create_inline_ad
  • update_creative_status
  • upload_image

All 25 tools it registers are named above.

What it can read

10 read actions, written as what they return rather than as the tool signature.

  • List every accessible LinkedIn ad account, and read one account's configuration.
  • Campaign performance, including audience penetration and average dwell time.
  • Ad-level metrics, engagement and video statistics.
  • Campaign groups with aggregated performance, and every campaign including drafts and paused ones.
  • Performance broken down by job function, industry, seniority, company size, country and region.
  • Unique member reach, frequency and native audience penetration.
  • Matched and lookalike saved audiences.
  • Conversion metrics by conversion action, and the conversion tracking rules themselves.
  • Lead form submissions, cost per lead, and the lead-gen form configurations.
  • Compare metrics between time periods or entities, and read daily time series.

What it can write, and where the write lands

10 of the 10 write actions land on LinkedIn itself. Those are the rows that carry the account risk: an automated message, invitation, post or campaign change is activity under your own name, and Section 8.2 of the User Agreement bars sending it by automated means. Section 8.2 of the User Agreement ↗

ActionWhere it landsWhat it does
create_campaign_groupYour LinkedIn accountCreates a campaign group in a live ad account.
update_campaign_groupYour LinkedIn accountChanges a group's status, budget, name or end date.
delete_campaign_groupYour LinkedIn accountDeletes a campaign group. There is no undo from the caller's side.
create_campaignYour LinkedIn accountCreates a campaign with targeting, budget and objective.
update_campaignYour LinkedIn accountChanges a campaign's status, budget, targeting or bid.
delete_campaignYour LinkedIn accountDeletes a campaign. There is no undo from the caller's side.
create_creativeYour LinkedIn accountCreates a creative from an existing post or share.
create_inline_adYour LinkedIn accountCreates an ad with inline text, image and call to action in one call.
update_creative_statusYour LinkedIn accountActivates, pauses or archives a creative.
upload_imageYour LinkedIn accountUploads a local image file to LinkedIn for use in ads. See the security note: the file path is caller-controlled and unconfined.

Read the middle column before the third. A write that lands off LinkedIn — a vendor workspace, a CRM, a local file — is undone by deleting a row. A write that lands on LinkedIn has already been seen by another member.

Setup — moderate

Installing it, in the project's own commands

Every command and every configuration block below is the project's own, copied unchanged on 20 September 2026. Where a project publishes no config block, this page says so rather than composing one — a snippet written here would be a snippet the maintainer never tested.

From source

Shell
git clone https://github.com/danielpopamd/linkedin-ads-mcp.git
cd linkedin-ads-mcp
npm install
npm run build
cp .env.example .env

Then put the client id and secret in .env.

Authorise

Shell
npm run auth

Opens the browser and completes the OAuth flow. Requires the Advertising API product to be approved on the app first.

The configuration block

Client config keys are not interchangeable, and a block pasted under the key a different client expects fails silently rather than erroring. That is why the blocks below are the project's own, in the clients it names, rather than one block normalised here.

Local build

claude_desktop_config.json
JSON
{
  "mcpServers": {
    "linkedin-ads": {
      "command": "node",
      "args": ["/full/path/to/linkedin-ads-mcp/dist/index.js"],
      "env": {
        "LINKEDIN_CLIENT_ID": "your_client_id",
        "LINKEDIN_CLIENT_SECRET": "your_client_secret"
      }
    }
  }
}
What it needs before it will start

Node.js 18 or newer and a local TypeScript build; the config points at the built output. No Docker, no headless browser, no paid third-party API key, no database. The real gate is on LinkedIn's side: a LinkedIn Company Page, a developer app with the Advertising API product approved, and an ad account with data in it. The hosted route instead requires an AdPlug account.

Clients the project documents

Claude Desktop — the only client the README gives a config block for; Claude Code — the README ships a copy-paste install prompt for it; Any MCP client that speaks stdio; ChatGPT and Cursor are named in the repository description and the hosted tip, with no setup instructions in this repository. Where the file goes in each Claude surface. The same block in Cursor. What a ChatGPT connector can and cannot reach.

How it talks to the client

stdio for the self-hosted server. The hosted variant is listed in the MCP registry as streamable-http.

Where the process runs

Self-hosted from source, or the author's hosted connector AdPlug, which does the OAuth for you and needs no developer app of your own.

What it costs to run

The vendor's own figures, quoted rather than computed

The self-hosted server is free and MIT-licensed; you pay only LinkedIn ad spend. The README says of the hosted sibling that "Read tools are free; every write is previewed before it runs. This open-source server stays free and self-hosted." AdPlug's price for write access is not stated in the repository and was not verified.

Sales Navigator — Not supported

No Sales Navigator functionality.

Recruiter — Not supported

No LinkedIn Recruiter functionality.

None of the figures above are LinkedIn's. They are third-party prices in the currency and the tiering each project publishes, read on 20 September 2026 and quoted rather than converted.

Repository signals, read 20 September 2026

Nobody has changed the code in months

198 days between the last code change and the day these figures were read. Between 90 days and a year since the last code change. It may still work; nobody has checked.

How far the project has got

Solo-maintainer project. First commit January 2026, seven commits on main, no tests, no CI, no changelog. Published to the official MCP registry in September 2026. The recent pushes are documentation pointing at the author's commercial hosted product; the code itself has not moved since March 2026 and three issues sit unanswered.

How this status was decided

Active means code changed within 90 days of the observation date; stale means up to 365 days. It is measured from the last change to code, not to the README, and never from the maintainer's own adjective. Anything past a year is dropped from this directory rather than published as dormant.

Stars
34 — 11 forks, 0 watchers.
Last commit
— Both September commits are README-only.
Last code change
— the commits after it did not change code, which is why the status below is measured from here and not from the commit above.
Open issues
3 — The API's open_issues_count of 4 includes an open pull request. None of the three has a visible maintainer reply.
Status
Stale
Observed

Every figure in this section was read from GitHub on , and star and issue counts move daily. The issue count is the Issues tab, not the API field of the same name — that one counts pull requests as issues and overstates every repository in this directory.

Credential handling and known problems

What to check before you point it at a real account

Both cards below are read from the repository and its own security documentation. A project saying what it does with a session is evidence of intent, not proof of behaviour.

What running it exposes

No personal-account risk of the usual kind: this server never touches a personal profile, never drives a logged-in session, and asks for no session cookie. Everything goes through LinkedIn's official Marketing API under an OAuth app you own, so there is no scraping exposure and no account-ban exposure. The risk is money and blast radius instead. With the rw_ads scope the model can create, edit, pause and delete live campaigns, campaign groups and creatives, and change budgets and bids, in an account that is spending. In the self-hosted code there is no confirmation prompt, preview or dry run before a write executes, and the two delete tools have no undo from the caller's side. The "every write is previewed before it runs" promise applies to the hosted connector, not to this repository. Anyone pointing a model at a live ad account should treat the rw_ads scope as a spend authorisation.

How it handles your credentials

An open, unfixed vulnerability report: issue #5, "Arbitrary File Read Vulnerability in linkedin-ads-mcp", filed 12 July 2026 and still open on 20 September 2026 with no maintainer reply. The image-upload tool takes a caller-controlled absolute file path and passes it straight through, with no directory confinement and no type validation, so any file the server process can read can be pulled and uploaded to LinkedIn. The reporter scores it CVSS 8.2 and includes a proof of concept. This matters most where a model can be prompt-injected into calling the tool. Separately, the client secret is stored in plaintext in the client config env block, and OAuth tokens are written as plain JSON to a file in your home directory, though with 0600 and 0700 permissions.

2 things that will waste an hour

Small, checkable and specific to this project — a stale package name, a broken link, a manifest that advertises something the code removed.

  • The last functional code change was March 2026; the September commits changed only the README, which is why the status here reads stale rather than active.
  • Three open issues, none answered: an arbitrary file read, a 422 on one campaign objective, and demographic results returned as URNs rather than names.
If this is not the one

The registry names no comparable server for this one

Nothing else in the directory covers the same ground closely enough to stand in for it. The other 12 are on the directory, grouped by what they authenticate with.

Nothing in this directory replaces it. The directory lists all 13, and 7 more were researched and left out with the rule each one failed.

Provenance

Every page this profile was read from

8 pages — the repository, its documentation and, where one exists, the vendor's own pricing page. Nothing on this profile is summarised from another directory or from a blog post about the project.

All of them read on . A repository moves faster than a price does: if a tool list or a command here no longer matches the project, the project changed and this page has not been re-read yet.

Where to next

Read the write table before you connect it

10 of this server's actions land on LinkedIn under your own account, on a oauth 2.0. That is medium account risk, and the account is what enforcement acts on.