VOOZH about

URL: https://glama.ai/mcp/servers/devag7/linkedin-mcp

โ‡ฑ LinkedIn MCP by devag7 | Glama


๐Ÿ”— LinkedIn MCP

LinkedIn for AI assistants โ€” structured data via a real, stealth browser session

๐Ÿ‘ CI
๐Ÿ‘ npm version
๐Ÿ‘ MIT License
๐Ÿ‘ TypeScript
๐Ÿ‘ MCP
๐Ÿ‘ Glama score

Give Claude, Cursor, and any MCP client access to LinkedIn โ€” profiles, people/job/company search, feed, messaging, and your network โ€” as clean structured JSON.

22 tools ยท reads + gated writes (connect, message, post, react, comment) ยท a real safety layer (daily caps, human pacing, circuit breaker) ยท 166 tests.

โš ๏ธ Automating LinkedIn violates its User Agreement and can get an account restricted. No tool is ban-proof โ€” and this one says so up front. Use a secondary account; read Account safety and DISCLAIMER.md first.


Why this exists

LinkedIn's internal Voyager API (the one its own web app uses) returns rich, structured JSON โ€” but it sits behind Cloudflare bot-management, which rejects plain HTTP requests (a stateless fetch or curl gets stuck in an endless redirect, even with a valid cookie). The only reliable way to read LinkedIn data programmatically in 2026 is from inside a real browser that clears the challenge.

This project's approach:

  1. Drive a real Chrome via patchright (an undetected Playwright fork) so Cloudflare's challenge is solved with a genuine browser fingerprint.

  2. Query Voyager from inside the authenticated page โ€” same-origin, the exact network path LinkedIn's own SPA uses โ†’ structured JSON, not scraped DOM text.

That last point is the edge over DOM-scraping tools: in-page API calls are locale-independent and resilient to UI redesigns, so they don't break on a moved CSS selector or a translated label.


Related MCP server: LinkedIn MCP Server

โœจ What's good here

๐Ÿงฉ Structured JSON

In-page Voyager API calls return normalized data, shaped into compact objects โ€” not brittle innerText scraping.

โœ๏ธ Writes are API calls, not button-clicking

connect / message / post / react / comment POST straight to Voyager โ€” the exact requests the web app sends, captured and verified live. No hunting for a "Connect" button under a sticky navbar, no composer-dialog race. Every write returns a structured status (ok / duplicate / already_connected / restricted / quota_exhausted / โ€ฆ) โ€” never a blind "sent: true".

๐Ÿ›ก๏ธ Safety layer built in

Serial queue, human-paced jittered delays, per-action daily budgets, account warmup ramp, and a circuit breaker that hard-stops on any checkpoint/captcha. (Risk reduction โ€” not a safety guarantee.)

๐Ÿ”ฅ One warm session

A single persistent browser per process (cookies + Cloudflare clearance survive restarts). Explicit close_session, signal-handled teardown โ€” no zombie Chrome.

๐ŸŒ Locale-independent

API + embedded-JSON parsing, not English-only DOM selectors โ€” survives UI redesigns and translations.

๐Ÿ”’ Local & private

Session stored under ~/.linkedin-mcp/ with 0700/0600 perms; no cookies/tokens to paste, none ever logged.


How it compares

DOM-scraping LinkedIn MCPs

This

Reads

scraped page text (brittle, locale-bound)

structured API JSON

Writes (connect/message/post)

click rendered buttons (break on sticky navbars, dialog races, localized labels)

direct Voyager POST, captured + verified live

Write feedback

"clicked it" โ†’ hope

structured status (ok / duplicate / restricted / quota_exhausted / โ€ฆ)

Resilience

breaks on UI tweaks / translations

API + embedded-JSON, locale-proof

Safety (caps, pacing, circuit breaker)

none

โœ… built-in, 166 tests

Zombie browser processes

common

โœ… reaped on close

Language

Python

TypeScript + official MCP SDK

We hit LinkedIn's own API from inside the challenge-passed browser โ€” reads and writes โ€” so you get the structured response and a real status, not parsed HTML and a hopeful click. (Shipping checklist + launch notes: LAUNCH.md.)

๐Ÿ“ฆ Status

