LinkedIn Poster MCP

LinkedIn Poster MCP

MCP server that lets you publish text and image posts to LinkedIn, fetch your profile, and check auth status using natural language.

Category
Visit Server

README

<div align="center">

<img src="assets/banner.jpg" width="100%" alt="LinkedIn Poster MCP banner">

LinkedIn Poster MCP — Publish to LinkedIn via natural language.

Post to LinkedIn without leaving the chat.

</div>

<p align="center"> <img src="https://img.shields.io/badge/status-MCP%20Server-0A66C2" alt="MCP server"> <img src="https://img.shields.io/badge/Node.js-24%2B-339933?logo=node.js&logoColor=white" alt="Node 24+"> <img src="https://img.shields.io/badge/transport-Streamable%20HTTP%20%2B%20stdio-4DC8FF" alt="transport"> <img src="https://img.shields.io/badge/storage-Upstash%20Redis-DC382D" alt="Upstash Redis"> <img src="https://img.shields.io/badge/auth-LinkedIn%20OAuth2-0A66C2" alt="LinkedIn OAuth2"> <img src="https://img.shields.io/github/license/codebytemirza/linkedin-post-mcp" alt="License"> </p>


A Model Context Protocol server that turns any MCP client into a LinkedIn publisher — text posts, image posts with alt text, profile lookups, and token-health checks, all driven by natural language instead of the LinkedIn API console.

› Post the launch photo to LinkedIn, caption it about our v2 release.
// MCP tool call resolved automatically
{
  "tool": "create_image_post",
  "caption": "Shipping v2 today",
  "images": ["launch.png"]
}
// polling upload status… AVAILABLE
ok post created — urn:li:share:7183…

Highlights

Never a blank image Two transports Admin dashboard Bearer-guarded endpoint
Polls LinkedIn's Images API until status is AVAILABLE before the post is created. Streamable HTTP on Vercel for production, plus a bundled stdio entry for local clients. Optional panel surfacing auth status and tool call logs at a glance. Every call to /api/mcp requires a bearer token before protocol handling begins.

MCP tools

Four tools, one bearer token. Every tool call authenticates through the same Redis-backed token — no per-call re-auth.

Tool Input Returns
create_post text, visibility? created post ID
create_image_post caption, images[1..20], visibility? created post ID
get_profile name + email
check_auth_status token validity + expiry

Architecture

Stateless endpoint, stateful token.

api/
  authorize.ts     GET   start LinkedIn OAuth (CSRF state in Redis)
  callback.ts      GET   exchange code for tokens, store, success page
  mcp.ts           POST  MCP endpoint, bearer-auth, tools
  dashboard.ts     GET   admin dashboard API
frontend/                React + Tailwind + MUI dashboard source -> public/
lib/
  config.ts               env vars, URLs, Redis client
  linkedin-auth.ts        token exchange, refresh, access-token helper
  linkedin-api.ts         profile, create_post, create_image_post
  logging.ts              structured logs to Redis
  errors.ts               NotAuthorizedError, LinkedInError
mcp-stdio.mjs       esbuild-bundled stdio entry

Facts worth remembering:

  • Tokens live under a single Redis key, linkedin:tokens.
  • /api/mcp is stateless and requires Authorization: Bearer <MCP_AUTH_TOKEN> on every request.
  • All LinkedIn calls use raw fetch() — no LinkedIn SDK dependency.

OAuth flow

One authorization, sixty days of posting.

Client -> /api/authorize -> LinkedIn OAuth -> /callback -> Redis -> MCP tools
Step What happens
01 /api/authorize creates a CSRF state, stores it in Redis for 10 minutes, redirects to LinkedIn.
02 LinkedIn authenticates the user and redirects back to /api/callback?code=...&state=....
03 /api/callback validates state, exchanges the code, saves tokens to Redis.
04 Tools call getValidAccessToken() — refreshing near expiry, or throwing NotAuthorizedError.

Note: LinkedIn issues a refresh_token only for apps provisioned with programmatic refresh. On the standard scope set, access tokens last 60 days and the user re-authorizes on expiry — check_auth_status always reports the real state.

Image upload

Why posts never render blank.

  1. Register — the server registers the upload and receives a signed uploadUrl.
  2. Upload — image bytes are uploaded directly to that signed URL.
  3. Poll -> post — status is polled until AVAILABLE, then — and only then — the post is created.

Setup

Prerequisites

  • Node.js 24+
  • LinkedIn Developer app with approved scopes: openid profile email w_member_social
  • An Upstash Redis database

Environment variables

Set these in Vercel and in a root .env for local development:

Variable Purpose
LINKEDIN_CLIENT_ID LinkedIn app client ID
LINKEDIN_CLIENT_SECRET LinkedIn app client secret
LINKEDIN_REDIRECT_URI Must match a whitelisted redirect URL exactly
UPSTASH_REDIS_REST_URL Upstash Redis REST URL
UPSTASH_REDIS_REST_TOKEN Upstash Redis REST token
MCP_AUTH_TOKEN Bearer token MCP clients send to /api/mcp

These files are git-ignored — never commit secrets.

Local development

npm install
vercel dev          # http://localhost:3000/api/...
npm run typecheck   # tsc --noEmit

Redirect URIs

local    http://localhost:3000/api/callback
prod     https://<your-app>.vercel.app/api/callback

Whitelist the exact URL in the LinkedIn Developer Portal — LinkedIn matches redirects with no tolerance for query params.

Client setup

Remote or local — pick one.

<details> <summary><b>Remote — Streamable HTTP</b></summary>

  • Type: Custom / MCP server, Streamable HTTP
  • Endpoint: https://<your-deployed-url>/api/mcp
  • Header: Authorization: Bearer <MCP_AUTH_TOKEN> </details>

<details> <summary><b>Local — stdio</b></summary>

Point the client at the bundled entry:

node /path/to/linkedin-post-mcp/mcp-stdio.mjs

</details>

Deploy

Ship it to Vercel.

vercel           # preview
vercel --prod    # production
  • vercel.json pins api/** to the Node.js runtime.
  • Set the production callback URL for LinkedIn.
  • After deploying, open /api/authorize once — then every tool works.

Security

What's actually guarded.

  • Secrets come from environment variables only — nothing is logged.
  • Endpoint — the MCP endpoint requires a bearer token before protocol handling.
  • CSRF — OAuth state guards against request forgery and is one-time-use with a short TTL.

<p align="center"> <sub>Node.js 24+ · Streamable HTTP + stdio · Upstash Redis · LinkedIn OAuth2</sub> </p>

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