linkedin-mcp
# linkedin-mcp
An MCP (Model Context Protocol) server that lets an AI agent post, comment, and read analytics on LinkedIn — for your personal profile, and optionally a company page you administer.
Point Claude (or any MCP-compatible agent) at this server and it can:
- **post_to_profile** — publish a post to your personal LinkedIn profile
- **post_to_company_page** — publish a post to a company page you administer
- **comment_on_post** — comment on a post as your profile or a company page
- **get_recent_posts** — list recent posts with their URNs, so the agent can find something to comment on or check analytics for
- **get_post_analytics** — impressions, reactions, comments, shares, and clicks for a post
Nothing here talks to LinkedIn except LinkedIn's own official REST API. Your access token stays local, in a `.env` file you control.
---
## 1. Create a LinkedIn Developer App
1. Go to [linkedin.com/developers/apps](https://www.linkedin.com/developers/apps) and create a new app.
2. Under **Products**, add:
- **Sign In with LinkedIn using OpenID Connect** — lets you look up your own person URN
- **Share on LinkedIn** — gives you `w_member_social`, the scope that lets you post and comment as yourself
3. If you also want company page posting and analytics, add the product that grants `w_organization_social` / `r_organization_social` on your app (LinkedIn calls this the Community Management API in newer developer accounts, Marketing Developer Platform in older ones). This product is gated — you apply for access from the app's Products tab, and LinkedIn reviews the request. Skip this if you only want personal posting; `post_to_profile`, `comment_on_post`, and `get_recent_posts`/`get_post_analytics` for your profile all work without it.
## 2. Run the OAuth 2.0 flow to get an access token
LinkedIn uses the standard OAuth 2.0 authorization code flow.
**Authorize** (open in a browser, replace `CLIENT_ID` and `REDIRECT_URI` with your app's values):
```text
https://www.linkedin.com/oauth/v2/authorization
?response_type=code
&client_id=CLIENT_ID
&redirect_uri=REDIRECT_URI
&scope=openid%20profile%20w_member_social
```
Add `%20r_organization_social%20w_organization_social` to the scope if you added company page access in step 1.
LinkedIn redirects you to `REDIRECT_URI?code=AUTH_CODE`. Grab `AUTH_CODE` from that URL.
**Exchange the code for an access token:**
```bash
curl -X POST https://www.linkedin.com/oauth/v2/accessToken \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=AUTH_CODE" \
-d "redirect_uri=REDIRECT_URI" \
-d "client_id=CLIENT_ID" \
-d "client_secret=CLIENT_SECRET"
```
The response includes `access_token`. It's valid for 60 days — after that, repeat this flow to refresh it.
## 3. Get your person URN
```bash
curl https://api.linkedin.com/v2/userinfo \
-H "Authorization: Bearer ACCESS_TOKEN"
```
The `sub` field in the response is your person ID. Your person URN is `urn:li:person:SUB_VALUE`.
## 4. (Optional) Get your organization URN
Only needed for company page features:
```bash
curl "https://api.linkedin.com/v2/organizationalEntityAcls?q=roleAssignee" \
-H "Authorization: Bearer ACCESS_TOKEN"
```
Find your organization's ID in the response; the URN is `urn:li:organization:ORG_ID`.
## 5. Install
**Option A — npm package:**
```bash
npm install -g @sindhujaks/linkedin-mcp
```
**Option B — clone and build:**
```bash
git clone https://github.com/sindhujaIBM/linkedin-mcp.git
cd linkedin-mcp
npm install
npm run build
```
## 6. Configure your credentials
If you installed via npm, create a `.env` file in the directory you'll run the server from (see `.env.example` in this repo for the template). If you cloned the repo:
```bash
cp .env.example .env
```
Fill in `LINKEDIN_ACCESS_TOKEN` and `LINKEDIN_PERSON_URN` from steps 2–3. Add `LINKEDIN_ORGANIZATION_URN` if you did step 4.
## 7. Add it to Claude
**Claude Code** (npm install):
```bash
claude mcp add linkedin -- linkedin-mcp
```
**Claude Code** (cloned repo):
```bash
claude mcp add linkedin -- node /absolute/path/to/linkedin-mcp/dist/index.js
```
**Claude Desktop** — add this to your `claude_desktop_config.json`:
```json
{
"mcpServers": {
"linkedin": {
"command": "linkedin-mcp"
}
}
}
```
(Or `"command": "node", "args": ["/absolute/path/to/linkedin-mcp/dist/index.js"]` if you cloned the repo instead of installing via npm.)
Restart Claude, and the five tools above will be available. You can then just ask, in plain language: "post this to my LinkedIn profile," or "comment 'thanks for reading' on my most recent post," or "how did my last post do?"
---
## Notes
- Access tokens expire after 60 days. When yours does, tool calls will fail with an auth error — re-run the OAuth flow in step 2 and update `.env`.
- `post_to_company_page`, and using `as: "company"` on the other tools, all require `LINKEDIN_ORGANIZATION_URN` to be set — otherwise they return a clear error telling you what's missing.
- This uses LinkedIn's `/v2/ugcPosts` and related endpoints. LinkedIn occasionally changes API versioning requirements for newer developer apps; if a call fails with a version-related error, check LinkedIn's [API versioning docs](https://learn.microsoft.com/en-us/linkedin/marketing/versioning) for the current required header.
## License
MIT
TDQS
Scored across 5 tools
Each tool targets a clearly different action and resource: posting to a profile, posting to a company page, commenting, listing recent posts, and fetching analytics. There is no meaningful overlap or ambiguity between the tools.
All tool names follow the same snake_case verb-first convention, with clear patterns like post_to_* and get_*. The naming is predictable and makes the purpose of each tool immediately obvious.
Five tools is well-scoped for a LinkedIn content publishing and engagement server. Each tool covers a distinct core operation without unnecessary bloat or missing essentials.
The set covers the main lifecycle for LinkedIn posting: create posts, comment, retrieve recent posts, and view analytics. Delete and update operations are absent, but they are not core to the apparent purpose of publishing and measuring engagement.