linkedin-mcp
LinkedIn MCP Server
MCP server for LinkedIn post management and analytics. Deploy on Vercel, connect to Claude or any MCP-compatible LLM.
Architecture
Claude / LLM
│
│ POST /mcp (JSON-RPC)
▼
LinkedIn MCP Server (Vercel)
│
│ OAuth 2.0 + Bearer token
▼
LinkedIn API v2Step-by-Step Setup
STEP 1 — Create LinkedIn App
Click Create App
Fill in: App Name, LinkedIn Page (your company), App Logo
Click Create App
Go to Auth tab → note your Client ID and Client Secret
Under OAuth 2.0 settings → Authorized redirect URLs, add:
Local dev:
http://localhost:3000/auth/callbackProduction:
https://your-app.vercel.app/auth/callback
Go to Products tab → request access to:
Sign In with LinkedIn using OpenID Connect (instant approval)
Share on LinkedIn → gives you
w_member_socialscope (instant)Marketing Developer Platform → only if you need impression analytics (requires manual review)
STEP 2 — Clone and Install
git clone <your-repo>
cd linkedin-mcp-server
npm installSTEP 3 — Configure Environment
cp .env.example .envEdit .env:
LINKEDIN_CLIENT_ID=86xxxxxxxxxx
LINKEDIN_CLIENT_SECRET=WPxxxxxxxxxx
LINKEDIN_REDIRECT_URI=http://localhost:3000/auth/callback
PORT=3000STEP 4 — Build and Run Locally
npm run build
npm startServer starts at http://localhost:3000
Endpoints:
GET /health— health checkGET /auth/linkedin?user_id=YOUR_ID— start OAuth flowGET /auth/callback— LinkedIn redirects here automaticallyPOST /mcp— MCP endpoint for LLM tool calls
STEP 5 — Authenticate a LinkedIn Account
Open in browser:
http://localhost:3000/auth/linkedin?user_id=herbertThis redirects you to LinkedIn → you log in → LinkedIn redirects to your callback → token is stored.
Response you'll see:
{
"success": true,
"message": "LinkedIn authenticated for user herbert",
"person_id": "abc123xyz",
"expires_in_days": 60
}Save the person_id — you'll need it when calling post tools.
STEP 6 — Deploy to Vercel
npm install -g vercel
vercel login
# Set secrets
vercel env add LINKEDIN_CLIENT_ID
vercel env add LINKEDIN_CLIENT_SECRET
vercel env add LINKEDIN_REDIRECT_URI # set to https://your-app.vercel.app/auth/callback
# Deploy
npm run build
vercel --prodAfter deploy, update your LinkedIn app's redirect URI to the production URL.
STEP 7 — Connect to Claude
In Claude.ai → Settings → Connectors → Add MCP Server:
URL: https://your-app.vercel.app/mcpThat's your MCP URL.
Available MCP Tools
Tool | What it does |
| Check if a user is authenticated |
| Get profile info + LinkedIn person ID |
| Publish a post to LinkedIn |
| Fetch your recent posts |
| Get likes/comments on a post |
| Delete a post you own |
Example Claude Usage
Once connected, you can say:
"Check if user herbert is authenticated on LinkedIn"
"Post to LinkedIn as herbert: 'Excited to share our latest Oracle HCM implementation update...'"
"Get the last 5 LinkedIn posts for herbert and show me engagement"
Production: Replace In-Memory Token Store with Supabase
The current code stores tokens in memory (lost on restart). For production:
// src/services/linkedin.ts — replace storeToken/getToken with:
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_SERVICE_KEY!
);
export async function storeToken(userId: string, token: LinkedInToken) {
await supabase.from('linkedin_tokens').upsert({
user_id: userId,
access_token: token.access_token,
refresh_token: token.refresh_token,
expires_at: new Date(token.expires_at).toISOString(),
person_id: token.person_id,
});
}
export async function getToken(userId: string): Promise<LinkedInToken | undefined> {
const { data } = await supabase
.from('linkedin_tokens')
.select('*')
.eq('user_id', userId)
.single();
if (!data) return undefined;
return {
access_token: data.access_token,
refresh_token: data.refresh_token,
expires_at: new Date(data.expires_at).getTime(),
person_id: data.person_id,
};
}Supabase table:
create table linkedin_tokens (
user_id text primary key,
access_token text not null,
refresh_token text,
expires_at timestamptz not null,
person_id text,
created_at timestamptz default now(),
updated_at timestamptz default now()
);LinkedIn API Scope Reference
Scope | What it unlocks | Approval |
| Name, ID, photo | Instant |
| Email address | Instant |
| Post as yourself | Instant |
| Read company page posts | Manual review |
| Post as company page | Manual review |
| Impression/click analytics | Marketing partner only |
Token Expiry
Access tokens expire in 60 days
Refresh tokens expire in 365 days (if
offline_accessgranted)The server auto-refreshes tokens before they expire
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/ashishtechsavvy/linkedin-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server