LinkedIn MCP Server
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., "@LinkedIn MCP Serversearch for data scientists in San Francisco"
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.
LinkedIn MCP Server (Fork)
Personal fork of stickerdaniel/linkedin-mcp-server with additional tools for messaging and post engagement.
Added Tools
Tool | Description |
| Send a LinkedIn message to a 1st-degree connection |
| Send a connection request, with or without a note |
| Follow a LinkedIn company page |
| Read recent inbox conversations (supports |
| Read the full message thread with a specific person |
| Get the list of people who reacted to a LinkedIn post |
| Get the most recent organic post from a person's profile |
Related MCP server: LinkedIn MCP Server
Detail Mode
All page-scraping tools (get_person_profile, search_people, get_company_profile, get_company_posts, get_job_details, search_jobs) accept a detail parameter:
"basic"(default) — truncates each section's raw text toBASIC_SECTION_MAX_CHARS(2000 chars). LinkedIn front-loads the most important content (name, headline, location, about), so this captures essentials while staying well within LLM context limits. References, job IDs, and post URNs are always kept."full"— returns the complete raw page text, current behaviour.
If basic mode doesn't return enough information, call the tool again with detail="full".
The truncation limit is a single constant in linkedin_mcp_server/tools/utils.py:
BASIC_SECTION_MAX_CHARS = 2000All Tools
People
Tool | Description |
| Get profile info with optional sections: |
| Search for people by keywords and optional location. Supports |
| Get the most recent organic post from a person (visits profile first, then Posts activity tab; returns text, timestamp, URL, and URN) |
| Send a connection request, with or without a note (~300 char limit); handles profiles where Connect is in the More dropdown |
| Send a message to a 1st-degree connection (also used to reply to existing threads) |
| Follow a person's profile |
| Check whether you are following a person |
| Check whether you are connected to a person |
Companies
Tool | Description |
| Get company info with optional sections: |
| Get recent posts from a company's feed; returns post URNs plus lightweight |
| Follow a company page |
| Check whether you are following a company |
Jobs
Tool | Description |
| Search for jobs by keywords and optional location. Supports |
| Get full details of a specific job posting. Supports |
Messaging
Tool | Description |
| List recent inbox conversations with name, preview, timestamp, and unread flag; pass |
| Read the full message thread with a person by their LinkedIn username |
Posts
Tool | Description |
| Get the list of people who reacted to a post (by feed URL or post URN) |
| Get the most recent organic post from a person (no likes, no reshares) |
Session
Tool | Description |
| Close the browser session and clean up resources |
Setup
Prerequisites: Python 3.12+ and uv installed
# 1. Clone the repo
git clone https://github.com/pauling-ai/linkedin-mcp-server
cd linkedin-mcp-server
# 2. Install dependencies
uv sync
# 3. Log in (first time only)
uv run -m linkedin_mcp_server --loginThis opens a browser for you to log in manually (5 minute timeout for 2FA, captcha, etc.). The browser profile is saved to ~/.linkedin-mcp/profile/ and persists across sessions.
Installing into another project
To use this server from another Python project or Claude Code workspace, install it in editable mode pointing at your local clone:
# With uv (recommended)
uv pip install -e /path/to/linkedin-mcp-server
# Or with pip
pip install -e /path/to/linkedin-mcp-serverEditable mode means changes to the repo are immediately reflected — no reinstall needed.
Then point your MCP config at the installed binary:
# Find the installed binary path
which linkedin-scraper-mcpClaude Code / MCP Configuration
After installing (either in a project venv or globally), add to your .mcp.json:
{
"mcpServers": {
"linkedin": {
"command": "/path/to/venv/bin/linkedin-scraper-mcp",
"args": ["--project-auth", "--delay-between-linkedin-calls", "1.5", "--delay-jitter", "0.5"],
"env": {
"LOG_LEVEL": "INFO"
}
}
}
}Or run directly from the repo with uv (no install needed):
{
"mcpServers": {
"linkedin": {
"command": "uv",
"args": ["--directory", "/path/to/linkedin-mcp-server", "run", "-m", "linkedin_mcp_server", "--project-auth", "--delay-between-linkedin-calls", "1.5", "--delay-jitter", "0.5"],
"env": {
"LOG_LEVEL": "INFO"
}
}
}
}The uv approach is the simplest — just update the --directory path and you're done.
Use --slow-mo only when debugging or when you want to watch browser actions happen more slowly. For LinkedIn-facing pacing between tool calls, prefer --delay-between-linkedin-calls / --delay-jitter. The smaller --human-delay-min-ms / --human-delay-max-ms settings still control waits inside individual browser workflows.
If you want a separate LinkedIn account per repo on the same machine, start the server with --project-auth. That stores the auth state under the current project in .linkedin-mcp-server/ instead of the shared ~/.linkedin-mcp/ location.
CLI Options
--login- Open browser to log in and save persistent profile--logout- Clear stored LinkedIn browser profile--status- Check if current session is valid and exit--no-headless- Show browser window (useful for debugging)--project-auth- Store auth under the current project at.linkedin-mcp-server/--slow-mo MS- Debugging aid: slows all browser actions uniformly in ms (default: 0)--human-delay-min-ms MS- Minimum randomized delay between LinkedIn actions (default: 500)--human-delay-max-ms MS- Maximum randomized delay between LinkedIn actions (default: 2000)--delay-between-linkedin-calls SECONDS- Baseline delay before each LinkedIn MCP tool call (default: 1.5)--delay-jitter SECONDS- Random jitter added/subtracted from tool-call delay (default: 0.5)--delay-distribution {uniform,beta,lognormal}- Shape of randomized delays (default: beta)--linkedin-cache-dir PATH- Override cache root (default: beside auth profile)--disable-linkedin-cache- Disable LinkedIn tool result caching--profile-cache-ttl-hours HOURS- TTL for cached person profiles (default: 720 / 30 days)--no-reading-time- Disable reading-time pauses after page extraction--reading-time-wpm WPM- Simulated reading speed in words-per-minute (default: 800)--reading-time-jitter PERCENT- Jitter percentage for reading-time pauses (default: 30)--reading-time-max SECONDS- Maximum reading-time pause in seconds (default: 45)--log-level {DEBUG,INFO,WARNING,ERROR}- Logging level (default: WARNING)--timeout MS- Browser timeout for page operations in ms (default: 5000)--transport {stdio,streamable-http}- Transport mode (default: stdio)
Troubleshooting
Patchright browser cache: The server owns Patchright setup by default. On startup it sets PLAYWRIGHT_BROWSERS_PATH=~/.linkedin-mcp/patchright-browsers, sets PLAYWRIGHT_SKIP_BROWSER_GC=1, and idempotently runs python -m patchright install chromium. This makes separate terminals, cron jobs, uvx runs, and long-running automations independent of shell state and prevents unrelated Playwright/Patchright installs from garbage-collecting the browser revision. Override PLAYWRIGHT_BROWSERS_PATH if you need a custom cache, or set LINKEDIN_PATCHRIGHT_AUTO_INSTALL=0 to disable startup install.
Derived runtime profiles: Foreign runtimes reuse committed derived profiles by default, so server restarts do not re-bridge/rebuild the browser profile every time. Set LINKEDIN_PERSIST_DERIVED_SESSION=0 for legacy fresh-bridge behavior, or LINKEDIN_DEBUG_BRIDGE_EVERY_STARTUP=1 when intentionally debugging bridging.
Session expired: Run uv run -m linkedin_mcp_server --login again.
Login issues: LinkedIn may require confirmation in the mobile app, or show a captcha — the --login browser window lets you handle these manually.
Scraping issues: Use --no-headless to watch the browser and --log-level DEBUG for detailed logs.
Timeout issues: Increase with --timeout 10000 or env var TIMEOUT=10000.
Tool-call pacing: Tune with --delay-between-linkedin-calls / --delay-jitter or env vars LINKEDIN_CALL_DELAY_MS / LINKEDIN_CALL_DELAY_JITTER_MS. Defaults are 1.5 ± 0.5 seconds, so each LinkedIn MCP tool call starts after roughly 1-2 seconds.
In-tool pacing: Tune with --human-delay-min-ms / --human-delay-max-ms or env vars HUMAN_DELAY_MIN_MS / HUMAN_DELAY_MAX_MS. These are smaller pauses inside a tool workflow, e.g. after navigation or clicks.
Delay distribution: By default, randomized delays use a beta distribution (right-skewed) instead of a flat uniform distribution. This means most delays cluster toward the shorter end of the configured range, with occasional longer pauses — a pattern that's mathematically much harder for bot detectors to fingerprint. Use --delay-distribution uniform or DELAY_DISTRIBUTION=uniform to restore the old flat distribution. lognormal is also available for a classic human reaction-time model.
Reading-time simulation: After extracting page content, the scraper pauses proportionally to text length to simulate skimming. This makes the scraper's time-on-page correlate with content length, which looks more human to LinkedIn's behavioral analysis. Defaults are 800 WPM with ±30% jitter and a 45-second hard cap. Tune with --reading-time-wpm, --reading-time-jitter, --reading-time-max, or env vars READING_TIME_WPM, READING_TIME_JITTER_PCT, READING_TIME_MAX_SECONDS. Use --no-reading-time or READING_TIME_ENABLED=false to disable.
Scrolling behavior: The scraper simulates human-like scrolling via mouse wheel events rather than instant window.scrollTo jumps. Scroll distances are variable, occasionally include small upward corrections (overshoot/re-reading), and use non-uniform pauses between scroll steps. This triggers LinkedIn's lazy loaders and intersection observers more naturally than mechanical scrolling.
Mouse movement: The scraper replaces Playwright's default locator.click() (which teleports the mouse to the exact element center with no mousemove events) with curved quadratic Bezier paths that generate 5–10 mousemove events before every click. This includes variable speed, occasional overshoot-and-correction, and random target offsets within the element. Idle mouse micro-movements are also added during page reading time to maintain nonzero mouse event density.
Profile caching: get_person_profile caches raw profile scrape results for 720 hours by default. The cache is shared across sessions beside the auth profile: ~/.linkedin-mcp/cache/profiles/ by default, or .linkedin-mcp-server/cache/profiles/ when using --project-auth. Use force_refresh=true on the tool call to bypass cache for one profile. Requests that include the posts section are not cached, so competitor post discovery stays fresh. Use --profile-cache-ttl-hours, --linkedin-cache-dir, or --disable-linkedin-cache to tune globally. Env vars: LINKEDIN_PROFILE_CACHE_TTL_HOURS, LINKEDIN_CACHE_DIR, LINKEDIN_CACHE_DISABLED.
slow_mo vs pacing delays: --slow-mo / SLOW_MO is mainly for debugging because it slows nearly every browser action. Prefer the tool-call and in-tool pacing settings for normal runs.
Per-project LinkedIn accounts: Use --project-auth or env var PROJECT_AUTH=true. The login flow will then create:
.linkedin-mcp-server/profile/for the persistent browser profile.linkedin-mcp-server/cookies.json.linkedin-mcp-server/source-state.json.linkedin-mcp-server/runtime-profiles/for derived runtime sessions
send_message / get_conversation not finding the Message button: The target user must be a 1st-degree connection. The tool returns an error with diagnostic info if the button isn't found.
send_connection_request not finding the Connect button: The user may already be a connection, have a pending request, or not allow connection requests. If Connect is hidden behind a More dropdown, the tool handles this automatically.
Notes
Browser profile stored at
~/.linkedin-mcp/profile/Tool calls are serialized — concurrent requests queue rather than run in parallel
Use in accordance with LinkedIn's Terms of Service
License
Apache 2.0 — see LICENSE
This server cannot be installed
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
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/pauling-ai/linkedin-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server