linkedin-mcp-server
An MCP server that posts PDF/carousel content to a personal LinkedIn profile via LinkedIn's official REST API. It handles OAuth and provides tools to upload documents and publish posts.
README
linkedin-mcp-server
An MCP server that posts document/"carousel" content (e.g. a Gamma PDF export) to a personal LinkedIn profile via LinkedIn's official REST API. Built for the "post Gamma carousels to LinkedIn automatically" workflow, but the tools are generic enough for any PDF-carousel-to-LinkedIn use case.
It also hosts the LinkedIn OAuth flow itself, so you don't need a separate public server just to catch the redirect — this one is that server.
Tools
| Tool | What it does |
|---|---|
linkedin_get_profile |
Read-only. Confirms which account is authenticated. |
linkedin_upload_document |
Uploads a PDF (from a URL) to LinkedIn as a document asset. Doesn't publish anything. |
linkedin_create_post |
Publishes a post referencing an already-uploaded document. Irreversible. |
linkedin_post_carousel |
Does both steps in one call: download PDF → upload → publish. Irreversible. |
Use linkedin_upload_document + linkedin_create_post separately if you want
a review step between uploading and going live; use linkedin_post_carousel
for full one-shot automation.
1. Create the LinkedIn app (one-time, ~5 minutes)
- Go to https://www.linkedin.com/developers/apps → Create app.
- Fill in the required fields. LinkedIn requires the app be associated with a Company Page even for personal-profile posting — if you don't have one, create a minimal one for this purpose.
- On the Products tab, request "Share on LinkedIn". This is
self-serve for the scopes this server needs (
openid,profile,w_member_social) — no manual review wait. - On the Auth tab, note the Client ID and Client Secret, and add
an Authorized redirect URL of:
(must matchhttps://<your-deployed-host>/oauth/linkedin/callbackLINKEDIN_REDIRECT_URIexactly, including scheme/host/path)
2. Deploy the server
Two supported paths — pick based on where you want to host this.
Option A: Vercel (serverless)
Vercel Functions have no persistent disk, so the file-based token store won't survive between requests. Use the built-in Redis-backed store instead:
- Push this repo to GitHub, then import it in Vercel (New Project → your repo). It's picked up automatically —
api/index.tsis the serverless entrypoint,vercel.jsonroutes everything there. - In the Vercel project, go to Storage → Marketplace Database Providers → Upstash → Redis and create one. This injects Redis env vars into your project automatically.
- Add the rest of the environment variables (Project Settings → Environment Variables):
LINKEDIN_CLIENT_ID=... LINKEDIN_CLIENT_SECRET=... LINKEDIN_REDIRECT_URI=https://<your-vercel-domain>/oauth/linkedin/callback TOKEN_STORE_DRIVER=kv MCP_AUTH_TOKEN=<a long random string> - Redeploy so the new env vars take effect.
The 4.5 MB request-body limit on Vercel Functions doesn't affect this server
— the PDF is fetched by an outbound request from linkedin_post_carousel
(you pass a pdf_url, not the file itself), not received as an inbound
upload. The 300s default duration on every plan is comfortably more than an
upload+publish needs.
Option B: A host with a real disk (Fly.io, Railway, a VPS)
npm install
npm run build
npm start # or: node dist/index.js
Set these environment variables (see .env.example):
LINKEDIN_CLIENT_ID=...
LINKEDIN_CLIENT_SECRET=...
LINKEDIN_REDIRECT_URI=https://<your-deployed-host>/oauth/linkedin/callback
TOKEN_STORE_DRIVER=file
TOKEN_STORE_PATH=./data/tokens.json # point this at a persistent volume
MCP_AUTH_TOKEN=<a long random string> # protects /mcp and /oauth/linkedin/start
PORT=3000
TRANSPORT=http
Either way, you need a public HTTPS URL (for the OAuth redirect and for
Claude to reach /mcp).
3. Authorize (one-time human step)
Open, in a browser where you're logged into the LinkedIn account you want to post as:
https://<your-deployed-host>/oauth/linkedin/start?token=<MCP_AUTH_TOKEN>
Click Allow. You'll land back on /oauth/linkedin/callback, which
exchanges the code for an access + refresh token and saves them to
TOKEN_STORE_PATH. The access token is refreshed automatically by the
server on subsequent tool calls (refresh tokens last ~1 year), so this step
shouldn't need repeating often.
4. Register as a connector
This server hosts its own minimal OAuth 2.1 authorization server
(/.well-known/oauth-protected-resource, /.well-known/oauth-authorization-server,
/register, /authorize, /token — RFC9728, RFC8414, RFC7591, RFC8707,
PKCE), so it can be added as a real custom connector wherever a client
only supports "no auth" or full OAuth rather than a static bearer header
(e.g. Claude's Settings → Connectors → Add custom connector UI):
- Add
https://<your-deployed-host>/mcpas a custom connector's URL and choose OAuth. Most clients handle Dynamic Client Registration and PKCE automatically from there — no Client ID/Secret to paste in. - When the client opens the authorization page in a browser, you'll be
asked to enter
MCP_AUTH_TOKEN. That's the entire "login" step — this server is single-user, so proving you know that value is the consent gate. Submit it and you'll be redirected back with the connector connected. - Access tokens this layer issues are short-lived (1 hour) and refreshed automatically by the client using the refresh token from step 2 — no further action needed under normal use.
If your client only supports a static bearer token (e.g. MCP Inspector, or
curl), you can skip all of the above and just send
Authorization: Bearer <MCP_AUTH_TOKEN> directly — the old path still
works unchanged and is treated as a master key by the same /mcp route.
Local development
npm run dev # tsx watch, auto-reloads on save
For local testing you can run with TRANSPORT=stdio and connect via any
stdio-based MCP client (e.g. npx @modelcontextprotocol/inspector), though
you'll still need LINKEDIN_REDIRECT_URI reachable from your browser to
complete the OAuth step — a tunnel like ngrok works well for this during
development.
Notes / limitations
- Single-user by design (one LinkedIn account, one token file). Don't expose
this server publicly without
MCP_AUTH_TOKENset — it protects/mcp,/oauth/linkedin/start, and doubles as the consent gate on the connector OAuth server's/authorizepage. - The connector-facing OAuth layer (
/register,/authorize,/token) is intentionally separate from the LinkedIn-facing OAuth flow (/oauth/linkedin/start//callback) — the former lets clients (like Claude) authenticate to this server; the latter lets this server authenticate to LinkedIn. Don't confuse the twocode/tokenexchanges if you're debugging. - Registered OAuth clients, authorization codes, and issued access/refresh
tokens are stored the same way as the LinkedIn token (file or Redis, via
TOKEN_STORE_DRIVER) — seesrc/services/kv-store.ts/src/services/oauth-store.ts. Access tokens expire in 1 hour; refresh tokens don't expire but aren't rotated, matching this server's single-operator threat model. If you ever need to revoke everything, clear thedata/oauth-*files (file driver) or flush those key prefixes in Redis (kv driver). - Set
PUBLIC_BASE_URL(e.g.https://your-app.vercel.app) if you're behind a proxy that doesn't setX-Forwarded-Proto/Hostcorrectly — the OAuth metadata endpoints otherwise infer the base URL from the incoming request. - LinkedIn posts published via
linkedin_create_post/linkedin_post_carouselcannot be edited or deleted through this API — only from the LinkedIn UI. There's no "undo" tool here on purpose; double-check the caption and PDF before calling. - LinkedIn's native ads-only "Carousel" format has no organic API equivalent; what these tools produce is a document post, which LinkedIn renders as a swipeable carousel in the feed — visually the same thing users mean by "LinkedIn carousel."
LINKEDIN_API_VERSIONinsrc/constants.tsis a calendar-month version string LinkedIn requires on every REST call. Bump it periodically per LinkedIn's versioning docs.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。