Skip to main content
Glama
joaovaleri

linkedin-mcp

by joaovaleri
README.md
# linkedin-mcp

> A [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server that gives Claude full control over your LinkedIn profile — read, edit, add, remove entries, and publish posts, all from a single conversation.

Built with [Playwright](https://playwright.dev) for browser automation and the official [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk).

---

## Table of Contents

- [Features](#features)
- [Tools](#tools)
- [Prerequisites](#prerequisites)
- [Installation](#installation)
- [Connect to Claude Code](#connect-to-claude-code)
- [Usage](#usage)
- [Session Management](#session-management)
- [Project Structure](#project-structure)
- [Development](#development)
- [Troubleshooting](#troubleshooting)
- [Disclaimer](#disclaimer)
- [License](#license)

---

## Features

- **No LinkedIn API access required** — works through real browser automation, so you don't need an approved LinkedIn developer app.
- **Persistent session** — log in once, reuse the session for weeks.
- **Full profile coverage** — read and edit every section: experience, education, skills, certifications, languages, projects, honors, volunteer, publications, courses, organizations, test scores, and patents.
- **Remove entries** — delete any entry from any section by matching text.
- **Publish posts** — text posts and image posts both supported.
- **Portable** — profile slug is configured via environment variable; no hardcoded paths.

---

## Tools

### Read

| Tool | Description |
|------|-------------|
| `linkedin_get_profile` | Fetch name, headline, location, company, about, industry |
| `linkedin_get_contact_info` | Read phone, email, website, twitter |
| `linkedin_get_sections` | Read all profile sections with optional text filter |
| `linkedin_get_recent_posts` | Fetch recent posts from the activity page |

### Edit intro / basic info

| Tool | Description | Parameters |
|------|-------------|------------|
| `linkedin_update_headline` | Update profile headline | `headline` |
| `linkedin_update_summary` | Rewrite the About/Summary section | `summary` |
| `linkedin_update_industry` | Update the Industry/Setor field | `industry` |
| `linkedin_update_contact_info` | Update phone and/or address | `phone?`, `address?` |
| `linkedin_set_open_to_work` | Enable or disable Open to Work | `enable` (boolean) |

### Add entries

| Tool | Description |
|------|-------------|
| `linkedin_add_experience` | Add a work experience entry |
| `linkedin_add_education` | Add an education entry |
| `linkedin_add_skill` | Add a skill |
| `linkedin_add_certification` | Add a certification |
| `linkedin_add_language` | Add a language and proficiency level |
| `linkedin_add_project` | Add a project |
| `linkedin_add_volunteer` | Add a volunteer experience |
| `linkedin_add_honor` | Add an honor or award |
| `linkedin_add_publication` | Add a publication |
| `linkedin_add_course` | Add a course |
| `linkedin_add_organization` | Add an organization membership |
| `linkedin_add_test_score` | Add a test score (e.g. TOEFL, GRE) |
| `linkedin_add_patent` | Add a patent |

### Remove

| Tool | Description | Parameters |
|------|-------------|------------|
| `linkedin_remove_entry` | Remove any entry from any section by matching text | `section`, `search` |

Valid sections for `linkedin_remove_entry`: `experience`, `education`, `skills`, `certifications`, `languages`, `projects`, `honors`, `volunteer`, `publications`, `courses`, `organizations`, `test_scores`, `patents`

### Posts

| Tool | Description | Parameters |
|------|-------------|------------|
| `linkedin_create_text_post` | Publish a plain text post | `text` |
| `linkedin_create_image_post` | Publish a post with a local image | `text`, `imagePath` |

### Auth / Diagnostics

| Tool | Description |
|------|-------------|
| `linkedin_login` | Open browser for manual login and save session |
| `linkedin_dump_profile_buttons` | Diagnostic: dump all buttons on the profile page |

---

## Prerequisites

- [Node.js](https://nodejs.org) v18 or later
- [npm](https://www.npmjs.com) v9 or later
- [Claude Code](https://claude.ai/code) (or any other MCP-compatible client)
- A real LinkedIn account you're allowed to automate

---

## Installation

### Automated setup (recommended)

```bash
git clone https://github.com/khalidstark/linkedin-mcp.git
cd linkedin-mcp
chmod +x setup.sh
./setup.sh
```

The script will:
1. Check for Node.js
2. Install npm dependencies
3. Install the Playwright Chromium browser
4. Build the TypeScript source
5. Ask for your LinkedIn profile slug and output the config block to paste into `~/.claude.json`

### Manual setup

```bash
git clone https://github.com/khalidstark/linkedin-mcp.git
cd linkedin-mcp
npm install
npx playwright install chromium
npm run build
```

---

## Connect to Claude Code

Add the following to `~/.claude.json` under `mcpServers` (replace the path and slug):

```json
{
  "mcpServers": {
    "linkedin-editor": {
      "type": "stdio",
      "command": "node",
      "args": ["/absolute/path/to/linkedin-mcp/dist/index.js"],
      "env": {
        "LINKEDIN_PROFILE_SLUG": "your-profile-slug"
      }
    }
  }
}
```

Your profile slug is the last segment of your LinkedIn URL:
`https://www.linkedin.com/in/`**`your-profile-slug`**

Restart Claude Code after editing the config. Verify with:

```bash
claude mcp list
```

### Other MCP clients

For Claude Desktop, Cursor, and other MCP-compatible clients, use the same `node /path/to/linkedin-mcp/dist/index.js` command and pass `LINKEDIN_PROFILE_SLUG` in their environment config.

---

## Usage

### 1. Log in (first time only)

```
"Call linkedin_login"
```

A Chromium window will open. Log in to LinkedIn normally (including 2FA/captcha). Once you land on the feed, the session is persisted in the Chrome profile directory at `~/.linkedin-mcp-chrome-profile/` and reused on future calls.

### 2. Read your full profile

```
"Read all my LinkedIn profile sections"
```

### 3. Update your profile from a CV

```
"Here is my CV: [paste]. Update my LinkedIn headline and summary, add all my skills and certifications."
```

### 4. Remove an entry

```
"Remove the 'Old Company' entry from my experience section"
```

### 5. Publish a post

```
"Write a short post about my new certification and publish it on LinkedIn."
"Post this image to LinkedIn with caption 'Excited to share this!': /home/user/photo.jpg"
```

Image paths must be absolute.

---

## Session Management

The login session is persisted in the Chrome profile directory at `~/.linkedin-mcp-chrome-profile/` (cookies + local storage). It lives in your home directory, outside the repo, so it is never committed. If the session expires, call `linkedin_login` again.

To force a fresh login:

```bash
rm -rf ~/.linkedin-mcp-chrome-profile
```

---

## Project Structure

```
linkedin-mcp/
├── src/
│   ├── index.ts      # MCP server + tool registration
│   ├── linkedin.ts   # LinkedIn automation functions
│   └── browser.ts    # Playwright browser/session lifecycle
├── setup.sh          # Automated setup script for new machines
├── dist/             # Compiled output (generated, not committed)
├── package.json
└── tsconfig.json
```

---

## Development

```bash
npm run build   # Compile TypeScript → dist/
```

Rebuild and restart the MCP client to pick up changes. Claude Code reloads servers on restart, not on file change.

---

## Troubleshooting

**Server failed to connect**
- Check that the path to `dist/index.js` is correct and `npm run build` has been run.
- Verify `LINKEDIN_PROFILE_SLUG` is set in the `env` block of your MCP config.
- Ensure Node.js is accessible from the PATH that Claude Code's subprocess inherits.

**`npx playwright install chromium` fails**
Re-run with: `DEBUG=pw:install npx playwright install chromium`. On Linux you may also need `npx playwright install-deps chromium` for system libraries.

**LinkedIn shows a captcha or security check**
Solve it manually in the Chromium window opened by `linkedin_login`. The session is saved only after you reach the LinkedIn feed.

**Session keeps expiring**
LinkedIn invalidates sessions on password changes or security triggers. Delete `~/.linkedin-mcp-chrome-profile` and call `linkedin_login` again.

**A tool runs but the profile doesn't update**
LinkedIn occasionally ships UI changes that break selectors. Open an issue with the failing tool name and a redacted screenshot.

**"Browser closed unexpectedly"**
Another `linkedin-mcp` instance may be holding the profile lock. Kill stray `chromium` processes and retry.

---

## Disclaimer

This project uses browser automation to interact with LinkedIn. Automating LinkedIn actions may violate their [User Agreement](https://www.linkedin.com/legal/user-agreement). Use it on your own account, at your own discretion. The author is not responsible for any account restrictions or suspensions resulting from this tool.

---

## License

MIT

TDQS

B3.2/5.0

Scored across 41 tools

Disambiguation4/5

Most tools have clearly distinct purposes, but some overlap could cause confusion (e.g., linkedin_get_recent_posts vs linkedin_get_feed, or multiple search tools). However, descriptions are sufficiently detailed to disambiguate in most cases.

Naming Consistency5/5

All tools follow a uniform linkedin_verb_noun convention in snake_case, making it easy to infer function from name. No mixing of styles or inconsistent patterns.

Tool Count3/5

41 tools is on the high side but justified by LinkedIn's broad feature set covering profile management, search, messaging, and posts. However, some tools (e.g., many individual add_* tools) could potentially be combined without sacrificing clarity.

Completeness4/5

Covers most core LinkedIn operations: profile CRUD, search, messaging, posts, and connections. Minor gaps exist such as no tool to delete or update a post, but the overall surface is comprehensive.

Maintenance

ActivityStale
ResponsivenessSyncing