linkedin-mcp

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.

Category
Visit Server

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:

  1. Fixed shared secret (Postman, curl, ChatGPT's connector) — you generate MCP_BEARER_TOKEN yourself (e.g. openssl rand -hex 32) and put it in .env alongside LINKEDIN_ACCESS_TOKEN (obtained once via auth_setup.py). Clients send Authorization: Bearer <your MCP_BEARER_TOKEN>, and the server calls LinkedIn using the stored LINKEDIN_ACCESS_TOKEN underneath.
  2. 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_TOKEN and 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

  1. Create an app: https://www.linkedin.com/developers/apps
  2. Auth tab → add two redirect URLs:
    • http://localhost:8765/callback (for auth_setup.py, mode 1)
    • https://claude.ai/api/mcp/auth_callback (for Claude's connector, mode 2)
  3. Products tab → request:
    • Sign In with LinkedIn using OpenID Connect (auto-approved)
    • Share on LinkedIn (auto-approved)
  4. 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 .env for auth_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 definitions
  • linkedin_client.py — LinkedIn REST API wrapper (userinfo, posts)
  • resume_builder.py — reportlab-based resume PDF generator
  • auth_setup.py — one-time OAuth2 flow to obtain a LinkedIn access token
  • Dockerfile / Procfile — deployment
  • .env.example — credential template

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
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
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
VeyraX MCP

VeyraX MCP

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

Official
Featured
Local
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
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
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
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