linkedin-mcp-server
Enables AI agents to control LinkedIn (profile, network, messaging, publications, jobs) via MCP using a persistent Chrome profile and anti-detection bypass.
README
LinkedIn MCP Server
Serveur MCP (Model Context Protocol) pour piloter LinkedIn depuis un agent IA (Claude Code, Claude Desktop, Manus, etc.). Repose sur Patchright (fork anti-détection de Playwright) et un profil Chrome persistant pour conserver une session authentifiée tout en bypassant les protections Arkose/CAPTCHA.
⚠️ Breaking change & durcissement (sécurité)
Les écritures sont désactivées par défaut. Toutes les actions qui modifient LinkedIn (post, message, connexion, candidature, follow, react, etc. — 43 fonctions) refusent de s'exécuter tant que la variable d'environnement
LINKEDIN_MCP_ENABLE_WRITES=1n'est pas posée. C'est un garde-fou structurel contre l'injection de prompt indirecte : ni le contenu scrapé ni l'agent ne peuvent le contourner.
# Pour autoriser les écritures (à poser côté config MCP, env du process) :
LINKEDIN_MCP_ENABLE_WRITES=1
Autres durcissements appliqués :
| Domaine | Avant | Après |
|---|---|---|
| Prompt injection | descriptions / messages / notifs renvoyés en innerText brut |
_sanitize_external() strip les caractères de contrôle/zéro-largeur et neutralise les phrases impératives ; contenu externe encapsulé via _wrap_untrusted() |
| Soumission de candidature | champs inconnus remplis avec "3" (devinette) |
plus aucune devinette : champs non reconnus laissés vides + refus de soumettre s'il en reste (à renseigner via answers_json) |
| Captcha / checkpoint | detect_checkpoint() jamais appelé (code mort) |
navigation via _goto() qui combine retry_async() (retry transitoire) + detect_checkpoint() sur les lectures clés |
| Nettoyage Chrome | taskkill /f /im chrome.exe (tuait tout Chrome) |
kill ciblé uniquement sur le profil automatisé (~/.linkedin-mcp/profile) via psutil, repli PowerShell filtré par ligne de commande |
| Traçabilité erreurs | except Exception muets (0 traceback) |
traceback.format_exc() loggé en stderr sur 60+ handlers |
| Double encodage JSON | dispatcher manage_jobs ré-encodait du JSON déjà sérialisé |
dispatch retourne directement la chaîne JSON |
| Limite résultats | search_jobs figé à jobs[:5] |
paramètre limit exposé (défaut 25) |
💡
psutilest recommandé pour le kill ciblé. S'il est absent, un repli PowerShell (Windows) /pkill -f <profil>(Unix) est utilisé.
🌟 Fonctionnalités
10 outils consolidés :
| # | Outil | Couverture |
|---|---|---|
| 1 | manage_profile_info |
Profil : lecture, headline, about, photo, bannière, analytics |
| 2 | manage_profile_sections |
Expériences et formations (ajout/suppression, dates, "poste actuel") |
| 3 | manage_skills |
Compétences : add / delete / endorse |
| 4 | manage_recommendations |
Recommandations : demander / rédiger |
| 5 | manage_network |
Connexions, follow, block, recherche simple + avancée |
| 6 | manage_messaging |
DMs, pièces jointes, InMails, non-lus, notifications |
| 7 | manage_publications |
Posts, médias, sondages, articles, carrousels, événements, programmation |
| 8 | engage_social |
React / commenter / repost / save |
| 9 | manage_groups_and_pages |
Publier sur page entreprise ou groupe, join/leave, analytics page |
| 10 | manage_jobs |
Recherche, détails, save, Easy Apply, candidature externe (Greenhouse/Lever) |
⚙️ Installation
pip install -r requirements.txt
patchright install chromium
Dépendances pinnées (requirements.txt) :
mcp>=1.0.0,<2.0.0
patchright>=1.40.0,<2.0.0
python-dotenv>=1.0.0,<2.0.0
🔑 Authentification (bypass anti-bot)
LinkedIn bloque Playwright standard via Arkose. La procédure ci-dessous ouvre un Chrome réel piloté en mode isolé pour passer outre :
python cleanup_and_login.py
Ce script :
- Tue les Chrome résiduels et purge les profils corrompus
- Ouvre une fenêtre Chrome propre
- Tu te connectes à LinkedIn (coche "Se souvenir de moi")
- Attends 5 s sur le feed → le script détecte la session et la sauvegarde dans
~/.linkedin-mcp/profile
Cette étape est à refaire uniquement si la session expire (rare) ou si LinkedIn force une reconnexion.
🛠️ Enregistrement du serveur MCP
Claude Code (recommandé)
claude mcp add linkedin --scope user -- \
"C:/Users/<user>/AppData/Local/Programs/Python/Python312/python.exe" \
"C:/Users/<user>/Downloads/LinkedIn MCP Server/linkedin_mcp_server.py"
Vérification :
claude mcp list | grep linkedin
# → linkedin: ... - ✓ Connected
⚠️ Cold-start requis : après
claude mcp add, ferme et relance Claude Code (un--resumene re-découvre pas les nouveaux MCP tools).
Claude Desktop / Manus
claude_desktop_config.json :
{
"mcpServers": {
"linkedin": {
"command": "C:/Users/<user>/AppData/Local/Programs/Python/Python312/python.exe",
"args": ["C:/Users/<user>/Downloads/LinkedIn MCP Server/linkedin_mcp_server.py"]
}
}
}
🔐 Données personnelles — scraping automatique
Aucun .env à remplir pour les PII. Les champs nom / email / téléphone / localisation sont scrapés directement depuis ton compte LinkedIn connecté :
| Champ | Source |
|---|---|
first_name, last_name, full_name |
https://www.linkedin.com/in/<toi>/ (H1 du profil) |
location |
Top card du profil |
email, phone |
https://www.linkedin.com/mypreferences/d/category/account |
Le résultat est mis en cache par process : un seul scrape au premier appel d'un outil qui en a besoin, gratuit ensuite.
Fallback optionnel : si LinkedIn change la page settings (rare) et que le scrape email/phone échoue, tu peux poser ces variables dans ~/.linkedin-mcp/.env — elles seront utilisées en dernier recours, champ par champ :
LINKEDIN_EMAIL=...
LINKEDIN_PHONE=...
Salaire — calculé par l'IA
Le salaire n'est jamais stocké côté serveur. L'agent IA doit le calculer en fonction des compétences, du niveau et du poste, puis le passer via le paramètre salary_expectation du tool manage_jobs (action easy_apply).
📚 Référence des outils
1. manage_profile_info
Profil : informations de base, visuels, stats.
- Actions :
get,get_analytics,edit_headline,edit_about,update_picture,update_banner - Args :
action(req),profile_url,headline,about,image_path
2. manage_profile_sections
Expériences et formations.
- Actions :
add_experience,delete_experience,add_education,delete_education - Args :
action(req),title/company(req pour expérience),school/degree(req pour formation),field_of_study,start_month,start_year,end_month,end_year,current(bool),location,employment_type,description
3. manage_skills
- Actions :
add,delete,endorse - Args :
action(req),skill_name(req),profile_url(req pourendorse)
4. manage_recommendations
- Actions :
request,write - Args :
action(req),recipient_url_or_name(req),relationship,position,text
5. manage_network
- Actions :
connect,accept,remove,withdraw,follow,unfollow,block,unblock,search,search_advanced - Args :
action(req),profile_url_or_name,note,password(pourunblock),keywords,location,network(first/second/third),company,industry,school,limit(défaut 10)
6. manage_messaging
- Actions :
send,send_attachment,send_inmail,get_unread,read_thread,get_notifications - Args :
action(req),recipient_url_or_name,message,subject(poursend_inmail),file_path(poursend_attachment),max_messages(défaut 50)
7. manage_publications
- Actions :
post_simple,post_media,post_mentions,post_poll,schedule_post,post_article,post_carousel,trending_hashtags,create_event - Args :
action(req),content,title,visibility(public/connections),media_paths,mentions,poll_question,poll_options,poll_duration_days,schedule_year/month/day/hour/minute,pdf_path,cover_image_path,event_name,event_type(ONLINE/IN_PERSON),start_date,end_date,start_time,end_time,timezone,external_link,location
8. engage_social
- Actions :
react,comment,repost,save_post - Args :
action(req),post_url(req),reaction(LIKE/CELEBRATE/...),comment_text,repost_thoughts
9. manage_groups_and_pages
- Actions :
post_page,post_group,join_group,leave_group,get_company_analytics - Args :
action(req),target_url_or_handle(req),content
10. manage_jobs
- Actions :
search,details,save_job,easy_apply,external_apply - Args :
action(req)keywords,location,easy_apply,limit(nombre max de résultats, défaut 25) (poursearch)job_id_or_urlanswers_json(JSON de réponses pré-définies poureasy_apply)submit(bool, défautFalse— quandFalsele serveur s'arrête sur la review et sauvegarde une capture dans~/.linkedin-mcp/screenshots/easy_apply_review.png)resume_path,answers_dict(pourexternal_apply)salary_expectation(str, optionnel) — montant que l'IA doit calculer en fonction du poste / niveau / compétences
🎯 Visibilité des publications
| Valeur | Description |
|---|---|
public |
Visible par tout le monde (défaut LinkedIn) |
connections |
Visible uniquement par tes connexions |
📁 Structure du projet
.
├── README.md
├── CLAUDE.md ← contexte pour sessions Claude Code
├── linkedin_mcp_server.py ← serveur MCP monolithique
├── cleanup_and_login.py ← procédure d'auth (1 fois)
├── requirements.txt
├── tests/ ← suites d'intégration (LinkedIn live requis)
├── tools/ ← scripts utilitaires (debug, inspection, dumps)
└── scratch/ ← captures et artefacts de debug
🧪 Tests d'intégration
Tests unitaires hors-ligne (recommandés, aucune session requise) — vérifient les correctifs de durcissement de façon déterministe (deps lourdes stubbées) :
python tests/test_hardening.py # runner autonome → "18 passed, 0 failed"
# ou
pytest tests/test_hardening.py -q
Couverture : fix d'URL (_normalize_job_url), garde-fou d'écriture
(_writes_enabled / _assert_write_allowed), sanitisation anti-injection
(_sanitize_external / _wrap_untrusted), suppression du fallback "3",
câblage du code anciennement mort.
Tests d'intégration live (session LinkedIn active requise) :
python tests/test_linkedin_new_features.py
python tests/full_test_suite.py
🔒 Sécurité
- Aucun identifiant en clair : les cookies sont stockés par Chrome dans
~/.linkedin-mcp/profile, isolés du Chrome principal. - Pas de PII dupliquée : nom/email/téléphone/localisation viennent de LinkedIn lui-même, pas d'un fichier de config à maintenir.
- Logging stderr-safe :
printest redirigé surstderrpour ne pas polluer le canal stdio JSON-RPC du MCP. - Pas d'injection JS : tous les
page.evaluate()passent les valeurs via args, pas via f-string. - Écritures désactivées par défaut : 43 fonctions de modification protégées par
LINKEDIN_MCP_ENABLE_WRITES=1(garde-fou structurel anti prompt-injection). - Sanitisation du contenu externe :
_sanitize_external()/_wrap_untrusted()neutralisent les tentatives d'injection venant des descriptions, messages et notifications scrapés. - Détection captcha/checkpoint :
_goto()(retry +detect_checkpoint) stoppe proprement si LinkedIn sert une vérification, plutôt que de renvoyer des données douteuses. - Kill Chrome ciblé : seul le profil automatisé est terminé — les autres fenêtres Chrome de l'utilisateur ne sont jamais tuées.
- Usage responsable : respecte les limites LinkedIn (anti-spam, anti-scraping). Évite les boucles rapides massives.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。