MCP server that gives AI assistants access to LinkedIn Sales Navigator contact and account search.
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Topics declared
- ✓Documented (README)
claude mcp add linkedin-sales-nav-mcp -- uvx patchright{
"mcpServers": {
"linkedin-sales-nav-mcp": {
"command": "uvx",
"args": ["patchright"]
}
}
}MCP Servers overview
<p align="center">
<img src="docs/banner.jpg" width="100%"
alt="An AI agent at a laptop, streaming results into a stack of contact records beside a database and a magnifier.">
</p>
# LinkedIn Sales Navigator MCP Server
[](https://github.com/nick-choudhary/linkedin-sales-nav-mcp/actions/workflows/ci.yml)
[](https://pypi.org/project/linkedin-sales-nav-mcp/)
[](LICENSE)
[](https://lobehub.com/mcp/nick-choudhary-linkedin-sales-nav-mcp)
<!-- mcp-name: io.github.nick-choudhary/linkedin-sales-nav-mcp -->
MCP server that gives AI assistants (Claude Desktop, Claude Code, any MCP
client) access to **LinkedIn Sales Navigator contact and account search** —
by driving a **real, logged-in browser on your machine** and capturing Sales
Navigator's own search API responses.
## Why this design (and why not cookie-replay)
The common approach — copy your `li_at` + `JSESSIONID` cookies and replay them
as HTTP requests from a server — gets you **logged out repeatedly**. LinkedIn
scores each session on IP, browser fingerprint, TLS, and the full cookie set;
two replayed cookies from a different machine look like a hijacked session, so
it invalidates them.
This server does the opposite. It keeps a persistent browser profile you log
into **once, by hand**, and then lets that genuine session do the work:
```
MCP client (Claude) ──stdio/HTTP──> this server ──drives──> your logged-in Chromium ──> Sales Navigator
│
captures the JSON the browser
itself receives (page.on "response")
```
Every request to LinkedIn originates from the real browser: your IP, your
fingerprint, your full cookie jar, browser-generated CSRF/track headers, and
the session is refreshed by the browser as normal. Nothing is replayed or
reconstructed. That is what keeps you signed in.
We **never** automate the login itself — typing credentials is a strong bot
signal. You sign in manually once; the profile persists.
## Tools
| Tool | What it does |
|------|--------------|
| `search_contacts` | People/lead search from a Sales Navigator URL. Navigates + paginates in the browser, saves records to SQLite, returns a small progress summary. |
| `search_accounts` | Company/account search from a Sales Navigator URL. Same, for accounts. |
| `check_session_status` | Reports whether the browser profile has a live Sales Navigator session (tells you if you need to re-run `--login`). |
| `list_queries` | Every saved search with its progress: `url_hash`, status, `last_page`, `records_count`. |
| `get_results` | Pull a bounded slice (1–200) of a saved query's records into the conversation for analysis. |
| `export_results` | Write a saved query's records to JSON and/or CSV under the output folder. |
Both search tools take a **full Sales Navigator URL** (build the search in the
UI, copy it from the address bar) and a `pages` count (1–10, 25 results each).
Beyond tools, the server exposes one **resource** (`sales-nav://queries` —
saved queries and their progress as attachable JSON context) and one
**prompt** (`sales_nav_search_workflow` — the step-by-step prospecting
playbook, for clients that support MCP prompts).
### Search tools do not return the records
This is deliberate, and it is the thing most likely to surprise you. Records go
to SQLite; the tool returns only a status object, so a 250-row scrape doesn't
dump 250 rows into the model's context:
```jsonc
{
"url_hash": "a6ca46c9365bce93",
"scraper_type": "contacts",
"status": "paused", // new | in_progress | paused | complete
"new_records_this_call": 25,
"total_records": 25,
"total_available": 11897313,
"pages_fetched": 1,
"last_page": 1,
"next_page": 2, // null once exhausted
"raw_dir": null, // set when include_raw=true
"suggestion": "Saved 25 records so far (through page 1) ..."
}
```
To get at the data, call `get_results` (a sample) or `export_results` (files),
or read the SQLite database directly.
**Searches are resumable.** The URL is hashed to a `url_hash`; calling the same
URL again continues from `next_page` rather than restarting. Sales Navigator
caps any single search at 100 pages (2,500 results) no matter what
`total_available` reports — to go past that, split the search into narrower
filters and let de-duplication merge the slices.
## Setup
From PyPI (no clone needed):
```bash
uvx --from linkedin-sales-nav-mcp patchright install chromium # one-time browser download
```
Or from source:
```bash
git clone https://github.com/nick-choudhary/linkedin-sales-nav-mcp
cd linkedin-sales-nav-mcp
uv sync
uv run patchright install chromium # one-time browser download
cp .env.example .env # optional; defaults are fine on your machine
```
### 1. Log in once
```bash
uvx linkedin-sales-nav-mcp --login # PyPI install
# or, from a clone: uv run linkedin-sales-nav-mcp --login
```
A browser window opens. Sign into LinkedIn, open Sales Navigator, finish any
2FA/checkpoint. The server detects the signed-in session and saves the
profile, then exits.
### 2. Run the server
```bash
uvx linkedin-sales-nav-mcp # stdio, PyPI install
# or, from a clone: uv run linkedin-sales-nav-mcp
```
### Claude Desktop / Claude Code config
PyPI install:
```json
{
"mcpServers": {
"sales-navigator": {
"command": "uvx",
"args": ["linkedin-sales-nav-mcp"]
}
}
}
```
From a clone:
```json
{
"mcpServers": {
"sales-navigator": {
"command": "uv",
"args": ["run", "--project", "/path/to/linkedin-sales-nav-mcp", "linkedin-sales-nav-mcp"]
}
}
}
```
No secrets in the config — the session lives in the browser profile.
**Use `--project`, not `--directory`.** Both point uv at the repo, but
`--directory` *changes the working directory* to it, which would send your
exports into the repo instead of the project you are working in. `--project`
leaves the working directory alone, which is what the export layout below
expects.
### Installing it once, for every project
Pointing each config at a repo path gets tedious. Install the command onto your
PATH instead:
```bash
uv tool install linkedin-sales-nav-mcp # from PyPI
# or: uv tool install /path/to/linkedin-sales-nav-mcp (from a clone)
```
Then every project's config is just:
```json
{
"mcpServers": {
"sales-navigator": {
"command": "linkedin-sales-nav-mcp"
}
}
}
```
No path, no flags, and nothing to update when you move the repo. Re-run the
install with `--force` after pulling changes to pick them up.
Either way the database is shared and the login carries over, so a new project
needs no `--login` of its own — only its own `.mcp.json` entry.
### One server at a time
Configure it in as many projects as you like, but only run one at once. The
browser profile is a persistent Chromium profile and Chromium takes an
exclusive lock on it, so a second server starting while the first is live will
fail to launch its browser. If you use `uv run`, the first server also holds
the repo's `.venv`, and a second `uv run` can fail while trying to sync it.
### Environment variables
| Variable | Default | Purpose |
|----------|---------|---------|
| `USER_DATA_DIR` | `~/.linkedin-sales-nav/profile` | Persistent browser profile |
| `HEADLESS` | `false` | `false` = visible window (safest); `true` = headless (more detectable) |
| `CHROME_PATH` | — | Use your own Chrome instead of bundled Chromium |
| `PROXY_SERVER` | — | Leave empty on your own machine; only for a residential exit node if remote |
| `NAV_TIMEOUT` / `CAPTURE_WAIT` / `LOGIN_TIMEOUT` | `60` / `25` / `300` | Timeouts (s) |
| `TOOL_TIMEOUT` | `600.0` | Per-tool MCP timeout (s) — must exceed the pacing budget below |
| `PACING_ENABLED` | `true` | Human-like delays between pages (see below) |
| `PAGE_DELAY_MIN` / `PAGE_DELAY_MAX` | `3.0` / `8.0` | Random dwell before advancing a page (s) |
| `LONG_PAUSE_EVERY` | `5` | Take a longer break every N pages (`0` disables) |
| `LONG_PAUSE_MIN` / `LONG_PAUSE_MAX` | `20.0` / `45.0` | Length of that break (s) |
| `STATE_DIR` | `~/.linkedin-sales-nav` | Where `sales_nav.db` and raw captures live — follows you between projects |
| `OUTPUT_DIR` | `output` | Where JSON/CSV exports are written, relative to where the server runs |
| `TRANSPORT` / `HOST` / `PORT` / `HTTP_PATH` | `stdio` / `127.0.0.1` / `9000` / `/mcp` | Transport |
| `LOG_LEVEL` | `WARNING` | `DEBUG`, `INFO`, `WARNING`, `ERROR` |
## Where the data goes
Two directories, because the data has two lifetimes.
**State** lives in `<STATE_DIR>` (default `~/.linkedin-sales-nav`, beside the
browser profile): the SQLite database at `sales_nav.db` plus any raw captures
under `<url_hash>/raw/`. It belongs to your LinkedIn account rather than to any
one project, so it is the same database wherever you launch the server from —
`list_queries` shows one history across every folder.
**Exports** are project artifacts, so they resolve against the working
directory. `export_results` writes JSON/CSV into `<OUTPUT_DIR>/<url_hash>/`
(default `output/<url_hash>/`), landing in whichever project you ran the search
for. The database stays the source of truth; exports are generated from it on
demand.
> **Upgrading from 1.0.** The database used to live in `output/sales_nav.db`
> relative to the launch directory. As of 1.1 it is at
> `~/.linkedin-sales-nav/sales_nav.db` and is no longer read from the old path,
> so an existing `output/sales_nav.db` will look empty. Either move it (take
> `sales_nav.db`, `sales_nav.db-wal`, `sales_nav.db-shm` and the `<url_hash>/`
> dirWhat people ask about linkedin-sales-nav-mcp
What is nick-choudhary/linkedin-sales-nav-mcp?
+
nick-choudhary/linkedin-sales-nav-mcp is mcp servers for the Claude AI ecosystem. MCP server that gives AI assistants access to LinkedIn Sales Navigator contact and account search. It has 1 GitHub stars and its last recorded update is dated 2026-08-20.
How do I install linkedin-sales-nav-mcp?
+
You can install linkedin-sales-nav-mcp by cloning the repository (https://github.com/nick-choudhary/linkedin-sales-nav-mcp) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is nick-choudhary/linkedin-sales-nav-mcp safe to use?
+
Our security agent has analyzed nick-choudhary/linkedin-sales-nav-mcp and assigned a Trust Score of 95/100 (tier: Verified). See the full breakdown of passed checks and flags on this page.
Who maintains nick-choudhary/linkedin-sales-nav-mcp?
+
nick-choudhary/linkedin-sales-nav-mcp is maintained by nick-choudhary. The last recorded GitHub activity is dated 2026-08-20, with 0 open issues.
Are there alternatives to linkedin-sales-nav-mcp?
+
Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.
Deploy linkedin-sales-nav-mcp to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/nick-choudhary-linkedin-sales-nav-mcp)<a href="https://claudewave.com/repo/nick-choudhary-linkedin-sales-nav-mcp"><img src="https://claudewave.com/api/badge/nick-choudhary-linkedin-sales-nav-mcp" alt="Featured on ClaudeWave: nick-choudhary/linkedin-sales-nav-mcp" width="320" height="64" /></a>More MCP Servers
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
The fastest path to AI-powered full stack observability, even for lean teams.
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!