linkedin-analyzer

linkedin-analyzer

MCP server that lets you analyze your own LinkedIn profile with a local LLM (LM Studio). It uses Playwright to reuse your browser session, fetch profile data as JSON, and provides tools for session management and profile analysis.

Category
Visit Server

README

LinkedIn Analyzer

License Release Python

Analyze your own LinkedIn profile through LM Studio using an MCP server and Playwright — without the official LinkedIn API.

The tool reuses your existing browser session (including 2FA) to fetch your profile data as structured JSON, which a local LLM can then analyze for optimization opportunities.

⚠️ Legal / Compliance notice

  • This tool uses browser automation, not LinkedIn's official API.
  • Using it may violate LinkedIn's Terms of Service. Account restrictions are theoretically possible.
  • Use it only for your own profile, for personal, non-commercial purposes. Do not scrape third-party profiles, do not hammer the site.
  • You are solely responsible for how you use this software.

Architecture

┌─────────────┐      ┌──────────────┐      ┌─────────────────────┐      ┌──────────┐
│ LM Studio   │ ───→ │ MCP Server   │ ───→ │ Background Server   │ ───→ │ Browser  │
│ (LLM)       │ MCP  │ (stdio)      │ HTTP │ (127.0.0.1:8766)    │      │ Playwright│
└─────────────┘      └──────────────┘      └─────────────────────┘      └──────────┘
Component Purpose
mcp-server/linkedin_mcp.py MCP server (stdio JSON-RPC) exposed to LM Studio
background_server.py Long-running daemon that keeps the browser open (port 8766)
session_manager.py Encrypts and persists the browser session locally
config.py Environment-driven configuration

Prerequisites

The repo assumes nothing except:

  • Python 3.10+ (Linux/macOS/Windows via WSL — a POSIX shell)
  • LM Studio (local, version 0.3.17+ with MCP support)
  • A LinkedIn account (you will log in manually once)

Everything else is installed by the repo itself: a virtualenv, the Python dependencies, the Playwright browser (a managed Chrome for Testing build — no separate Chrome install needed), a session-encryption key, the background server as an auto-start service (launchd on macOS, systemd on Linux, nohup fallback otherwise), and the MCP registration inside LM Studio. curl, lsof, gcc or any other CLI tools are not required.

Installation

# 1. Clone and enter the repo
git clone https://github.com/FinleyVeeDub/linkedin-analyzer.git
cd linkedin-analyzer

# 2. Configure (optional - all values have working defaults)
cp .env.example .env
# edit .env as needed (see below)

# 3. Install everything in one go: builds the environment, installs the
#    background server as an auto-start service, and registers the MCP server
#    in LM Studio (no manual JSON editing):
./scripts/install.sh

install.sh prints ok when done. It is safe to re-run (idempotent). To undo everything, run ./scripts/uninstall.sh (or ./scripts/uninstall.sh --purge to also remove the venv and saved sessions).

On Debian/Ubuntu you may need the venv module first: sudo apt-get install -y python3-venv — the scripts tell you this if it is missing.

[!NOTE] Playwright installs its own browser

Playwright downloads a managed Chrome for Testing build into venv/ (first run: ~150 MB) and launches that — you do not need a separate Chrome/Chromium installation. install.sh, bootstrap.sh and the LM Studio wrapper all run venv/bin/python -m playwright install chromium for you. If the browser is ever missing or broken, reinstall it with venv/bin/python -m playwright install chromium.

What gets installed

Service Where Purpose
Python virtualenv venv/ Isolated Python environment
Python deps + Playwright browser venv/ The only external dependencies
Playwright Chrome for Testing venv/ Managed Chromium downloaded by Playwright (no system Chrome needed)
Session encryption key ~/.linkedin-analyzer/session.key Encrypts the saved session
Background server service launchd agent / systemd user unit Keeps the browser open, auto-starts on boot
MCP server entry ~/.lmstudio/mcp.json Lets LM Studio launch the MCP server

First run inside LM Studio (no install.sh)

If you skip install.sh, the wrapper (scripts/linkedin-analyzer-mcp-wrapper.sh) bootstraps everything itself the first time LM Studio starts it. The slow part (downloading the Playwright browser) runs in the background so it does not hit LM Studio's MCP startup timeout; the first tool call may answer "not ready yet" for a few seconds.

