Repository navigation
Releases
0.3.8 — wait for required fields
What was wrong
companies.get threw LAYOUT_UNSUPPORTED on a live company page even though the page renders completely. The reader required the company name immediately after navigation, before the page had rendered it: textOf with required: true took a single count, while the list readers already wait.
That single missing wait also caused a misdiagnosis: an early probe saw no <main> and no h1 and sent 0.3.7 after selector fallbacks that could never help. A probe with a four-second settle found main and exactly one h1, the company name.
What to expect now
- Required single fields — the company name, the job title, and the job-page presence check — are retried for up to five seconds with the same bound and step the list readers use.
- The first pass is immediate, so a page that already has the element adds no delay and every existing fixture behaves exactly as before.
- The read still fails closed: if the field never appears, it throws
LAYOUT_UNSUPPORTEDafter the bound.
Verified live on 2026-10-23
companies.getnow parses and returns the company name on the page that failed in 0.3.7.jobs.getkeeps returning title and url.
Action required
None. npm i -g linkedin-api-mcp@0.3.8 or let the plugin pick it up.
Known and deliberate
- Optional fields on the same pages (company followers, about) are still read once and immediately, so a field that renders after the name can be null.
- A page that genuinely lacks the field now takes about five seconds to fail instead of about a tenth of a second.
parseJobCardstill requires its title without a settle; list reads were out of scope.
by FiredMosquito831
0.3.7 — company pages and job titles
What was wrong
Two reads failed on the live site for measured reasons:
jobs.getlooked for the job title in anh1, and the job page renders it as anh2insidemain.companies.getrequiredmain h1, and the company page renders with no<main>element at all.
What to expect now
jobs.getfinds the title from anh2insidemain, after the existingh1candidates.companies.gettries[role="main"] h1, thensection h1, then a page-levelh1, aftermain h1.- Both stay fail-closed: no heading, no name or title.
Verified live on 2026-10-23
jobs.getreturned a populated record on a real job page: title present, url present. This part of the release works.companies.getstill returnsLAYOUT_UNSUPPORTED. The company page has noh1anywhere, so every h1-based candidate misses. The added fallbacks are correct for a page that has anh1, but they do not help this one.
Action required
None. npm i -g linkedin-api-mcp@0.3.7 or let the plugin pick it up.
Known and deliberate
companies.getremains unsupported on a live company page. The next step is to measure where the company name actually lives, not to add another fallback.jobs.getstill has nocompanyfield on the live page it was checked against.- The page-level
h1fallback takes the firsth1in document order; on a page whose site chrome has anh1before the company name, the wrong name could be returned.
by FiredMosquito831
0.3.6 — company posts and people search
What was wrong
Two reads failed on every call:
companies.postsused the feed's post-card ladder. The company posts page renders nodata-testid="mainFeed"and no reaction-controlled cards, so nothing matched even though the page shows posts.search.peopleused the shared search ladder, which is job-only. People results render aslistitemcards whose links are not/in/links, so no row or title could match, and the unqualifiedmain lihit the pagination control first.
What to expect now
companies.postsparses themain [role="article"]cards on a company posts page, appended after the existing ladder and wired only to this operation.search.peopleparsesmain [role="listitem"]cards: the name as the title and the card's link as the url.feed.list,posts.list,search.jobsandjobs.searchare unchanged, proven byte-identical on fixtures.
Action required
None. npm i -g linkedin-api-mcp@0.3.6 or let the plugin pick it up.
Known and deliberate
- Verified live on 2026-10-23:
search.peoplereturned 3 rows with a title and url on all 3.companies.postsreturned 3 rows but only the text field — no title and no permalink. Treat company post records as partial. - The person name and headline candidates are structural (
pelements), not measured markup; they resolved live on this account but are the most likely point of failure if LinkedIn changes the card. - Pagination exclusion assumes the pagination controls carry no
role="listitem".
by FiredMosquito831
0.3.5 — live check covers every read
What was wrong
linkedin experimental live-check accepted only a fixed list of seven operation names. Everything else — search.companies, search.posts, analytics.profile-views, jobs.get, invitations.received and the rest — was rejected with "Unknown operation(s) … Live checks are read-only", even though the catalog knows they are reads. The one command that can verify an adapter against the real site therefore could not verify most adapters.
A second defect showed up while fixing the first: under --all-reads --url <company URL>, reads that need a different input shape were reported as failed (Failed: INVALID_INPUT). They were never attempted, so the report claimed a failure that had not happened.
What to expect now
--operationsaccepts any catalog read, not just the default seven.--all-readschecks every catalog read, in catalog order.- An operation whose input does not match it, or that lacks its
--url/--query, is reported as skipped, never as failed. - The default run is unchanged: same seven operations, same output, same navigation count.
--all-readstogether with--operationsis a validation error, not a silent preference.
Action required
None. npm i -g linkedin-api-mcp@0.3.5 or let the plugin pick it up.
Known and deliberate
--all-readsalone runs the 13 reads that need no target and skips the 20 that do. One--urland one--queryare shared by every read that needs them, so a company URL is not also a post URL.- A skipped operation can hide an adapter that rejects a valid input. The skip line is the signal; the URL-family rule still lives in the adapter (
resolveUrl), not in the catalog. - A full
--all-readsrun navigates the member's own account many times; run it deliberately, not on a schedule. - Nothing here was checked against live LinkedIn by the automated suite.
by FiredMosquito831
0.3.4 — search companies, search posts, and honest analytics errors
What was wrong
Two read surfaces failed on every query:
search.companiesandsearch.postsreturnedLAYOUT_UNSUPPORTED. The search row ladder only knew job-card markup, so no company or post row could ever match. The title lookup is required, so even a matching row would have failed.analytics.profile-viewsreturnedLAYOUT_UNSUPPORTEDwhen LinkedIn redirected the request to/feed/. That redirect is an access gate, not a layout change, and misreporting it sent readers looking for a selector bug that did not exist.
What to expect now
search.companiesreturns company rows: the title comes from the company link, skipping the image-only logo link.search.postsreturns post rows that carry a reaction control — the same rule the feed reader uses — so suggested-people cards in the same list are excluded.analytics.profile-viewsreportsACCESS_RESTRICTED(exit 4) with a message that says the page redirected away.- Every other operation keeps its previous behaviour on a route leave:
LAYOUT_UNSUPPORTED.
Action required
None. npm i -g linkedin-api-mcp@0.3.4 or let the plugin pick it up.
Known and deliberate
- The new candidates are proven on synthetic fixtures, not on live pages. A live
experimental live-checkis the next step; until it runs, treat the fix as unconfirmed on the real site. search.peopleis still unsupported: its rows carry no anchors, so no row signature has been measured. It is left failing closed rather than guessed.- Post
urlandidstill come from the first link in a row, which may be the author profile. - Verified against the registry:
latest= 0.3.4,gitHead=98e34c0, tarball SHA-512 equalsdist.integrity, SLSA provenance present.
by FiredMosquito831
0.3.3 — visible challenges only
What was wrong
A read-only company-page check reported HUMAN_INTERVENTION_REQUIRED on a page that returned HTTP 200, showed no verification prompt, and had no checkpoint route. The detector counted any matching element: every normal LinkedIn page carries a reCAPTCHA Enterprise anchor iframe that is 0×0, visibility:hidden, and inside a display:none ancestor. Counting it made ordinary pages look like challenges, which also made a live read pass stop early and be misreported.
What to expect now
- A hidden background frame no longer stops an operation.
- A visible challenge — or a visible dialog, alert, or heading with explicit verification wording — still stops the operation and reports
HUMAN_INTERVENTION_REQUIRED. - Checkpoint routes and HTTP 401/403/429 still stop the operation, unchanged.
- No frame is removed, disabled, entered, or solved. There is no bypass of any kind.
Action required
None. Upgrade with npm i -g linkedin-api-mcp@0.3.3 (or let the plugin's pinned version pick it up), then re-run linkedin experimental live-check if you had reads stopping on a challenge.
Known and deliberate
- A challenge rendered inside an iframe whose host element stays 0×0 is caught by the verification-wording check rather than the frame check; the wording test is a heuristic.
- Write adapters remain unverified live (0 of 21). Nothing about writes changed in this release.
- Verified against the registry:
latest= 0.3.3,gitHead=96909b2, tarball SHA-512 equalsdist.integrity, SLSA provenance present.
by FiredMosquito831
0.3.2 — live-verification fixes
What changed
The browser adapters were verified against a real signed-in account for the first time. The live run showed that LinkedIn obfuscates its class names, so every class-based selector the adapters relied on was dead. This release moves them onto structural anchors and fixes what the real pages exposed.
Fixed
- Obfuscated markup: selectors now key on
data-testid,componentkey,data-job-id, roles and aria labels. - Feed accuracy: the feed list mixes posts with suggested people and ad cards. Only list items carrying a reaction control are treated as posts, and the author is read from the first profile link that renders a name.
- Accessibility-tree gaps: some live controls are excluded from the accessibility tree, so role queries returned zero for a control that exists. Resolution now tries role, then aria label, then the attribute selector, after waiting for the control to render.
- Connections route:
/mynetwork/invite-connect/connections/. - Intermittent SPA 404: accepted only when the app shell actually renders.
- Empty accounts: zero posts, conversations or connections now return an empty result instead of a layout failure.
- Inbox rows: live rows are the thread links themselves; the new-message stub is excluded.
- Outcome honesty: a verification challenge before dispatch reports
AUTH_REQUIRED(exit 3), not an uncertain outcome (exit 8).
Added
approvals approve --yesremoves the typed prompt while still requiring the exact reviewed digest.- OAuth login defaults to a registered HTTPS redirect, because LinkedIn rejects HTTP redirects.
- Browser login waits for the session cookie when no terminal is attached.
HANDOFF-2026-10-22.mdrecords the measured status.
Measured live status
Reads: 7 of 7 report ok. profile.get, feed.list, companies.get and jobs.search parse real data; posts.list, inbox.list and connections.list prove the empty-account path only.
Writes: none verified live. The first attempts at companies.follow were interrupted by a LinkedIn manual-verification challenge and changed nothing. Write adapters remain fixture-tested; do not run them in bulk.
Upgrade
npm install -g linkedin-api-mcp@0.3.2