Full transparency โ€” exactly where every piece stands (and what's still alpha):

Area

State

Stealth browser engine (patchright)

โœ… built, live-proven

In-page Voyager fetch (the core mechanism)

โœ… live-verified (returns structured JSON)

Safety layer (queue / pacer / budgets / circuit-breaker)

โœ… built, 166 unit tests

Profile โ€” get_profile, get_my_profile (name, headline, summary, experience, education, skills, certifications, languages)

โœ… live-verified

Feed / notifications โ€” get_feed, get_notifications

โœ… live-verified

Jobs / messaging โ€” search_jobs, get_job_details, get_inbox, get_conversation

โœ… live-verified

People / companies โ€” search_people, search_companies, get_company, get_company_posts, get_company_employees (DOM fallback)

โœ… live-verified

Network โ€” get_pending_invitations (received + sent)

โœ…

Session โ€” whoami, health_check (live Voyager probe + budget headroom), close_session

โœ…

Write tools โ€” connect_with_person, send_message, create_post, react_to_post, comment_on_post

โœ… all 5 endpoints captured + live-verified on a burner; gated (confirm:true + daily caps), structured statuses. Still โš ๏ธ alpha โ€” these take real, often irreversible actions; use a throwaway account.

22 tools. typecheck + 166 tests green.

Login is headful, the server is headless. The one-time --login opens a real Chrome window (to clear Cloudflare and let you solve any captcha/2FA). After that the persistent profile carries the clearance, so the server runs headless โ€” verified returning live data. Use a residential IP; datacenter/VPN IPs are often pre-flagged by Cloudflare regardless of headless vs headful.


๐Ÿš€ Quick start

1. Log in once (opens a real Chrome window โ€” sign in, solve any captcha/2FA):

npx -y linkedin-mcp-tools@latest --login

Needs Google Chrome installed (or run npx patchright install chrome once). Your session โ€” Cloudflare clearance and all โ€” persists to ~/.linkedin-mcp/profile/.

2. Point your MCP client at it. Claude Desktop / Cursor / Claude Code config:

{
 "mcpServers": {
 "linkedin": {
 "command": "npx",
 "args": ["-y", "linkedin-mcp-tools@latest"]
 }
 }
}

Then just ask: "Get my LinkedIn profile and summarize my experience" or "Find 5 recruiters at Google."

git clone https://github.com/devag7/linkedin-mcp.git
cd linkedin-mcp
npm install
npm run setup:browser # installs the Chrome patchright drives
npm run login # log in once
npm run spike # verify: fetches your profile as JSON
npm run build # produces dist/

MCP config: "command": "node", "args": ["/absolute/path/to/dist/index.js"].

Headless / server deployment

The one-time --login needs a window; the server then runs headless (verified returning live data). Run --login on a machine with a display (or via VNC), copy ~/.linkedin-mcp/profile/ to your server, and run there:

LINKEDIN_HEADLESS=true npx -y linkedin-mcp-tools@latest # no display needed

Use a residential IP โ€” datacenter/VPN IPs are frequently pre-flagged by Cloudflare regardless of headless vs headful.


๐Ÿ›ก๏ธ Account safety

Read this. Automating LinkedIn violates its User Agreement and can get your account restricted or banned โ€” no tool can prevent that, including this one. The built-in safety features (daily caps, human pacing, warmup, circuit breaker) reduce risk; they do not eliminate it.

Defaults err conservative:

  • Connections 20/day, messages 50/day, likes+comments 50/day combined, follows 30/day โ€” combined write cap 150/24h.

  • Profile views 80/day, searches 30/day.

  • New-account warmup ramp over the first weeks; pending-invite ceiling and acceptance-rate pauses.

  • Reads paced 4โ€“12s apart, writes 45โ€“150s, with long breaks and a working-hours gate.

  • A circuit breaker stops automatically on any checkpoint, captcha, or "unusual activity" page โ€” and never tries to solve one.

Recommendations: use a secondary/throwaway account, run from a residential IP, warm it up slowly. See DISCLAIMER.md for the full legal/ToS notice.


โš™๏ธ Configuration

Variable

Default

Description

LINKEDIN_HEADLESS

true

Server runs headless. --login always opens a real window regardless. Set false to watch the browser.

LINKEDIN_CHROME_PATH

โ€”

Explicit Chrome binary path (else patchright's).

LINKEDIN_PROFILE_DIR

~/.linkedin-mcp/profile

Persistent browser profile.

LINKEDIN_IDLE_TIMEOUT_MS

300000

Close the browser after this idle time (0 disables).

LINKEDIN_CONCURRENCY

1

Serial by default; >1 is ban-risky.

TRANSPORT

stdio

stdio (primary) or http.


๐Ÿ›  Development

npm run dev # run from source (stdio)
npm run typecheck
npm test # vitest (safety layer + smoke)
npm run build

๐Ÿ“„ License

MIT โ€” see LICENSE. Not affiliated with LinkedIn. Use at your own risk; see DISCLAIMER.md.

Made by Dev Agarwalla

A
license - permissive license
A
quality
A
maintenance

Maintenance

โ€“Maintainers
โ€“Response time
0dRelease cycle
9Releases (12mo)
Commit activity

Latest Blog Posts

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/devag7/linkedin-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server