Reported issues for LinkedIn
Pod holds 15 of 15 problems reported by people outside the maintainer team. Issues filed by the project's own owners, members and collaborators are excluded entirely — a maintainer's release checklist is not a warning to a prospective user.
Back to LinkedIn.
Most discussed
Add --json and --version flags to the CLI
What is missing
The CLI has auth, --test, and serving. Two small additions would help.
--version prints the installed version. Currently the only way to check is python -c "import linkedin_mcp; print(linkedin_mcp.__version__)", which is a lot to ask of someone reporting a bug. Version is the first thing an issue needs.
--json on --test emits machine-readable output. --test currently prints the redacted config and Session OK. for humans. A JSON mode would let people
Read the thread · 2026-08-09 · open · 2 comments
No test covers posts.py
What is missing
Every other tool module has a test file:
tests/test_company_parsing.py
tests/test_job_parsing.py
tests/test_messaging_parsing.py
tests/test_people_parsing.py
tests/test_safety.py
tests/test_session_errors.py
tests/test_throttle.py
There is no test_post_parsing.py. None of the 68 passing tests exercise posts.py at all, so it could break entirely and CI would stay green.
Why this one matters more than it looks
search_posts returns text **any stranger on Lin
Read the thread · 2026-08-09 · open · 2 comments
No test enforces the README's blanket fencing guarantee, so unfenced fields are found one at a time
What is wrong
Every fencing test in this repo targets one named field. Nothing asserts the blanket guarantee the README makes, so an unfenced field is only discovered when somebody happens to look at that specific line.
That has now happened three times:
- #6,
headlineonget_profileandsearch_people - #13,
author_headlineonsearch_posts - the company
tagline(filed separately)
Each was found by reading the code, not by a failing test. A fourth would be found the same way.
Read the thread · 2026-08-12 · closed · 1 comment
get_company returns tagline unfenced, though it fences the about blurb
What is wrong
get_company fences the about blurb but returns tagline raw.
src/linkedin_mcp/tools/companies.py:379 fences the about text:
result["about"] = fence(
safety_truncate(_clean(about_text), _ABOUT_LIMIT, "company about"),
"company.about",
)
but line 347 returns the tagline with only whitespace normalisation:
"tagline": tagline, # _clean()ed on line 341, never fenced
grep -c "fence(" src/linkedin_mcp/tools/companies.py returns 1,
Read the thread · 2026-08-12 · closed · 1 comment
The fencing guard walks only tools/, so a prose field in server.py would pass unnoticed
What is wrong
tests/test_fencing_coverage.py walks only one directory:
TOOLS_DIR = Path(__file__).resolve().parent.parent / "src" / "linkedin_mcp" / "tools"
...
for path in sorted(TOOLS_DIR.glob("*.py")):
Everything outside tools/ is invisible to it. That includes server.py, which already
returns dicts containing a message key, and any future resources.py or prompt module.
src/linkedin_mcp/
server.py <- returns {"error": ..., "message": ...}, not walked
[Read the thread](https://github.com/JohannsenLum/linkedin-api-mcp/issues/20) · 2026-08-15 · open · 0 comments
### Server still negotiates MCP protocol 2025-11-25, blocked on FastMCP allowing mcp>=2
## What's wrong
This server negotiates MCP protocol version `2025-11-25`. The current specification is
`2026-07-28`, [announced on 2026-07-28](https://blog.modelcontextprotocol.io/posts/2026-07-28/).
The cause is upstream, not in this repository. `fastmcp` currently pins `mcp<2`, and only
`mcp>=2.0.0` speaks the new protocol version. Verified:
this repo's environment
mcp 1.29.0 LATEST_PROTOCOL_VERSION = 2025-11-25
clean venv
pip install mcp==2.0.0 -> LATEST_PROTOCOL_VERSION
Read the thread · 2026-08-10 · open · 0 comments
search_posts returns author_headline unfenced, though it fences the post body
What's wrong
search_posts fences the post body but returns the author's headline raw.
In src/linkedin_mcp/tools/posts.py, the post text goes through the safety pipeline at both
return sites:
# line 369, structural path
"text": fence(safety_truncate(text, _POST_TEXT_LIMIT, "post text"), "post.text"),
# line 526, selector fallback path
"text": fence(safety_truncate(post_text, _POST_TEXT_LIMIT, "post text"), "post.text"),
The author headline, in the same two dicts, does not
Read the thread · 2026-08-10 · closed · 0 comments
The 120-action hourly ceiling lives only in memory, so a process restart or second instance silently resets or doubles it
What's wrong
README.md (around lines 280 to 290) describes the 120-actions-per-hour ceiling as "enforced, not just claimed": "Once hit, further calls fail immediately with a rate_limited error rather than queueing or sleeping."
The enforcement lives entirely in process memory. ActionQueue.__init__ in src/linkedin_mcp/throttle.py (lines 46 to 52) stores usage in self._history: deque[float] = deque(), an attribute on the instance, with no file, database, or IPC behind it. `build_serve
Read the thread · 2026-08-10 · open · 0 comments
Most recent
A missing Chromium browser install surfaces as a generic internal error instead of the existing missing_browser hint
What's wrong
Session.start() in src/linkedin_mcp/session.py (lines 92 to 129) only catches one failure mode when launching the browser:
try:
from patchright.async_api import async_playwright
except ImportError as exc:
raise LinkedInError(
"missing_browser",
"The browser automation dependency is not installed.",
"Run `uvx --from linkedin-api-mcp patchright install chromium`, or "
"`patchright install chromium` in your environment.",
)
[Read the thread](https://github.com/JohannsenLum/linkedin-api-mcp/issues/9) · 2026-08-10 · open · 0 comments
### connect reports sent: true without confirming the invitation actually went out
## What's wrong
`do_connect` in `src/linkedin_mcp/tools/messaging.py` clicks the send-invite button and, if no weekly-limit banner appears, returns `{"sent": true, ...}` (around line 1083) purely because the click did not throw. There is no check that the invitation modal actually closed or that LinkedIn's UI now shows the person as pending.
This is the exact anti-pattern the same file explicitly guards against for messages. `_confirm_sent` (line 773) exists specifically because a click that d
[Read the thread](https://github.com/JohannsenLum/linkedin-api-mcp/issues/8) · 2026-08-10 · open · 0 comments
### README's Contributing section never explains how to run the test suite, though 68 tests need no browser or LinkedIn account
## What's wrong
The README's Contributing section (around lines 325 to 333) only links to the GitHub issues/PR page and CHANGELOG.md. It never says how to run the test suite, and never mentions that this project has a full offline test double for the browser layer.
I ran the suite myself from the repo root:
pip install -e ".[dev]" python -m pytest -q
Result: `68 passed in 0.80s`. No `patchright install chromium`, no `LINKEDIN_COOKIE`, no network access needed. The CI workflow (`.gith
[Read the thread](https://github.com/JohannsenLum/linkedin-api-mcp/issues/7) · 2026-08-10 · closed · 0 comments
### get_profile and search_people return the headline unfenced, contradicting the README's fencing guarantee
## What's wrong
A LinkedIn headline is free text the profile owner chose themselves (LinkedIn allows roughly 220 characters, and people routinely fill it with slogans or full sentences). `README.md` (around line 293) says: "Anything read off a LinkedIn page (a headline, an about section, a message) passes through your agent as data. It is fenced before your agent sees it."
The code does not do this for headline. In `src/linkedin_mcp/tools/people.py`:
- Line 741: `headline = clean(card.get("he
[Read the thread](https://github.com/JohannsenLum/linkedin-api-mcp/issues/6) · 2026-08-10 · closed · 0 comments
### Selectors have no early warning when LinkedIn changes its markup
## The problem
This server reads rendered pages. When LinkedIn changes its markup, tools start returning `parse_failed` and nobody knows until a user reports it.
That is not hypothetical. v0.0.1 and v0.0.2 shipped with selectors that returned `parse_failed` on **every page**, because LinkedIn had moved to hashed per-build class names (`b0712e9a`, `_129ac5aa`), removed the `id="experience"` section anchors, and stopped using `h1` on profiles. Two releases went out broken before anyone ran them
[Read the thread](https://github.com/JohannsenLum/linkedin-api-mcp/issues/5) · 2026-08-09 · open · 0 comments
### get_inbox cannot return conversation_id, so get_conversation is hard to reach
## The problem
`get_inbox` returns participant, preview, timestamp and unread state correctly, but `conversation_id` is always `null`. That makes `get_conversation` awkward to use: you can see a thread exists but cannot open it.
## Why it is null, and why this is not a simple selector fix
I checked this against a real captured inbox page. Conversation rows carry **no `href`, no `data-urn`, and no id attribute anywhere in the row's subtree**. LinkedIn binds each row's click to an in-memory obj
[Read the thread](https://github.com/JohannsenLum/linkedin-api-mcp/issues/2) · 2026-08-09 · open · 0 comments
### search_posts returns null for reaction and comment counts
## What happens
`search_posts` correctly extracts the author, headline and post body, but `reactions` and `comments` always come back `null`.
search_posts: 2 posts author=Anthony M. Gonzales, MBA reactions=None comments=None
Confirmed against a live account on v0.0.3.
## Why it is worth fixing
Engagement is most of what makes a post search useful. Without it a model cannot tell a post nobody read from one that landed, so it has no basis for ranking or summarising what it found
[Read the thread](https://github.com/JohannsenLum/linkedin-api-mcp/issues/1) · 2026-08-09 · open · 0 comments
The remaining reports are on [the project's issue tracker](https://github.com/JohannsenLum/linkedin-api-mcp/issues).