flin-linkedin-ads-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@flin-linkedin-ads-mcplist my LinkedIn ad accounts"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
flin-linkedin-ads-mcp
flin-linkedin-ads-mcp ist ein strikt read-only MCP Server für LinkedIn Ads.
Er ist dafür gebaut, direkt in Claude über MCP eingebunden und getestet zu werden.
Features
Read-only Zugriff auf LinkedIn Ads Daten
Ad Accounts lesen
Campaign Groups lesen
Campaigns lesen
Creatives lesen
Share-Content lesen (
get_share_content, best effort für Bild-URLs)Insights/Analytics lesen
Company Intelligence lesen (
/accountIntelligence, private API Access nötig)Keine Schreiboperationen in
v0.1.x
Related MCP server: linkedin-campaign-manager-mcp
Scope v0.1.x (strict read-only)
Kein Create/Update/Delete
Kein Pause/Resume
Kein generischer Proxy-Endpunkt
Kein eingebauter OAuth-Refresh-Flow im MCP selbst
Direkt in Claude testen
Variante A: Lokal aus diesem Repo (empfohlen zum Entwickeln)
In Claude:
SettingsöffnenDeveloperöffnenMCP Config bearbeiten
Diesen Server eintragen:
{
"mcpServers": {
"flin-linkedin-ads-mcp-local": {
"command": "uv",
"args": [
"run",
"--directory",
"/Users/nicolasg/Antigravity/flin-linkedin-ads-mcp",
"flin-linkedin-ads-mcp"
],
"env": {
"LINKEDIN_ACCESS_TOKEN": "AQX...",
"LINKEDIN_API_VERSION": "202603",
"LINKEDIN_RESTLI_PROTOCOL_VERSION": "2.0.0"
}
}
}
}Danach Claude neu starten.
Variante B: Via uvx (wenn Paket publiziert ist)
{
"mcpServers": {
"flin-linkedin-ads-mcp": {
"command": "uvx",
"args": ["--refresh", "flin-linkedin-ads-mcp"],
"env": {
"LINKEDIN_ACCESS_TOKEN": "AQX...",
"LINKEDIN_API_VERSION": "202603",
"LINKEDIN_RESTLI_PROTOCOL_VERSION": "2.0.0"
}
}
}
}2-Minuten Smoke Test in Claude
Nach dem Restart in Claude diese Calls testen:
list_ad_accountslist_campaignsget_insightsmitpivot=campaign
Wenn list_campaigns eine Auswahl zurückgibt, den Call mit einem vorgeschlagenen ad_account_id wiederholen.
Hinweis zu get_insights:
Der MCP nutzt den LinkedIn
analyticsFinder mit Single-Pivot.Implementierung ist auf die Dokumentation
view=li-lms-2026-03ausgerichtet.date_fromist Pflicht (LinkedInadAnalyticserwartetdateRange).Unterstützte
fieldsfolgen der Metrics-Tabelle aus der offiziellen Reporting-Schema-Doku (max. 20 Felder pro Request).Der Server nutzt intern
pivot.value/timeGranularity.valueund hat zusätzlich einen Fallback auf Legacy-Parameternamen für bessere API-Kompatibilität.Neuere Video/Event-Felder sind enthalten, z. B.
videoWatchTime,averageVideoWatchTime,eventViews,eventWatchTime,averageEventWatchTime.
Beispiel für einen stabilen Test-Call:
{
"ad_account_id": "508834004",
"date_from": "2025-08-01",
"date_to": "2025-12-31",
"fields": [
"impressions",
"clicks",
"costInLocalCurrency",
"dateRange"
],
"pivot": "account",
"time_granularity": "MONTHLY"
}get_insights Parameter (2026-03)
Wichtigste Parameter:
pivot: z. B.account,campaign_group,campaign,creative,member_company_size,member_industry,member_seniority,member_job_title,member_job_function,member_country_v2,member_region_v2,member_company,member_county,share,company,conversiontime_granularity:DAILY,MONTHLY,ALL,YEARLYfields: Liste aus der offiziellen Metrics-Tabelle, maximal 20 Einträge, case-sensitiveKompatibilitätsfelder:
pivotValue→pivotValues,clickThroughRate(berechnet alsclicks / impressions),costPerClick(berechnet alscostInLocalCurrency / clicks)
date_from:YYYY-MM-DD(Pflicht)date_to: optional,YYYY-MM-DD
Facets/Filter:
ad_account_id(ein Konto) oderaccount_ids(mehrere Konten)optional zusätzlich:
campaign_ids,campaign_group_ids,creative_ids,share_ids,company_idsoptional:
campaign_type,objective_typeoptional Sortierung:
sort_by_field+sort_order(müssen zusammen angegeben werden)
Kompatibilität:
entity_idsbleibt für Backward-Kompatibilität erhalten (z. B. beipivot=campaign).
list_creatives / get_creative Bild-URL (optional)
Für Creative-Calls kann optional das Derived-Field imageUrl in fields angefordert werden.
imageUrlwird bevorzugt direkt aus dem Creative-contentextrahiert.Falls dort keine Bild-URL enthalten ist und eine
content.referenceaufurn:li:adDirectSponsoredContent:*zeigt, versucht der MCP zusätzlich eine Auflösung überadDirectSponsoredContents/{urn}.Falls dort keine Bild-URL enthalten ist und eine Share-Referenz vorhanden ist, versucht der MCP zusätzlich eine Auflösung über die referenzierte Share/Post-Entity.
Wenn keine Bild-URL auflösbar ist, ist
imageUrlnull.
Beispiel:
{
"ad_account_id": "508834004",
"id": "urn:li:sponsoredCreative:935973186",
"fields": ["id", "name", "imageUrl"]
}list_account_intelligence (202603)
Neues Tool:
list_account_intelligence
Dieser Endpunkt nutzt GET /rest/accountIntelligence?q=account und ist laut LinkedIn private API (zusätzliche Freischaltung erforderlich).
Wichtige Parameter:
ad_account_id(oder Auto-Resolve bei genau einem Account)lookback_window:LAST_7_DAYS,LAST_30_DAYS,LAST_60_DAYS,LAST_90_DAYSoptional:
ad_segment_ids,campaign_idoptional:
skip_company_decorationoptional:
page_start,page_size(max. 1000)
Wichtige Response-Felder:
companyName,engagementLevelpaidImpressions,paidClicks,paidEngagements,paidLeadspaidQualifiedLeads,conversions(ab API-Version202603)organicImpressions,organicEngagements
Beispiel:
{
"ad_account_id": "508834004",
"lookback_window": "LAST_30_DAYS",
"page_size": 100
}get_share_content (best effort)
Neues Tool:
get_share_content
Wichtige Parameter:
share_urn(Pflicht, Formaturn:li:share:<id>)include_raw(optional,truegibt zusätzlich das rohe API-Payload zurück)
Response enthält u. a.:
share_urn,source_endpoint(sharesoderposts)post_url(LinkedIn Feed URL)textimage_url(erstes gefundenes Bild odernull)image_urls,thumbnail_urls
Beispiel:
{
"share_urn": "urn:li:share:7379073146093568000",
"include_raw": false
}Troubleshooting get_insights
Bei ILLEGAL_ARGUMENT oder RESOURCE_NOT_FOUND bitte prüfen:
Feldnamen sind exakt korrekt (
clicksstattclick,impressionsstattimpression).Maximal 20
fields.Mindestens ein gültiger Facet-Filter (
ad_account_id/account_idsoder andere Facets).IDs im korrekten Format (Account/Campaign/Campaign Group/Creative numerisch oder URN;
share_idsundcompany_idsals URN).Datum im Format
YYYY-MM-DD.date_fromist gesetzt (ohnedateRangeantwortet LinkedIn oft mitILLEGAL_ARGUMENT).pivotist einer der dokumentierten Werte (siehe oben).
Schneller API-Gegencheck (ohne MCP) für das Token:
curl -i 'https://api.linkedin.com/rest/adAccounts?q=search&pageSize=1' \
-H 'Authorization: Bearer DEIN_ACCESS_TOKEN' \
-H 'Linkedin-Version: 202603' \
-H 'X-Restli-Protocol-Version: 2.0.0'LinkedIn Access Token generieren (Schritt für Schritt)
Voraussetzung:
LinkedIn Developer App vorhanden
Marketing API Zugriff für die App freigeschaltet
Scope
r_adsfür Entities (Accounts/Campaigns/Creatives)Scope
r_ads_reportingfürget_insightsDie Ad Accounts sind in der Developer App unter
Products -> View Ad AccountsgemapptDer authentifizierte User hat eine Ad-Account-Rolle (mind.
VIEWER)
1) App in LinkedIn Developer Portal vorbereiten
In der App unter
Auth:Client IDundClient SecretnotierenRedirect URL hinzufügen, z. B.
http://localhost:9876/callback
In der App sicherstellen, dass die Marketing/Ads Berechtigungen aktiviert sind (
r_ads+r_ads_reporting)
2) Authorization Code holen
Im Browser öffnen (Werte ersetzen, redirect_uri URL-encoden).
Für diesen MCP müssen im Scope mindestens enthalten sein:
r_ads(Accounts/Campaigns/Creatives)r_ads_reporting(get_insights)
Optional (nur wenn deine App dafür freigeschaltet ist):
offline_access(für Refresh-Token-Flow)
Empfohlene URL für den MCP (ohne Refresh-Token):
https://www.linkedin.com/oauth/v2/authorization?response_type=code&client_id=DEIN_CLIENT_ID&redirect_uri=http%3A%2F%2Flocalhost%3A9876%2Fcallback&scope=r_ads%20r_ads_reporting&state=dein_csrf_stateVariante mit optionalem offline_access:
https://www.linkedin.com/oauth/v2/authorization?response_type=code&client_id=DEIN_CLIENT_ID&redirect_uri=http%3A%2F%2Flocalhost%3A9876%2Fcallback&scope=r_ads%20r_ads_reporting%20offline_access&state=dein_csrf_stateNach Login/Consent leitet LinkedIn auf deine Redirect-URL zurück:
http://localhost:9876/callback?code=AUTH_CODE&state=dein_csrf_stateDen code aus der URL kopieren.
3) Authorization Code gegen Access Token tauschen
curl -X POST 'https://www.linkedin.com/oauth/v2/accessToken' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'code=AUTH_CODE' \
--data-urlencode 'redirect_uri=http://localhost:9876/callback' \
--data-urlencode 'client_id=DEIN_CLIENT_ID' \
--data-urlencode 'client_secret=DEIN_CLIENT_SECRET'Beispiel-Response:
{
"access_token": "AQX...",
"expires_in": 5183999
}access_token als LINKEDIN_ACCESS_TOKEN in die Claude MCP Config übernehmen.
Wichtig: Bei diesem MCP erfolgt Authentifizierung über env in der MCP Config.
Es gibt hier keinen eingebauten OAuth-Refresh-Flow im Server selbst.
Wenn der Token abläuft, musst du einen neuen Token erzeugen und in der Config ersetzen.
4) Ablauf / Erneuerung
Access Tokens laufen typischerweise nach ca. 60 Tagen ab.
Dann OAuth-Flow erneut durchführen.
Falls deine App für programmatic refresh tokens freigeschaltet ist, kannst du stattdessen per Refresh Token erneuern.
5) 401/403 schnell diagnostizieren
Token gegen Ads-Account-Endpunkt testen:
curl -i 'https://api.linkedin.com/rest/adAccounts?q=search&pageSize=1' \
-H 'Authorization: Bearer DEIN_ACCESS_TOKEN' \
-H 'Linkedin-Version: 202603' \
-H 'X-Restli-Protocol-Version: 2.0.0'Interpretation:
401 Unauthorized: Token abgelaufen, widerrufen oder falscher Scope-Set wurde neu konsentiert403 Forbidden: Token ist gültig, aber Scope/Rolle/App-Mapping fehlt200 OK: Auth grundsätzlich korrekt
Environment Variablen
Pflicht:
LINKEDIN_ACCESS_TOKEN
Optional:
LINKEDIN_API_VERSION(Default:202603)LINKEDIN_RESTLI_PROTOCOL_VERSION(Default:2.0.0)LINKEDIN_TIMEOUT_SECONDS(Default:30)LINKEDIN_MAX_RETRIES(Default:3)
Lokale Entwicklung
cd /Users/nicolasg/Antigravity/flin-linkedin-ads-mcp
python -m pip install -e ".[dev]"
pytest -q
ruff check .
mypy srcSicherheit (wichtig)
Niemals
LINKEDIN_ACCESS_TOKENoder OAuth Secrets ins Repo committen.envist bereits in.gitignoreToken nur über MCP
envin Claude oder über lokale Shell-Umgebung setzenVor jedem Push prüfen:
git status
git diff -- .envWenn eine Datei mit Secrets auftaucht: Commit abbrechen und Secrets rotieren.
GitHub Actions & Release (PyPI-ready)
Dieses Repo enthält:
CI Workflow:
.github/workflows/ci.ymlRelease Workflow:
.github/workflows/release.yml
Der Release-Workflow macht bei v* Tags:
Lint + Typecheck + Tests
Build +
twine checkTrusted Publishing zu PyPI
GitHub Release mit
dist/*Artefakten
Node-20-Deprecation-Warnungen sind abgefangen durch:
aktuelle Actions-Majors (
checkout@v6,setup-python@v6)FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: truein beiden Workflows
PyPI Trusted Publisher einmalig einrichten
PyPI Project:
flin-linkedin-ads-mcpOwner:
flin-agencyRepository:
flin-linkedin-ads-mcpWorkflow:
release.ymlEnvironment:
pypi
Release auslösen
git add -A
git commit -m "release: v0.1.0"
git tag v0.1.0
git push origin main --tagsOffizielle Referenzen
LinkedIn OAuth Overview:
Authorization Code Flow (native clients):
Reporting (Ad Analytics):
Reporting Schema (Metrics + Query Parameters):
Company Intelligence API:
Programmatic Refresh Tokens:
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/flin-agency/flin-linkedin-ads-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server