linkedin-ads-mcp
This server lets you connect an MCP-compatible AI client (like Claude) to LinkedIn Ads for account management, performance analytics, audience insights, conversions, lead gen, and public Ad Library research.
Account & campaign management: list/inspect ad accounts, create/update/delete campaign groups and campaigns, manage creatives, upload images, and create inline ads.
Performance & analytics: get campaign/creative performance, compare date ranges, view daily trends, and track impressions, clicks, spend, CTR, conversions, and engagement.
Audience & demographics: analyze performance by job function, seniority, industry, company size, region/country; view reach and audience penetration; list saved audiences.
Conversions & lead gen: list conversion rules, track conversion performance and value, list lead gen forms, and measure form submissions and qualified leads.
Ad Library research: search public LinkedIn ads from any advertiser with filters like country, date range, targeting, and impression volume.
LinkedIn Ads MCP
A Model Context Protocol (MCP) server for LinkedIn Ads. Connect Claude (or any MCP-compatible AI client) directly to your LinkedIn ad accounts to query performance, manage campaigns, analyse audiences, and search the public Ad Library — all in natural language.
The server speaks the MCP authorization spec (2025-06-18), so it works as a remote connector anywhere Claude supports custom MCP servers — claude.ai (personal), Claude Desktop, and Claude Teams. Add one URL, click "Connect", sign in with LinkedIn, done. For a Teams plan, the org owner adds the URL once and each member individually authenticates on first use.
What you can do
Account & Campaign Management
List and inspect ad accounts
Create, update, and delete campaign groups and campaigns
Manage creatives and update their status
Upload images and create inline ads
Performance & Analytics
Get campaign and creative performance metrics
Compare performance across date ranges
View daily trends
Analyse audience demographics and reach
Conversions & Lead Gen
Track conversion performance
View lead gen form submissions and performance
Ad Library (Public)
Search any advertiser's public LinkedIn ads
Filter by country, date range, targeting categories, impression volume
Useful for competitive research and creative inspiration
Related MCP server: ads-mcp
How auth works
There are two modes. Pick one.
Mode A — Local STDIO (one user, no server)
Use this if you only want it on your own machine. npm run auth runs the LinkedIn OAuth flow once and stores your token in ~/.linkedin-ads-mcp/tokens.json. Claude Desktop launches the server as a subprocess. No Firestore, no Cloud Run, no public URL.
Mode B — Remote HTTP server (Claude Teams, claude.ai, multi-user)
The MCP server is also an OAuth 2.1 authorization server. When Claude connects:
Claude discovers our metadata at
/.well-known/oauth-protected-resourceand/.well-known/oauth-authorization-server.Claude registers itself via Dynamic Client Registration (
POST /oauth/register).Claude redirects the user to
/oauth/authorize. We delegate identification to LinkedIn OAuth.After LinkedIn login, we issue our own opaque bearer token to Claude — LinkedIn credentials never leave the server.
On each
/mcprequest Claude sends our bearer; we map it server-side to the right user's stored LinkedIn credentials and call the LinkedIn Marketing APIs.
A note on access control. LinkedIn returns whatever email the account was registered with — usually personal (gmail, hotmail, etc.) rather than work email. Domain-based restriction therefore isn't reliable. By default this MCP allows any LinkedIn user to connect; the security comes from LinkedIn's own permission model (each user only sees ad accounts their LinkedIn profile has access to). For tighter control, set
ALLOWED_EMAILSto a comma-separated allow-list of LinkedIn-account emails.
Prerequisites
Node.js 18+
A LinkedIn Marketing Developer Platform-approved app
A Google Cloud project (Mode B only)
Step 1 — Create a LinkedIn Developer App
Go to LinkedIn Developer Portal and create an app (or use an existing one).
Under Products, request:
Sign In with LinkedIn using OpenID Connect (gives
openid emailfor user identification)Marketing Developer Platform (gives
r_ads,r_ads_reporting,rw_ads,r_organization_social,w_organization_social— required for the ads tools; access requires LinkedIn approval)
Under Auth → OAuth 2.0 settings → Authorized redirect URLs, add:
http://localhost:8080/oauth/callback(local dev)https://YOUR-CLOUD-RUN-URL/oauth/callback(Mode B — add after deploy)
Copy the Client ID and Client Secret — you'll need them in the env config below.
Step 2 — Install
git clone https://github.com/dhawalshah/linkedin-ads-mcp
cd linkedin-ads-mcp
npm install
cp .env.example .env # fill in valuesStep 3 — Mode A: Local STDIO
npm run auth # one-shot browser sign-in; saves token to ~/.linkedin-ads-mcp/tokens.json
npm run buildThen add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS):
{
"mcpServers": {
"linkedin-ads": {
"command": "node",
"args": ["/absolute/path/to/linkedin-ads-mcp/dist/index.js"],
"env": {
"LINKEDIN_CLIENT_ID": "your_client_id",
"LINKEDIN_CLIENT_SECRET": "your_client_secret"
}
}
}
}Restart Claude Desktop. You're done — skip the rest.
Step 3 — Mode B: Remote HTTP server (Claude Teams / claude.ai)
Enable Firestore
The server stores OAuth bearer tokens and per-user LinkedIn credentials in Firestore.
In Cloud Console, Firestore → Create database → Native mode, pick a region.
Grant the Cloud Run service account Cloud Datastore User role under IAM & Admin → IAM.
Deploy to Cloud Run
gcloud run deploy linkedin-ads-mcp \
--source . \
--region YOUR_REGION \
--project YOUR_PROJECT_ID \
--platform managed \
--port 8080 \
--allow-unauthenticated \
--set-env-vars "GCP_PROJECT_ID=your-project-id,BASE_URL=https://YOUR-SERVICE-URL.run.app,LINKEDIN_CLIENT_ID=...,LINKEDIN_CLIENT_SECRET=..."Recommended: store
LINKEDIN_CLIENT_SECRETin Secret Manager and inject via--set-secretsrather than as a plain env var.
After it's up, go back to the LinkedIn Developer Portal and add the live callback URL:
https://YOUR-SERVICE-URL.run.app/oauth/callbackConnect from Claude
Claude Teams (org owner adds it once for everyone):
Settings → Connectors → Add custom connector
URL:
https://YOUR-SERVICE-URL.run.app/mcpEach member clicks Connect, signs in with LinkedIn, done.
claude.ai personal:
Settings → Connectors → Add custom connector
URL:
https://YOUR-SERVICE-URL.run.app/mcp
Claude Desktop with a remote server:
{
"mcpServers": {
"linkedin-ads": {
"url": "https://YOUR-SERVICE-URL.run.app/mcp"
}
}
}Claude Desktop will run the OAuth dance the first time you use it.
Environment Variables
Variable | Required | Description |
| Yes | OAuth client ID from your LinkedIn app. |
| Yes | OAuth client secret from your LinkedIn app. |
| No | Override the LinkedIn callback URL. Defaults to |
| Mode B | Public URL of this service. Used for OAuth metadata and as the canonical resource URI tokens are bound to. |
| Mode B | GCP project hosting Firestore. |
| No | Comma-separated allow-list of LinkedIn-account emails. Empty = no restriction. |
| Mode A | Override the local token file path. Defaults to |
| Mode A | Inline JSON to seed local tokens (overrides the file). |
| No | HTTP port (default |
Available Tools
Account & Campaign Management
Tool | Description |
| List all accessible LinkedIn ad accounts |
| Account name, currency, status, and serving status |
| List campaigns for an account |
| List campaign groups |
| Manage campaign groups |
| Manage campaigns |
| Manage creatives |
| One-shot creative + campaign creation |
| Upload an image asset for use in creatives |
Performance & Analytics
Tool | Description |
| Impressions, clicks, cost, CTR, CPC, conversions per campaign |
| Performance metrics broken down by creative, including engagement and video metrics |
| Side-by-side comparison of two date ranges |
| Daily performance trend data |
Audience & Demographics
Tool | Description |
| Performance breakdown by demographic pivot (industry, seniority, function, etc.) |
| Reach and impression counts across an audience |
| List saved targeting audiences |
Conversions & Lead Gen
Tool | Description |
| All configured conversion actions |
| Conversion counts and value across campaigns |
| All Lead Gen forms on an account |
| One-click leads, form opens, qualified leads |
Ad Library (Public)
Tool | Description |
| Search any advertiser's public LinkedIn ads with filters |
Example Prompts
List my LinkedIn ad accounts
Show campaign performance for the last 30 days
Compare last week vs the week before for account 12345
Which industries are clicking most on campaign X?
What did my top creative drive in conversions last month?
Search the LinkedIn Ad Library for ads from Stripe in the US in 2026OAuth endpoint reference (Mode B)
For developers who want to verify the implementation or write their own MCP client.
Endpoint | Spec | Purpose |
| RFC 9728 | Advertises the canonical resource URI and authorization server. |
| RFC 8414 | Authorization server metadata. |
| RFC 7591 | Dynamic Client Registration. |
| OAuth 2.1 | Starts the auth code flow with PKCE; redirects to LinkedIn. |
| — | LinkedIn redirects here; we mint our authorization code and bounce back to the MCP client. |
| OAuth 2.1 | Authorization code + refresh token grants. |
A GET /mcp without a valid bearer returns 401 with a WWW-Authenticate: Bearer resource_metadata="…" header pointing at the protected-resource metadata document, which is how a standards-compliant MCP client discovers the rest.
PKCE caveat: LinkedIn's OAuth implementation does not support PKCE on the upstream side, so PKCE is only enforced on the Claude → us channel. The us → LinkedIn channel uses a
stateparameter for CSRF protection.
Tech Stack
TypeScript + Node 18+
@modelcontextprotocol/sdk — MCP server framework
Express — HTTP server
@google-cloud/firestore — per-user token storage and OAuth-server state (Mode B)
Google Cloud Run — Serverless hosting
About Dhawal Shah
I run a 40-plus person digital marketing agency out of Singapore, and I build the automation my own teams use. This server is one of those tools rather than a weekend project: it runs against live LinkedIn Ads accounts every week, which is why the read-only surface is wide and the write surface is deliberately narrow.
Fourteen years building companies across Asia behind it. 5,000+ campaigns, 400+ brands, 30+ startups advised, and 300+ training sessions for teams including Sony, Toyota, DHL and Interpol. I am also an Accredited Director with the Singapore Institute of Directors, which in practice means I get asked what breaks, who is accountable and what it costs before anyone asks what it can do.
I write up the routines and agents I actually run at dhawalshah.net.
Worth reading alongside this repo: Google Ads, Meta, LinkedIn & TikTok MCPs for Claude: Agency Setup Guide.
License
MIT
Available Tools
25 toolscompare_performanceA
Compares performance between two time periods, campaigns, or campaign groups. Calculates percentage changes and highlights significant differences. Essential for reporting on performance trends.
Inputs: periodA (required), periodB (required), accountId (required), comparisonType (required).
create_campaignB
Creates a new LinkedIn ad campaign within a campaign group. Requires targeting criteria, budget, and objective type.
Inputs: name (required), accountId (required), objectiveType (required), unitCostAmount (required), +18 more.
create_campaign_groupA
Creates a new LinkedIn campaign group for organizing campaigns. Campaign groups manage status, budget, and performance across multiple related campaigns.
Inputs: name (required), accountId (required), startDate (required), status, +6 more.
create_creativeB
Creates a new LinkedIn creative/ad under a campaign. Requires a content reference (post/share URN) or will be created as a reference to existing content.
Inputs: accountId (required), campaignId (required), contentReference (required), name, +3 more.
create_inline_adA
Creates a new LinkedIn ad with inline content directly (without needing a pre-existing post). This creates the ad content (text, image/video, landing page, CTA) and the creative in a single call. Use this to create sponsored content ads from scratch.
Inputs: accountId (required), campaignId (required), commentary (required), organizationId (required), +8 more.
delete_campaignA
Deletes a LinkedIn campaign. Draft campaigns are deleted immediately. Non-draft campaigns are set to PENDING_DELETION status.
Inputs: accountId (required), campaignId (required).
delete_campaign_groupA
Deletes a LinkedIn campaign group. Draft groups are deleted immediately. Non-draft groups are set to PENDING_DELETION status.
Inputs: accountId (required), campaignGroupId (required).
get_account_detailsA
Retrieves detailed information about a specific LinkedIn Ad Account including status, currency, notification settings, and linked organization.
Inputs: accountId (required).
get_audience_demographicsB
Retrieves demographic breakdown of who saw or interacted with your ads. Shows performance segmented by job function, seniority, industry, company size, or geographic location. Essential for understanding if you're reaching your target audience. Note: Demographic data has a 12-24 hour delay.
Inputs: accountId (required), startDate (required), demographicType (required), limit, +3 more.
get_audience_reachA
Shows unique member reach and native audience penetration for campaigns. Returns LinkedIn's native audiencePenetration metric (approximate unique members reached / total target audience size). Helps understand what percentage of your target audience you've reached. Note: Date range must be 92 days or less.
Inputs: accountId (required), startDate (required), endDate, campaignIds, +1 more.
get_campaign_groupsC
Lists all campaign groups for an account with their configuration and optionally aggregated performance. Campaign groups help organize campaigns and control budget at a higher level.
Inputs: accountId (required), status, endDate, startDate, +1 more.
get_campaign_performanceA
Retrieves performance metrics for campaigns within a specified date range. Returns key metrics like impressions, clicks, spend, CTR, conversions, audience penetration, and average dwell time. The primary tool for daily campaign monitoring and optimization decisions.
Inputs: accountId (required), startDate (required), endDate, campaignIds, +2 more.
get_conversion_performanceA
Retrieves conversion metrics broken down by conversion type/action. Shows which conversions are being driven by which campaigns, with cost per conversion and conversion value.
Inputs: accountId (required), startDate (required), endDate, campaignIds, +2 more.
get_creative_performanceA
Retrieves performance metrics for individual ad creatives. Shows which specific ads are performing best, including engagement metrics (likes, comments, shares), video metrics, and average dwell time. Essential for creative optimization.
Inputs: accountId (required), startDate (required), endDate, campaignIds, +3 more.
get_daily_trendsB
Retrieves daily performance trends over a specified period. Returns time-series data for visualizing performance patterns, identifying anomalies, and understanding day-of-week effects.
Inputs: accountId (required), startDate (required), endDate, metrics, +2 more.
get_lead_gen_performanceB
Retrieves lead generation form performance including form submissions, qualified leads, and cost per lead. Essential for B2B marketers running lead gen campaigns.
Inputs: accountId (required), startDate (required), endDate, campaignIds, +1 more.
list_ad_accountsA
Lists all LinkedIn Ad Accounts accessible to the authenticated user. Returns account names, IDs, status, currency, and serving statuses. Use this to get an overview of all accounts or find a specific account ID.
Inputs: type, status, includeTest.
list_campaignsA
Lists campaigns for a LinkedIn Ad Account. Unlike get_campaign_performance (which only returns campaigns with analytics data), this tool returns ALL campaigns including DRAFT and PAUSED campaigns with zero impressions. Supports filtering by campaign group and status.
Inputs: accountId (required), status, campaignGroupIds.
list_conversionsA
Lists all conversion tracking rules configured for an account. Shows conversion names, types, attribution windows, and enabled status.
Inputs: accountId (required), enabledOnly.
list_lead_formsA
Lists all lead generation forms configured for an account with their questions and settings. Helps understand what forms are available and their configuration.
Inputs: accountId (required), status, includeQuestions.
list_saved_audiencesA
Lists saved/matched audiences available in the account for targeting. Shows audience names, sizes, and statuses to help plan campaign targeting.
Inputs: accountId (required), status, audienceType.
update_campaignA
Updates an existing LinkedIn campaign. Can change status (ACTIVE/PAUSED/ARCHIVED), budget, name, targeting, bid amount, and other settings. Uses partial update - only specified fields are changed.
Inputs: accountId (required), campaignId (required), name, status, +11 more.
update_campaign_groupA
Updates an existing LinkedIn campaign group. Can change status (ACTIVE/PAUSED/ARCHIVED/DRAFT), budget, name, or end date.
Inputs: accountId (required), campaignGroupId (required), name, status, +3 more.
update_creative_statusB
Updates the intended status of a LinkedIn creative/ad. Can activate, pause, or archive creatives.
Inputs: accountId (required), creativeId (required), intendedStatus (required).
upload_imageA
Uploads an image file to LinkedIn for use in ads. Supports PNG, JPG, and GIF formats. Returns the image URN that can be used as the mediaId when creating inline ads. The image is uploaded in two steps: initialize upload (get URL + URN), then upload binary.
Inputs: filePath (required), organizationId (required), accountId, assetName.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 25 tools
Most tools target clearly distinct resources and actions—accounts, campaigns, campaign groups, creatives, audiences, conversions, lead forms, and analytics. The main possible confusion is between create_creative and create_inline_ad, but the descriptions clarify that one references existing content while the other creates content inline; list_campaigns and get_campaign_performance are also explicitly differentiated.
Tool names generally follow a consistent snake_case verb_noun pattern with clear verbs like list, get, create, update, delete, compare, and upload. Minor inconsistencies exist, notably get_campaign_groups is a listing operation while parallel resources use list_, and get_daily_trends/compare_performance use metric-style names rather than resource-object names.
At 25 tools, the surface is on the heavy side for an MCP server. Most tools serve a distinct aspect of LinkedIn ads management, but the number of separate performance/analytics tools and creative-creation variants pushes it into the borderline heavy range.
The server covers the core campaign and creative lifecycle plus performance analytics well, but notable gaps remain: there is no list/get creatives tool, no video upload despite inline ad support mentioning video, and no create/update for lead forms, conversions, or audiences. These gaps require external workarounds for some common workflows.
Maintenance
Related MCP Connectors
LinkedIn Ads MCP server: run LinkedIn campaigns, ad groups, ads and reports from AI.
1Hosted MCP server for Google Ads and LinkedIn Ads analysis.
Hosted LinkedIn Ads MCP server, with each action switched on or off per account.
Managed LinkedIn MCP server for AI agents: search, connect, message and enrich on accounts you own.
Related MCP Servers
- AlicenseBqualityDmaintenanceAn MCP server that connects Claude to the LinkedIn Ads API for natural-language control over campaign management, audience targeting, creative uploads, analytics, and account auditing.376 npmMIT
- AlicenseNot gradedqualityDmaintenanceUnified MCP server for managing Meta Ads, LinkedIn Ads, Google Ads, GA4, and Search Console with 89 read/write tools, multi-account support, OAuth setup, and safe dry-run mutations.MIT
- AlicenseBqualityBmaintenanceA read-only MCP server for LinkedIn Ads that enables users to query ad accounts, campaigns, creatives, insights, and company intelligence via natural language.17350 PyPIMIT
- FlicenseNot gradedqualityDmaintenanceMCP server for posting and managing LinkedIn content, supporting personal and company accounts. Deployed on Cloudflare Workers with token management via KV.-