Configuration (.env)

Variable Default Description
HOST 127.0.0.1 Bind address of the background server
PORT 8766 Port of the background server
SESSION_DIR ./browser_sessions Where the encrypted session file is stored
SESSION_ENCRYPTION_KEY (empty) Optional explicit Fernet key
SESSION_ENCRYPTION_KEY_FILE ~/.linkedin-analyzer/session.key Key file, created automatically if missing
BROWSER_HEADLESS False True for automated/headless runs

[!INFO] Port 8766 may already be occupied

.env is the single source of truth for the port — nothing needs to be edited in code. Every component reads it: config.py (pydantic-settings), background_server.py (settings.PORT), linkedin_mcp.py (stdlib dotenv reader), and all scripts (start-daemon.sh, the LM Studio wrapper, bootstrap.sh, install.sh) source .env before using PORT. A real environment variable always wins over .env.

On machines where another service already binds 8766 (e.g. the Hermes agent reserves 8766, in which case the analyzer was moved to 8767), LM Studio cannot reach the daemon and the MCP tools fail with a connection error. Fix: pick a free port and set PORT in .env, e.g. PORT=8767, then restart start-daemon.sh and LM Studio.

The 8766 fallback default (only used when PORT is set neither in .env nor as an environment variable — change it here only if you want a different default for everyone):

File Line Usage
config.py 13 Pydantic default for PORT
background_server.py 1143 Daemon bind port (settings.PORT)
mcp-server/linkedin_mcp.py 92 MCP server's base URL to the daemon
scripts/linkedin-analyzer-mcp-wrapper.sh 50 Wrapper default
scripts/bootstrap.sh 39 Bootstrap default
scripts/install.sh 40 Service install default
start-daemon.sh 30 Daemon start default
.env.example 6 Documented default

Running

Option A — Start the daemon manually

./start-daemon.sh          # starts background_server.py on PORT (default 8766)
./stop-daemon.sh           # stops it again

The background server must keep running while you use the MCP tools — it holds the browser open.

Verify it is up:

curl http://127.0.0.1:8766/health

Option B — Auto-start wrapper (used by LM Studio)

scripts/linkedin-analyzer-mcp-wrapper.sh is the command LM Studio launches. The wrapper locates Python 3.10+ itself, builds the environment on first run (the slow steps in the background), ensures a session key exists, starts the background server once its dependencies are ready, and then runs the MCP server in stdio mode itself:

{
  "mcpServers": {
    "linkedin-analyzer": {
      "command": "/path/to/linkedin-analyzer/scripts/linkedin-analyzer-mcp-wrapper.sh"
    }
  }
}

Note: install.sh writes this entry for you into ~/.lmstudio/mcp.json with the correct absolute path. If you write it by hand, replace /path/to/linkedin-analyzer with the real absolute path of your clone. No args are needed — the wrapper starts the stdio MCP server itself.

Setup in LM Studio

  1. Run ./scripts/install.sh once in the terminal (recommended).
  2. Restart LM Studio, switch to the Program tab in the right sidebar — the linkedin-analyzer MCP server should be listed as connected.
  3. Start a chat with the system prompt — pick docs/system-prompt.en.md (or the German docs/system-prompt.de.md) and paste it in.
  4. Ask the assistant to check your session or analyze your profile.

If the MCP server does not show up, re-add it manually via Install > Edit mcp.json with the snippet from Option B, then fully restart LM Studio (a cached server definition may otherwise keep the old command).

First login (one-time)

  1. Call the linkedin_login tool — the browser opens at LinkedIn's login page.
  2. Log in manually in the browser (2FA is supported).
  3. The session auto-saves as soon as the login is detected. You can also force it with linkedin_save_session.
  4. Verify with linkedin_check_session.

MCP tools

