LinkedIn MCP Server — Kugamon Build
A defensive thin wrapper around the upstream mcp-server-linkedin package (formerly linkedin-scraper-mcp) that pins fastmcp<4.0 so uvx doesn't silently upgrade users into the FastMCP 4.0 API removal that took every install down on 2026-08-31. Same 17 LinkedIn tools, same Chromium-based auth flow, same behavior — zero-risk crash guard on top.
Use this instead of the upstream package unless you know you want to track the latest FastMCP release.
A note on the
-chromein the nameThis package is part of a family of Kugamon MCP wrappers —
salesforce-mcp-auto-auth-chromeandreddit-mcp-chrome— and shares their naming convention. But-chromemeans something different here, and we want to be upfront about it.
Package What -chromemeanssalesforce-mcp-auto-auth-chromeReads the session cookie from your real Chrome profile reddit-mcp-chromeReads session cookies from your real Chrome profile linkedin-mcp-chrome(this one)Drives a separate bundled Chromium browser (via upstream's Patchright), with its own saved login Practically, that means: you log into LinkedIn once, inside a browser window this server opens — not in your everyday Chrome. That session is saved to
~/.linkedin-mcp/profile/and reused. Being logged into LinkedIn in your normal Chrome does not carry over.This is inherited from upstream, not a choice we made. If a future version adds real Chrome-profile cookie reuse (killing the separate login and the ~40 MB Chromium download), we'll note it here.
How it fits together
Claude Desktop ── stdio ──▶ this package (Python) ── hands off to ──▶ mcp-server-linkedin
│ │ (unmodified)
│ └── pins fastmcp<4 in metadata, │
│ so uvx never resolves 4.0+ │
│ ▼
│ Patchright Chromium
│ (headless browser
│ with saved profile)
│ │
│ ▼
└── one entry in claude_desktop_config.json LinkedIn (web scrape)
The package adds nothing at runtime — no monkey-patching, no cookie extraction, no wrappers around the actual tools. It exists purely so that when uvx resolves the dependency graph, it can never pick up a FastMCP version that upstream's code hasn't been ported to yet. When upstream releases a FastMCP 4-compatible version, this wrapper drops the pin and moves on.
Files in this repo
src/linkedin_mcp_chrome/__main__.py— entry point. Prints a version banner, then callslinkedin_mcp_server.cli_main:mainunchanged.src/linkedin_mcp_chrome/__init__.py— package version.pyproject.toml— the actual work happens here. Declaresmcp-server-linkedin>=4.23.1andfastmcp>=3.4.4,<4.0as dependencies.examples/claude_desktop_config.example.json— copy-paste-ready Claude Desktop config snippet.docs/how-it-works.md— the full story: what broke on 2026-08-31, why upstream shipped it unpinned, what this wrapper does about it, and when the pin should come off.
Setup — Part 1: Add to Claude Desktop (~1 min, one-time)
Fastest path — have Claude do it for you
If Claude Desktop already has filesystem access to your home directory (Cowork mode users do by default), paste the following into a fresh Claude chat:
Add a LinkedIn MCP entry to my Claude Desktop config named `linkedin`.
The MCP command should be `uvx linkedin-mcp-chrome` (it's on PyPI).
Set env var UV_HTTP_TIMEOUT to "300" so the first-run Chromium
download doesn't time out. Make a backup of my existing config first.
Claude reads your existing claude_desktop_config.json, adds the entry alongside anything already there, backs up the original, and tells you when to restart. When Claude confirms it's done, skip to Restart Claude Desktop below.
Alternate route — edit claude_desktop_config.json yourself
If you'd rather edit JSON by hand:
1. Open your Claude Desktop config. On macOS the file lives at:
~/Library/Application Support/Claude/claude_desktop_config.json
2. Add this entry to mcpServers.
{
"mcpServers": {
"linkedin": {
"command": "uvx",
"args": ["linkedin-mcp-chrome"],
"env": {
"UV_HTTP_TIMEOUT": "300"
}
}
}
}
The UV_HTTP_TIMEOUT env var gives uvx time to download the ~40 MB Patchright Chromium binary the first time the wrapper runs.
Restart Claude Desktop
Cmd+Q (a full quit — not just closing the window) and reopen. Claude Desktop reads the config at startup.
Sanity check
Ask Claude something the LinkedIn MCP can answer: "using the linkedin MCP, look up Marc Benioff's profile and summarize his recent posts." First call will pause while the server downloads Chromium and opens a browser window asking you to log into LinkedIn. Sign in once and the session is saved for future calls.
Setup — Part 2: LinkedIn login (once, then persistent)
The wrapper doesn't touch auth at all — it inherits the exact flow from mcp-server-linkedin. On the first tool call that needs auth:
- A browser window opens to LinkedIn's login page.
- Sign in normally (LinkedIn's 2FA and CAPTCHA prompts work).
- The session cookie is saved to
~/.linkedin-mcp/profile/on your Mac and reused on every subsequent call.
If you want to sign in before the first tool call — or re-authenticate after LinkedIn logged you out — run this once in Terminal:
uvx linkedin-mcp-chrome --login
The 17 tools
All 17 come from the underlying mcp-server-linkedin — this wrapper adds nothing to the surface area.
Profiles (3)
| Tool | Purpose |
|---|---|
get_person_profile |
Get a person's profile (experience, education, interests, posts, contact info — selectable sections) |
get_my_profile |
Get the authenticated user's own profile |
get_sidebar_profiles |
Extract "People you may know" and similar recommendation blocks |
Companies (3)
| Tool | Purpose |
|---|---|
get_company_profile |
Get a company's overview + selectable sections |
get_company_posts |
Recent posts from a company's feed |
get_company_employees |
Employees listed on the company page |
Search (3)
| Tool | Purpose |
|---|---|
search_people |
People search with keyword + location filters |
search_companies |
Company search |
search_jobs |
Job listings search |
Jobs (2)
| Tool | Purpose |
|---|---|
get_job_details |
Full detail on a specific posting |
get_saved_jobs |
Your saved jobs |
Messaging (4)
| Tool | Purpose |
|---|---|
get_inbox |
List recent conversations |
get_conversation |
Read one conversation |
search_conversations |
Keyword search across messages |
send_message |
Send a message (requires explicit confirmation) |
Connections + feed (2)
| Tool | Purpose |
|---|---|
connect_with_person |
Send or accept a connection request |
get_feed |
Get your home feed |
(Plus close_session, search_posts — depending on the exact upstream version.)
Each tool's full schema is advertised through the MCP tools/list method — Claude reads it automatically.
Why a pinned wrapper (vs. just using the upstream directly)
On 2026-08-31, FastMCP shipped 4.0.0. It removed the exclude_args keyword argument from @FastMCP.tool(), which mcp-server-linkedin uses in tools/person.py. Because upstream's pyproject.toml declared fastmcp>=3.4.4 with no upper bound, every fresh uvx mcp-server-linkedin@latest resolution installed FastMCP 4.0 and crashed at import time with:
TypeError: FastMCP.tool() got an unexpected keyword argument 'exclude_args'
Every Claude Desktop user who had the LinkedIn MCP configured saw it disconnect simultaneously with no config change. This is the same class of bug that hit mcp-salesforce-connector when mcp 2.0 removed Server.list_tools() (see kugamon/salesforce-mcp-auto-auth-chrome's v0.1.1 release notes for that story).
The user-side workaround is uvx --with "fastmcp<4" mcp-server-linkedin@latest, but that requires every user to edit their claude_desktop_config.json. This wrapper builds the pin into the package metadata so no user has to know about the workaround — uvx linkedin-mcp-chrome just works, forever, until we drop the pin.
The full write-up — including why upstream ships without upper bounds, the general "pin transitive SDKs" lesson, and how to spot this pattern early — is in docs/how-it-works.md.
Local development
If you want to test changes before pushing:
# Install Python 3.12+ and uv if you don't have them
curl -LsSf https://astral.sh/uv/install.sh | sh
# Clone and run from source
git clone https://github.com/kugamon/linkedin-mcp-chrome.git
cd linkedin-mcp-chrome
uv sync
# Smoke-test — should print version banner then start the MCP server
uv run python -m linkedin_mcp_chrome --help
To point your local Claude Desktop config at the working copy instead of the published version, change the args to:
"args": ["run", "--directory", "/absolute/path/to/your/checkout", "python", "-m", "linkedin_mcp_chrome"]
When will the pin come off?
When upstream mcp-server-linkedin releases a version compatible with FastMCP 4.x. At that point this wrapper's next release will:
- Bump the
fastmcpupper bound (either to<5.0or drop it entirely, depending on how upstream chooses to handle it) - Note it in the version history
- Users get the update automatically the next time
uvxrefreshes its cache
Track: stickerdaniel/linkedin-mcp-server issues for the port PR.
LinkedIn TOS + ban risk (from the upstream author)
LinkedIn's TOS prohibits automated tools. Per the upstream README: "With normal usage (not bulk scraping!) you're not risking a ban. So far, no users have been banned for using this MCP." Prompt your Claude agents to make targeted, human-scale requests — a profile lookup here, a search there — not a script that pulls 500 profiles in an hour.
If LinkedIn does throttle you, back off and reduce your usage. This wrapper doesn't change any of that — it inherits everything from upstream, including the browser-based session, the persistent profile, and the per-tool rate limiting.
Troubleshooting
Claude shows "Server disconnected" at startup: Look at ~/Library/Logs/Claude/mcp-server-linkedin.log for the actual Python traceback. If you see TypeError: FastMCP.tool() got an unexpected keyword argument 'exclude_args' — you're not using this wrapper, you're using the raw mcp-server-linkedin. Switch your config to uvx linkedin-mcp-chrome and the pin will prevent the crash.
First tool call hangs for ~90 seconds: The upstream MCP server downloads Patchright Chromium (~40 MB) the first time it needs to authenticate. Once. After that, calls are fast. UV_HTTP_TIMEOUT=300 in your config gives it the runway.
Every tool call returns an auth error: Your LinkedIn session expired. Run uvx linkedin-mcp-chrome --login in Terminal, sign in via the browser window that pops up, and retry.
Chromium won't launch on my Mac: This is an upstream mcp-server-linkedin issue. Check ~/.linkedin-mcp/patchright-browsers/ — if it's empty or corrupt, delete it and let the next tool call re-download. Also check that macOS Gatekeeper hasn't quarantined the Chromium binary.
I want to opt out of the pin and track the latest FastMCP: Then use the upstream package directly (uvx mcp-server-linkedin@latest). You're back to being exposed to the next major-version bump.
Version history
- v0.1.0 — initial release on PyPI. Wraps
mcp-server-linkedin>=4.23.1, pinsfastmcp>=3.4.4,<4.0. macOS + Chromium (Patchright) via upstream — no direct browser interaction from this wrapper.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file linkedin_mcp_chrome-0.1.0.tar.gz.
File metadata
- Download URL: linkedin_mcp_chrome-0.1.0.tar.gz
- Upload date:
- Size: 11.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
25731546aeb203b9e65fac63c29f644142c437fa6c3128edf5d1b693c3bc8d28
|
|
| MD5 |
153881538c00bef9e81176879589309d
|
|
| BLAKE2b-256 |
9607d920b2a513b1aeaf556229bd80e513d2652d6405509e6363cdbe2c921766
|
Provenance
The following attestation bundles were made for linkedin_mcp_chrome-0.1.0.tar.gz:
Publisher:
publish.yml on kugamon/linkedin-mcp-chrome
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
linkedin_mcp_chrome-0.1.0.tar.gz -
Subject digest:
25731546aeb203b9e65fac63c29f644142c437fa6c3128edf5d1b693c3bc8d28 - Sigstore transparency entry: 2697142971
- Sigstore integration time:
-
Permalink:
kugamon/linkedin-mcp-chrome@44d81b528f97aef83edf5c2fa69732e8649e8639 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/kugamon
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@44d81b528f97aef83edf5c2fa69732e8649e8639 -
Trigger Event:
push
-
Statement type:
File details
Details for the file linkedin_mcp_chrome-0.1.0-py3-none-any.whl.
File metadata
- Download URL: linkedin_mcp_chrome-0.1.0-py3-none-any.whl
- Upload date:
- Size: 8.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1d5bd187a239105a69aa08ce737f7b614b63d35bf232fd10ee7d0d60e26f92dd
|
|
| MD5 |
7dd2a854f11b8466e16c80ff0024b4eb
|
|
| BLAKE2b-256 |
81ff4664ef302593bd40c1ac22e6b2af36ab71f2fe7080397a53625c05575866
|
Provenance
The following attestation bundles were made for linkedin_mcp_chrome-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on kugamon/linkedin-mcp-chrome
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
linkedin_mcp_chrome-0.1.0-py3-none-any.whl -
Subject digest:
1d5bd187a239105a69aa08ce737f7b614b63d35bf232fd10ee7d0d60e26f92dd - Sigstore transparency entry: 2697143005
- Sigstore integration time:
-
Permalink:
kugamon/linkedin-mcp-chrome@44d81b528f97aef83edf5c2fa69732e8649e8639 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/kugamon
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@44d81b528f97aef83edf5c2fa69732e8649e8639 -
Trigger Event:
push
-
Statement type: