Skip to content

v0.0.3

Choose a tag to compare

@JohannsenLum JohannsenLum released this 09 Aug 18:41
· 10 commits to main since this release

The first version whose parsers have actually been run against LinkedIn. 0.0.1 and 0.0.2 returned parse_failed on every page, and send_message reported success for messages it never sent. If you installed either, upgrade.

uvx linkedin-api-mcp@latest auth
uvx linkedin-api-mcp@latest --test

Why the old versions did not work

LinkedIn ships hashed, per-build CSS class names now (b0712e9a, _129ac5aa). The stable-looking classes every scraper targets no longer exist, the id="experience" section anchors are gone, and a profile page has zero h1 elements. Anything matching on a class returns nothing.

Parsing now anchors on what a rebuild cannot rename:

  • document.title and href patterns for identity
  • a result row is the smallest ancestor containing exactly one entity link
  • fields classified by shape, not position, so a 22-character headline and a 60-character one parse the same way
  • text nodes walked and repeats dropped, because LinkedIn renders every label twice, once visible and once for screen readers

Verified against a live account

Tool
get_my_profile, get_profile name, headline, location, public id
search_people name, degree, headline, location
get_company, search_companies name, industry, size, headquarters
search_jobs title, company, location, on-site/remote
search_posts author and body; counts null
get_inbox participant, preview, timestamp; conversation_id null
send_message delivered, then confirmed by reading the thread back

The bug worth reading about

send_message used to click a send button and return. Nothing checked delivery, so a wrong-but-clickable element produced {"sent": true} for a message that never existed. Confirmed against a real account: the tool said sent, the message was not there.

A read tool that lies gives you wrong information. A write tool that lies makes you believe you contacted someone, and you wait for a reply that is not coming.

Both send paths now poll until the text appears in the conversation and raise send_unconfirmed otherwise, telling you to check the browser before retrying so a partial send never becomes two messages.

Related: the Message control is an <a> pointing at /messaging/compose/?recipient=, and two decoys sit beside it in the same card. Links with screenContext=PROFILE_HIGHLIGHTS carry a prefilled body= ("Hi Basil, we both worked at PayPal..."), and sidebar links point at a different person. Either would have sent the wrong thing, and delivery verification would have happily confirmed it. Both are rejected now.

Also fixed

  • A malformed cookie sends LinkedIn into a redirect loop. That was reported as navigation_failed with a hint to check your network. It now says the cookie is malformed.
  • auth raised an unhandled EOFError in any piped or containerised shell. pbpaste | linkedin-api-mcp auth works now.
  • The profile top card picked the organisation line as the headline for anyone whose headline is under 25 characters.

Known gaps, stated plainly

  • conversation_id is null from the inbox. LinkedIn binds each row's click to an in-memory object rather than a URL, so there is nothing in the row to read.
  • Post reaction and comment counts return null.
  • experience and education load only on scroll and are still empty.

Disclaimer: This is an independent, community project. It is not affiliated with, authorized by, endorsed by, or sponsored by LinkedIn Corporation or Microsoft. "LinkedIn" is a registered trademark of LinkedIn Corporation and is used here only descriptively to identify the third-party service this software interoperates with.