Tool Description
linkedin_check_session Check whether a session exists and you are logged in
linkedin_login Open the browser at LinkedIn's login page (does not wait for login)
linkedin_save_session Persist the current session after a manual login
linkedin_get_profile Fetch the raw profile data (JSON)
linkedin_analyze_profile Fetch the profile data for analysis
linkedin_get_posts Fetch your own recent posts from the activity tab (limit/scroll query args)
linkedin_get_post Fetch one post by URL (url query arg, urn:li:activity:...)
linkedin_analyze_posts Fetch your posts for analysis (limit/scroll query args)
linkedin_clear_session Delete the saved session

Tool calls forward only whitelisted arguments (see PARAM_WHITELIST in mcp-server/linkedin_mcp.py) to the background server as query parameters; anything else in arguments is ignored.

HTTP API (background server)

Endpoint Method Description
/health GET Health check
/check GET Session/login status
/login POST Open the browser at the login page
/save POST Persist the current session
/session DELETE Clear the saved session
/profile GET Full profile data (name, headline, about, experience, education, skills)
/posts GET Own posts from the activity tab (limit, scroll query args)
/post GET Single post by URL (url query arg, validated against urn:li:activity:...)
/debug, /debug/dom, /debug/selectors GET Debugging aids

Security

Aspect Implementation
Passwords Never stored in code
Session Stored locally and encrypted with Fernet (browser_sessions/)
2FA Fully supported during the initial login
Data Stays on your machine; the LLM only sees what you send it

Important: The browser_sessions/ files contain login tokens. They are encrypted, but treat them like passwords. The key lives in SESSION_ENCRYPTION_KEY_FILE (default ~/.linkedin-analyzer/session.key). Both are git-ignored — never commit them.

Troubleshooting

"Not logged in" / authwall redirects

curl -X DELETE http://127.0.0.1:8766/session   # clear session
curl -X POST http://127.0.0.1:8766/login       # log in again in the opened browser

MCP server does not initialize in LM Studio

  • Run ./scripts/install.sh once, restart LM Studio, and check the Program tab.
  • After changing the command, remove the MCP server and re-add it in LM Studio, then fully restart LM Studio (a cached server definition may otherwise keep the old command).
  • Test the MCP handshake directly in a terminal: printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | ./scripts/linkedin-analyzer-mcp-wrapper.sh You should get a JSON result back (no error).
  • If the wrapper fails, it writes progress to boot.log in the project directory and the daemon logs to background_server.log.

First tool call says "Background server unreachable / not ready yet"

  • On a very first run the Playwright browser is still downloading in the background. Wait a few seconds and call the tool again.
  • If it persists: check background_server.log, or run ./scripts/linkedin-analyzer-mcp-wrapper.sh --ensure-only once in the terminal (blocks until everything is ready, prints ok).

Browser does not open

  • Make sure BROWSER_HEADLESS=False in .env (or unset).
  • Reinstall the browser: venv/bin/python -m playwright install chromium
  • On Linux only, you may also need system libraries: venv/bin/python -m playwright install-deps

Server not reachable

  • Is it running? curl http://127.0.0.1:8766/health
  • Port taken? Set another PORT in .env (the wrapper respects PORT too).

LinkedIn shows a captcha / rate limit

  • Wait a few hours.
  • Clear the session and log in again.
  • Do not send requests too frequently.

Project layout

linkedin-analyzer/
├── background_server.py        # Long-running daemon (keeps browser open, HTTP API)
├── session_manager.py          # Encrypted session persistence
├── config.py                   # Environment configuration
├── mcp-server/
│   └── linkedin_mcp.py         # MCP server for LM Studio (stdio)
├── scripts/
│   └── linkedin-analyzer-mcp-wrapper.sh # Auto-start wrapper: bootstraps env + stdio MCP
├── docs/
│   ├── system-prompt.en.md     # English system prompt for LM Studio
│   └── system-prompt.de.md     # German system prompt for LM Studio
├── start-daemon.sh / stop-daemon.sh
├── requirements.txt
├── .env.example
└── browser_sessions/           # Encrypted sessions (git-ignored)

Development

Test the MCP server directly:

venv/bin/python mcp-server/linkedin_mcp.py --stdio

Then send JSON-RPC lines over stdin (initialize, tools/list, tools/call).

License

MIT — see LICENSE.

Credits

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured
E2B

E2B

Using MCP to run code via e2b.

Official
Featured