LinkedIn & Sales NavigatorTeardown
The 2-star LinkedIn MCP server has more outbound capability than the 2,800-star one
Source audit of 6 LinkedIn MCP repos: the 2-star repo has Sales Navigator, invite origination, and InMail send — the most-starred repo lacks them.
What we ranSource audit of 6 LinkedIn/Sales Navigator MCP repos at named commits; tool surfaces read from source; star counts captured 2026-07-22. Includes a v3 correction of three false-absence claims found across successive passes.
Capability across six LinkedIn MCP repos runs opposite to GitHub stars.
stickerdaniel/linkedin-mcp-server, 2,854 stars, has two write tools and no
Sales Navigator at commit b872f92. bhaktatejas922/unipile-linkedin-mcp, 2
stars, has Sales Navigator search, invitation origination, InMail send, and
direct messages at commit a6a28cb — the most complete outbound surface in
the set. Star count tells you nothing about capability here.
Kairon builds a competing LinkedIn/Sales Navigator MCP server, so read what follows with that in mind. The method is a source read anyone can reproduce — shallow-clone a repo, grep its tool declarations at a named commit, done — the same discipline as wiring Search Console to an agent through Application Default Credentials instead of trusting a summary. Run it yourself before trusting a vendor's audit of its own category, including this one.
On LinkedIn automation. LinkedIn's User Agreement prohibits automated access to the platform, and every tool audited below automates it. This is a source read of what they declare — not a test of whether they work, not permission, not a safety guarantee, and not advice to run them. Your account, your risk.
Earlier passes of this same audit got three facts wrong — all false negatives: two from a grep truncated before it finished listing a repo's tools, and a third that called a repo's tools unenumerable when its own docs listed them. The corrections are below, each with the fix.
Method for all of it: shallow clone, read the tool declarations in source at the commit shown, pull stars/license/last-push from the GitHub API. No LinkedIn account was authenticated and no request reached LinkedIn — source and metadata only.
Capability by repo
| Repo | Stars | Sales Nav search | Invite | InMail send | DM |
|---|---|---|---|---|---|
| stickerdaniel | 2,854 | ✗ | ✓ connect_with_person | ✗ | ✓ send_message |
| eliasbiondo | 161 | ✗ | ✗ | ✗ | ✗ (read-only) |
| felipfr | 75 | ✗ | ✗ | ✗ | ✓ send-message |
| LaGrowthMachine | 29 | ~ (URL import, not a search endpoint) | ✗ (no atomic tool) | ✗ | ✓ send_linkedin_message |
| globodai | 4 | ✓ | ✗ | ✓ linkedin_send_inmail | ✗ |
| bhaktatejas922/unipile | 2 | ✓ search_people_sales_nav | ✓ send_invitation | ✓ send_inmail | ✓ send_message, start_chat |
Star counts and last-push dates captured 2026-07-22; commit hashes are pinned
and stable. LaGrowthMachine's row is read from the tools its repo documents
in CLAUDE.md at f1f8402, not verified against the live
mcp.lagrowthmachine.com server; every other row is read from source at the
commit shown.
The most complete outbound surface in the set belongs to the least-starred repo.
One caveat before that reads as a scoreboard: these are not like-for-like.
unipile-linkedin-mcp is a thin wrapper over Unipile, a paid third-party API,
and stickerdaniel's own README points readers at Unipile as the paid route to
Sales Navigator and InMail. So part of what the table shows is a free
self-hosted scraper measured against a wrapper on a commercial service that
already solved those endpoints. "More capability per star" is the accurate
reading; "better" is not, and we have not measured setup cost, account
requirements, or whether any of it works.
bhaktatejas922/unipile-linkedin-mcp — commit a6a28cb, 22 tools
2 stars, Python, MIT, last pushed 2026-01-22. Unipile-API-backed rather than
browser scraping. Tools extracted from unipile_linkedin.py by matching
@mcp.tool() decorators to their function signatures:
list_accounts() get_my_profile()
search_people(keywords, location, ...)
search_people_sales_nav(keywords, location, ...) <- Sales Navigator
search_companies(keywords, industry, ...)
search_posts(keywords, sort_by, date_posted, ...)
get_search_params(param_type, query)
get_profile(provider_id, sections) get_company_profile(company_id)
send_invitation(provider_id, message) <- originates a request
list_invitations_sent(limit, cursor)
list_invitations_received(limit, cursor)
accept_invitation(invitation_id) decline_invitation(invitation_id)
cancel_invitation(invitation_id) list_relations(limit, cursor)
list_chats(limit, cursor, unread_only)
get_chat_messages(chat_id, limit, cursor)
send_message(chat_id, text) start_chat(attendees_ids, text)
send_inmail(attendees_ids, subject, text) <- InMail send
get_inmail_credits()
search_people_sales_nav is a Sales Navigator search endpoint — one of two
in the set, alongside globodai's, below. send_invitation(provider_id, message) originates a connection request rather than acting on one that
already exists. send_inmail(attendees_ids, subject, text) is a second
InMail send tool, also alongside globodai's. send_message and start_chat
cover direct messages.
stickerdaniel/linkedin-mcp-server — commit b872f92, 16 tools
2,854 stars, Python, Apache-2.0, last pushed 2026-07-22. Two write tools live
in linkedin_mcp_server/tools/*.py:
messaging.py: send_message(linkedin_username: str, message: str, confirm_send: bool, ctx: Context, profile_urn: str | ...)
person.py: connect_with_person(linkedin_username: str, ctx: Context, note: str | None = None, ...)
confirm_send: bool is a required positional argument, not a config flag —
every call has to explicitly opt in to sending. That is a deliberate safety
design, worth crediting regardless of who ships it.
Full tool surface at this commit:
get_company_profile get_company_posts search_companies
get_company_employees get_feed get_job_details
search_jobs get_inbox get_conversation
search_conversations send_message get_person_profile
search_people connect_with_person get_sidebar_profiles
get_my_profile
No Sales Navigator:
$ grep -ril "sales.nav|salesnav|sales_nav" --include=*.py
scraping/connection.py
scraping/extractor.py
tests/test_scraping.py
All three .py hits are incidental: scraping/connection.py:66 and
scraping/extractor.py:236 are the same DOM comment — "Primary action
<button>s (Follow, Connect, Save in Sales Navigator) carry aria-label" —
and tests/test_scraping.py:889 is a test fixture comment. Widening the grep
to .md, the discipline this post insists on elsewhere, surfaces a fourth
mention at README.md:25: marketing copy pointing readers at Unipile's hosted
Sales Navigator support, not a tool this repo declares. The claim holds —
every Sales Navigator reference in this repo is documentation or DOM text, not
a search endpoint.
No InMail send either, just two read-side mentions: tools/messaging.py:107
disambiguates whether an inbox thread is an InMail, and
scraping/extractor.py:396 is a regex stripping the upsell string ^Get up to .+ replies when you message with InMail$ out of scraped text.
globodai-group/mcp-linkedin-sales-navigator — commit aeb02f3, 7 tools
4 stars, TypeScript, MIT, last pushed 2026-02-05. Playwright-driven
(src/browser/navigator.ts). Tool files under src/tools/:
search.ts -> linkedin_search_leads
leads.ts -> linkedin_get_lead_profile, linkedin_save_lead
lists.ts -> linkedin_create_lead_list, linkedin_list_lead_lists
inmails.ts -> linkedin_send_inmail
export.ts -> linkedin_export_leads
Sales Navigator is the product here, not a comment: linkedin_search_leads
is a Sales Navigator search endpoint, and linkedin_send_inmail is an InMail
send tool. No invitation-origination or direct-message tool appears in this
file set.
felipfr/linkedin-mcpserver — commit d87e7f3, 7 tools
75 stars, TypeScript, MIT, last pushed 2025-03-28. Seven server.tool(
registrations in src/: get-connections, get-my-profile,
get-network-stats, get-profile, search-jobs, search-people,
send-message. send-message is the one write path in this set.
eliasbiondo/linkedin-mcp-server — commit 34d277c, 7 tools
161 stars, Python, MIT, last pushed 2026-03-08. Read-only at this commit:
get_person_profile, get_company_profile, get_company_posts,
get_job_details, search_people, search_jobs, close_browser. No write
tool appears in this file set.
LaGrowthMachine/gtm-system — commit f1f8402, a client for a hosted server
29 stars, Python, MIT, last pushed 2026-07-19.
This repo has now cost two corrections, both of the same kind. An earlier version of this post said it was "not an MCP server at all", on the strength of this grep:
$ grep -ril "mcp.server|FastMCP|@modelcontextprotocol" --include=*.py --include=*.ts --include=*.json
(no matches)
That was wrong, and the grep is why: it never searched .md. The repo's own
docs describe a live hosted server.
claude mcp add --scope user --transport http LaGrowthMachine \
https://mcp.lagrowthmachine.com
So the project does expose an MCP tool surface — the server is hosted, not
in-repo. What sits in the repo is the client side: CLAUDE.md, install.sh,
and a skills/ directory (catch-opportunities, fuel-my-pipeline,
get-qualified-meetings).
The next version fixed that sentence and then wrote a fresh false-absence in
its place: that the tools could not be enumerated without a live account, so
the row had to stay unknown. That is the third false-absence in this audit,
and it landed on the very repo the post keeps using to teach the lesson. The
enumeration was in the repo the whole time. CLAUDE.md at f1f8402 (commit
title: "refresh MCP tool list") documents roughly 30 tools under the
mcp__LaGrowthMachine__* namespace. A sample of what it lists:
create_audience_from_linkedin_url— create an audience directly from a Sales Navigator search URLsend_linkedin_message— send a LinkedIn reply inside a conversationsend_email_message,list_campaigns,get_campaign_stats,get_linkedin_post,execute_bigquery_query, plus inbox, workspace, and identity tools
(CLAUDE.md also lists higher-level skills — sales-nav-search-builder,
won-deal-icp-finder, and others — which are agent workflows layered on those
tools, not entries in the mcp__LaGrowthMachine__* namespace. This post counts
tools, not skills.)
Read the shape, not the count. Sales Navigator access here is a URL import
(create_audience_from_linkedin_url) rather than a live search endpoint like
unipile's search_people_sales_nav; LinkedIn messaging is
send_linkedin_message, an in-conversation reply. The documented surface
includes no atomic connection-request tool and no InMail-send tool — which is
why those two cells read ✗ and the DM cell reads ✓.
One honest boundary remains, narrower than unknown: these are the tools the
repo documents, not tools we ran. We have not verified them against the live
mcp.lagrowthmachine.com server, which needs an account we do not have.
"Documented in-repo" and "verified against the live server" are different
claims; this row is the first, and it is flagged as such under the table.
The architecture is worth naming because it is the one we use ourselves.
Kairon's MCP is hosted at app.heykairon.com/mcp with the code in apps/api.
Grep the wrong directory of our repo and you would "prove" we have no server
either.
Where the first pass got it wrong
This audit ran three times: a first extraction at 2026-07-21T03:18:10Z
(clones and greps, 03:18–03:35Z), a deepening pass at 2026-07-21T10:12:05Z
that closed a gap on felipfr's tool declarations and refuted two of the first
pass's own conclusions, and an independent re-clone of all six repos on
2026-07-22 that caught a third.
- The first pass claimed
linkedin_send_inmail(globodai) was the only InMail send tool across the six repos. False.bhaktatejas922/unipilealso hassend_inmail(attendees_ids, subject, text). - The first pass claimed unipile only carried invitation lifecycle, not
origination. False.
send_invitation(provider_id, message)originates a request. The tool list that produced this claim came from agrep ... | head -20against unipile's source that cut off before reaching thesend_*functions. - A later pass claimed LaGrowthMachine's tools could not be enumerated
without a live account, and left its row unknown. False, on the same
pattern. The repo's own
CLAUDE.mdatf1f8402(commit title: "refresh MCP tool list") documents roughly 30 tools undermcp__LaGrowthMachine__*—create_audience_from_linkedin_url,send_linkedin_message, and more (the namespaced tools;CLAUDE.mdlists higher-level skills separately). An account verifies those tools against the live server; it is not what reveals that the repo documents them.
All three errors trace to the same mistake: inferring that a tool doesn't exist
because it didn't show up in an extraction that was itself incomplete. The
second pass matched @mcp.tool() decorators to their full function
signatures instead of grepping and truncating. Any claim shaped like "repo X
doesn't have Y" needs the full tool list, not a slice of it — a head -20
on a grep is exactly the kind of slice that produces a false absence.
What this audit does not establish
- Whether any of it works. A tool declared in source is not a tool that works. No server was executed and no request reached LinkedIn.
- Reliability, rate limits, or ban risk. That needs a live run against an owned test account over time, deliberately not attempted here.
- Setup cost.
bhaktatejas922/unipile-linkedin-mcpis API-backed and presumably requires a Unipile account; that was not investigated and shouldn't be assumed either way.
The reproduction is a shallow clone and a grep against a commit hash you can check out yourself. More audits built the same way are on the Kairon blog.