Connects Claude to the LinkedIn Campaign Manager API with seven production-tested tools for managing ad accounts. You get read-only access by default (campaigns, campaign groups, account analytics, flexible pivot reporting by demographics or device) with an opt-in write flag for mutations. Ships with OAuth handling, automatic retry on rate limits, and multi-account support. Notable detail: CTR calculations use landingPageClicks instead of total clicks to exclude social engagement inflation. Built by someone running active campaigns across multiple clients, so it handles real production scenarios like token refresh and response truncation. Pair it with the same author's Bing Ads server if you're managing cross-platform campaigns.
Production-grade MCP server for LinkedIn Campaign Manager API. Enables Claude to manage LinkedIn ad accounts, campaigns, ad sets, and creatives with full read/write support.
Features:
Stats:
landingPageClicks (not total clicks with engagement)npm install mcp-linkedin-ads
Security: Never share your .mcp.json file or commit it to git -- it may contain API credentials. Add .mcp.json to your .gitignore.
Get OAuth credentials:
r_ads, rw_ads, w_member_social, r_organization_social, w_organization_socialCreate config.json:
cp config.example.json config.json
Fill in your credentials:
{
"oauth": {
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET"
},
"clients": {
"default": {
"account_id": "YOUR_AD_ACCOUNT_ID",
"name": "My Account"
}
}
}
Set environment variables (recommended for production):
export LINKEDIN_ADS_CLIENT_ID="your_client_id"
export LINKEDIN_ADS_CLIENT_SECRET="your_client_secret"
export LINKEDIN_ADS_ACCESS_TOKEN="your_access_token"
| Variable | Required | Default | Purpose |
|---|---|---|---|
LINKEDIN_ADS_CLIENT_ID | yes | -- | OAuth client ID |
LINKEDIN_ADS_CLIENT_SECRET | yes | -- | OAuth client secret |
LINKEDIN_ADS_ACCESS_TOKEN | yes | -- | OAuth access token |
LINKEDIN_ADS_REFRESH_TOKEN | optional | -- | OAuth refresh token (rotated automatically when set) |
LINKEDIN_ADS_MCP_WRITE | optional | false | Set to true to expose mutating tools. Read-only by default. |
The LinkedIn Ads MCP currently ships with read-only tools only. The write-mode
gate is already in place so that any future create/update/pause/enable/remove
tool is hidden from ListTools and refused at call time unless
LINKEDIN_ADS_MCP_WRITE=true is set in the MCP server environment. This
mirrors the Google Ads MCP gate and matches the pattern being rolled out to
Bing / Reddit / Meta. Motivation: prevent a casual LLM request from mutating
production ad accounts without the operator explicitly opting in.
npm start
Add to ~/.claude.json:
{
"mcpServers": {
"linkedin-ads": {
"type": "http",
"url": "http://localhost:3001"
}
}
}
Claude Desktop: Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows).
// Get client context
linkedin_ads_get_client_context({ working_directory: "/path/to/project" })
// List campaigns
linkedin_ads_list_campaigns({ account_id: "511664399" })
// Get campaign performance
linkedin_ads_campaign_performance({
start_date: "2026-01-01",
end_date: "2026-03-31",
time_granularity: "MONTHLY"
})
// Flexible analytics (e.g. by seniority)
linkedin_ads_analytics({
start_date: "2026-03-01",
end_date: "2026-03-31",
pivot: "MEMBER_SENIORITY"
})
landingPageClicks (LP clicks), NOT clicks (total clicks)DRAFT — Not yet activeACTIVE — Actively servingPAUSED — Paused manuallyARCHIVED — Historical recordflexible_spec array (OR logic between items)exclude_spec arraynpm run dev # Run in dev mode (tsx)
npm run build # Compile TypeScript
npm test # Run contract tests
Files:
src/index.ts — MCP server, OAuth flow, tool handlerssrc/tools.ts — Tool schema definitionssrc/errors.ts — Error handling & classificationconfig.json — Credentials & client mappingError Handling:
src/tools.tssrc/index.ts tool dispatch.contract.test.tsnpm test -- --run # Single run
npm test -- --watch # Watch mode
Config file not foundcp config.example.json config.json
# Fill in your OAuth credentials and account IDs
Missing required credentialsCheck that:
LINKEDIN_ADS_CLIENT_ID and LINKEDIN_ADS_CLIENT_SECRET are set (or in config.json)config.json exists and contains at least one client with account_idRate limit exceededLinkedIn enforces strict rate limits. The server includes automatic retry with exponential backoff. If you hit limits:
CTR seems too lowVerify you're using landingPageClicks (LP clicks), not clicks (all interactions). The latter includes social engagement and will inflate CTR incorrectly.
MIT
Contributions welcome! Please:
docs/ folder for detailed API referenceMark Harnett — Demand generation leader and paid media practitioner building AI-powered ad management tools. This server was born from managing LinkedIn campaigns across multiple clients and wanting Claude to handle campaign ops, performance analysis, and bulk creative updates autonomously.
Built with production workloads in mind: resilient API calls (circuit breakers, retry with backoff, response truncation), accurate CTR calculation (landing page clicks, not total clicks), and multi-account support.
Also by Mark: mcp-bing-ads -- Bing/Microsoft Ads MCP server with 10 tools.
Last Updated: 2026-03-13
LINKEDIN_CLIENT_ID*LinkedIn OAuth app client ID
LINKEDIN_CLIENT_SECRET*secretLinkedIn OAuth app client secret
LINKEDIN_ACCESS_TOKEN*secretLinkedIn OAuth access token
io.github.infoinlet-marketplace/mcp-observability
betterdb-inc/monitor
com.mcparmory/datadog
thotischner/observability-mcp
io.github.tantiope/datadog-mcp
io.github.us-all/datadog