linkedin-mcp
MCP server for LinkedIn that lets Claude and ChatGPT read your profile, post updates, and generate a resume PDF pre-formatted for LinkedIn's Import Resume feature.
README
LinkedIn MCP Server — Remote Edition (Claude + ChatGPT)
An MCP server exposing LinkedIn actions, reachable from both Claude and ChatGPT as a custom connector. Runs over HTTP (not stdio) because ChatGPT only supports remote, HTTPS-reachable MCP servers — it cannot launch a local script the way Claude Desktop can.
What this can and can't do
LinkedIn's public API does not expose any endpoint for a third-party app to write directly to a profile's About, Experience, or Projects sections — for any account type. That's a platform restriction, not something this code can work around without violating LinkedIn's User Agreement (browser automation/credential scraping), which this project does not do.
| Tool | What it does |
|---|---|
get_my_profile |
Reads your name, email, photo via OpenID Connect |
create_post |
Publishes a text or link post to your feed |
generate_resume_pdf |
Builds a PDF from structured About/Experience/Projects data, formatted for LinkedIn's own Import Resume feature |
generate_resume_pdf is the practical route to "updating" Experience/Education:
LinkedIn auto-parses a resume PDF and pre-fills those sections for review. About
and Projects aren't reliably auto-parsed — the PDF still includes them clearly
labeled so you have polished text ready to paste in manually.
Two connection modes, and which credentials each one wants
This server supports two different ways of authenticating, auto-detected per request:
- Fixed shared secret (Postman, curl, ChatGPT's connector) — you generate
MCP_BEARER_TOKENyourself (e.g.openssl rand -hex 32) and put it in.envalongsideLINKEDIN_ACCESS_TOKEN(obtained once viaauth_setup.py). Clients sendAuthorization: Bearer <your MCP_BEARER_TOKEN>, and the server calls LinkedIn using the storedLINKEDIN_ACCESS_TOKENunderneath. - Direct LinkedIn OAuth passthrough (Claude's connector) — Claude logs
into LinkedIn itself using your LinkedIn app's Client ID/Secret (not
anything you generate) and sends LinkedIn's own resulting access token
as the Bearer header. The server detects this token doesn't match your
MCP_BEARER_TOKENand uses it directly as the LinkedIn access token instead.
Don't mix these up: MCP_BEARER_TOKEN is something you invent for mode 1;
your LinkedIn app's Client ID/Secret (from LinkedIn's own Auth tab) are what
mode 2 needs, and they're never typed into .env at all — Claude holds them.
1. LinkedIn app setup
- Create an app: https://www.linkedin.com/developers/apps
- Auth tab → add two redirect URLs:
http://localhost:8765/callback(forauth_setup.py, mode 1)https://claude.ai/api/mcp/auth_callback(for Claude's connector, mode 2)
- Products tab → request:
- Sign In with LinkedIn using OpenID Connect (auto-approved)
- Share on LinkedIn (auto-approved)
- Copy the Client ID / Secret from the Auth tab — you'll use these directly
in Claude's connector settings for mode 2, and/or in your own
.envforauth_setup.py(mode 1).
2. Local setup & one-time LinkedIn auth
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
# fill in LINKEDIN_CLIENT_ID, LINKEDIN_CLIENT_SECRET, and set a random MCP_BEARER_TOKEN
python auth_setup.py # opens browser, completes LinkedIn OAuth, saves LINKEDIN_ACCESS_TOKEN to .env
3. Deploy it somewhere public
Both Claude and ChatGPT need to reach this server over HTTPS — localhost won't
work for either unless you tunnel it. Pick one:
Quick test (ngrok tunnel, temporary URL):
python server.py # starts on http://0.0.0.0:8000
ngrok http 8000 # gives you a temporary https:// URL
Permanent (Docker, deploy to Render/Fly.io/Railway/any host that runs containers):
docker build -t linkedin-mcp .
docker run -p 8000:8000 --env-file .env linkedin-mcp
Point that platform's generated HTTPS domain at container port 8000, path /mcp.
A Procfile is also included for platforms that build directly from source
(Railway, Heroku-style) without a Dockerfile.
Your MCP endpoint URL will be: https://<your-domain>/mcp
4. Connect it to Claude
Claude.ai → Settings → Connectors → Add custom connector. The dialog only has three fields that matter here — no separate Authorization URL / Token URL inputs, despite what you might expect from a typical OAuth setup:
- Name: whatever you want it labeled as (e.g.
linkedIn-mcp) - Remote MCP server URL:
https://<your-domain>/mcp - Advanced settings → OAuth Client ID / OAuth Client Secret: your
LinkedIn app's Client ID and Client Secret (from LinkedIn's Auth tab) —
not anything you generate yourself, and not your server's
MCP_BEARER_TOKEN
Click Add, then Connect. This sends you to LinkedIn's real login/consent screen — log in and approve. LinkedIn redirects back to Claude with a genuine access token, which Claude then sends as the Bearer header on every tool call.
Before this works, add a second authorized redirect URL in your LinkedIn app's
Auth tab (alongside http://localhost:8765/callback, which auth_setup.py
still uses separately):
https://claude.ai/api/mcp/auth_callback
The server handles the rest automatically: since the token Claude sends won't
match your own MCP_BEARER_TOKEN, it's treated as a real LinkedIn access token
and used directly against LinkedIn's API — no code changes needed per person
who connects. This also means multiple people could each connect with their
own LinkedIn account against the same deployed server.
If Connect fails at the LinkedIn-login step itself (not after — see below), double check the redirect URL above was saved exactly, and that both "Sign In with LinkedIn using OpenID Connect" and "Share on LinkedIn" show as fully added under your LinkedIn app's Products tab.
If it reaches LinkedIn's login/consent screen fine, but fails silently right
after you approve: that's LinkedIn's token endpoint requiring the client
secret in the POST body rather than an Authorization: Basic header, which
some OAuth clients don't handle by default. If that happens and persists,
fall back to the Claude Desktop + mcp-remote approach below — it sidesteps
this entirely.
Connecting via Claude Desktop + mcp-remote (guaranteed fallback)
If the direct-OAuth route above doesn't work, or you're not on claude.ai web:
~/Library/Application Support/Claude/claude_desktop_config.json (macOS):
{
"mcpServers": {
"linkedin": {
"command": "npx",
"args": [
"-y", "mcp-remote",
"https://<your-domain>/mcp",
"--header", "Authorization: Bearer YOUR_MCP_BEARER_TOKEN"
]
}
}
}
This runs locally as a subprocess and attaches your fixed bearer token directly — no OAuth negotiation involved. Restart Claude Desktop after saving.
Connecting it to ChatGPT
ChatGPT → Settings → Apps & Connectors → Advanced settings → enable Developer mode (requires Plus/Pro/Business/Enterprise) → Add custom connector:
- URL:
https://<your-domain>/mcp - Authentication: choose token/API key auth → paste your
MCP_BEARER_TOKEN - In a new chat, open the
+menu → Developer mode → toggle this connector on for that conversation (ChatGPT enables connectors per-conversation).
Using generate_resume_pdf
generate_resume_pdf(
output_path="/tmp/resume.pdf",
full_name="Vaibhav Sharma",
headline="Frontend / Full-Stack Developer",
email="you@example.com",
phone="+91-XXXXXXXXXX",
location="Bengaluru, India",
about="Frontend/full-stack developer specializing in AI-powered conversational...",
experience=[{
"title": "Frontend Developer",
"company": "Kapture CRM",
"location": "Bengaluru, India",
"start_date": "Jan 2024",
"end_date": "Present",
"bullets": [
"Built and shipped the Vitos AI voice/chat agent builder UI end-to-end",
"Normalized Redux state using createEntityAdapter across the Vitos state tree",
],
}],
projects=[{
"name": "Shifra",
"description": "Voice-controlled AI assistant built with xAI's Grok API.",
"tech": ["React", "TypeScript", "Grok API", "Vercel"],
}],
skills=["React", "TypeScript", "Redux", "Node.js"],
)
Then: LinkedIn → Me → View Profile → Enhance profile → Import resume, review
the auto-filled Experience/Education, and paste the About/Projects text manually.
Since the file lands wherever the server runs, ask Claude/ChatGPT to send you the
generated PDF or point output_path somewhere you can retrieve it (e.g. a synced
folder), depending on how you've deployed the server.
Files
server.py— remote MCP server (streamable-http + bearer auth) + tool definitionslinkedin_client.py— LinkedIn REST API wrapper (userinfo, posts)resume_builder.py— reportlab-based resume PDF generatorauth_setup.py— one-time OAuth2 flow to obtain a LinkedIn access tokenDockerfile/Procfile— deployment.env.example— credential template
Recommended Servers
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.
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.
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.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
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.
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.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
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.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.