mcp-server-linkedin
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-server-linkedin Publish a LinkedIn post about our new AI feature with an image"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Use Cases
Content Publishing: Draft and publish LinkedIn posts from your AI assistant without switching context.
Media Sharing: Upload images and videos alongside your posts in a single command.
Link Previews: Share articles with auto-generated link preview cards.
Multi-Format Workflow: Compose text-only updates, visual content, or article shares through one unified interface.
Account Management: Authenticate, check your profile, and manage your session without leaving your editor.
Built for developers and content creators who want their AI tools to publish directly to LinkedIn.
Quick Start
Prerequisites
Python 3.10+
LinkedIn App — Follow the step-by-step setup guide or the quick version below:
Create an app at LinkedIn Developer Portal
Products: "Share on LinkedIn" + "Sign In with LinkedIn using OpenID Connect"
OAuth 2.0 scopes:
openid,profile,email,w_member_socialRedirect URL:
http://localhost:3000/callback
Install
uvx mcp-server-linkedinOr with pip:
pip install mcp-server-linkedinRelated MCP server: LinkedIn MCP Server
Configuration
Set these environment variables:
LINKEDIN_CLIENT_ID=your_client_id # From LinkedIn Developer Portal
LINKEDIN_CLIENT_SECRET=your_secret_here # From LinkedIn Developer Portal
LINKEDIN_REDIRECT_URI=http://localhost:3000/callback # Optional, this is the defaultClaude Desktop
Add to your claude_desktop_config.json:
{
"mcpServers": {
"linkedin": {
"command": "uvx",
"args": ["mcp-server-linkedin"],
"env": {
"LINKEDIN_CLIENT_ID": "your_client_id",
"LINKEDIN_CLIENT_SECRET": "your_secret_here"
}
}
}
}{
"mcpServers": {
"linkedin": {
"command": "uvx",
"args": ["mcp-server-linkedin"],
"env": {
"LINKEDIN_CLIENT_ID": "your_client_id",
"LINKEDIN_CLIENT_SECRET": "your_secret_here"
}
}
}
}VS Code + Copilot
Add to .vscode/mcp.json in your workspace:
{
"servers": {
"linkedin": {
"command": "uvx",
"args": ["mcp-server-linkedin"],
"env": {
"LINKEDIN_CLIENT_ID": "your_client_id",
"LINKEDIN_CLIENT_SECRET": "your_secret_here"
}
}
}
}Cursor
Add to .cursor/mcp.json in your project root:
{
"mcpServers": {
"linkedin": {
"command": "uvx",
"args": ["mcp-server-linkedin"],
"env": {
"LINKEDIN_CLIENT_ID": "your_client_id",
"LINKEDIN_CLIENT_SECRET": "your_secret_here"
}
}
}
}Kiro
Add to .kiro/settings/mcp.json:
{
"mcpServers": {
"linkedin": {
"command": "uvx",
"args": ["mcp-server-linkedin"],
"env": {
"LINKEDIN_CLIENT_ID": "your_client_id",
"LINKEDIN_CLIENT_SECRET": "your_secret_here"
}
}
}
}Claude Code
claude mcp add linkedin -- uvx mcp-server-linkedinThen set LINKEDIN_CLIENT_ID and LINKEDIN_CLIENT_SECRET in your environment.
Windsurf
Add to your Windsurf MCP configuration:
{
"mcpServers": {
"linkedin": {
"command": "uvx",
"args": ["mcp-server-linkedin"],
"env": {
"LINKEDIN_CLIENT_ID": "your_client_id",
"LINKEDIN_CLIENT_SECRET": "your_secret_here"
}
}
}
}Running from Source
Replace "command": "uvx", "args": ["mcp-server-linkedin"] with:
{
"command": "uv",
"args": ["--directory", "/path/to/mcp-server-linkedin", "run", "mcp-server-linkedin"]
}Authentication
Start your MCP client (Claude Desktop, Kiro, etc.)
Ask: "Authenticate with LinkedIn"
Browser opens → authorize the app → callback captured automatically
Token saved to
~/.mcp-server-linkedin/token.jsonToken lasts 2 months. Re-run
linkedin_authwhen it expires.
Tools
Tool | Description |
| OAuth 2.0 browser-based authentication |
| Get your name, email, and person URN |
| Remove stored token |
| Publish a text-only post |
| Publish a post with an image |
| Publish a post with a video (up to 200 MB) |
| Publish a post with a link preview |
| Delete a post by ID |
| Get post analytics (requires Community Management API) |
| Get aggregated analytics (requires Community Management API) |
Tool Details
Parameter | Type | Default | Description |
| string | required | Post content (up to ~3000 chars) |
| string |
|
|
Parameter | Type | Default | Description |
| string | required | Post caption |
| string | required | Absolute path to image (JPEG, PNG, GIF) |
| string |
|
|
Parameter | Type | Default | Description |
| string | required | Post caption |
| string | required | Absolute path to video (MP4, max 200 MB) |
| string |
|
|
Parameter | Type | Default | Description |
| string | required | Post commentary |
| string | required | Article URL (generates link preview) |
| string |
| Optional link preview title |
| string |
| Optional link preview description |
| string |
|
|
Parameter | Type | Default | Description |
| string | required | Post URN (e.g., |
Architecture
src/mcp_server_linkedin/
├── config.py # Constants, API URLs, settings dataclass
├── exceptions.py # Typed exception hierarchy
├── server.py # FastMCP entrypoint + tool registration
├── models/ # Frozen dataclass API response models
├── services/ # Async API client with connection pooling
├── tools/ # MCP tool implementations (validate → delegate → format)
│ ├── auth.py # OAuth flow, profile, logout
│ ├── posting.py # Text, image, video, article, delete
│ └── analytics.py # Stubbed (pending API access)
└── utils/ # Token persistenceRate Limits
Limit | Value |
API requests per member per day | 150 |
Token duration | 2 months |
Max video file size | 200 MB |
The server relays LinkedIn's rate limit errors clearly but does not enforce limits internally.
Security
Tokens stored locally at
~/.mcp-server-linkedin/token.jsonNo credentials in code — all secrets via environment variables
Official API only — uses
w_member_socialscopeLocal OAuth callback — authorization code never leaves your machine
No data collection — this server sends nothing except LinkedIn API calls
Development
git clone https://github.com/Huzaifa-ali/mcp-server-linkedin.git
cd mcp-server-linkedin
uv sync --all-extras
pre-commit installuv run mcp-server-linkedin # Run the server
uv run ruff check src/ # Lint
uv run ruff format src/ # Format
uv run mypy src/ # Type check
uv run pytest # TestTest with MCP Inspector:
npx @modelcontextprotocol/inspector uv run mcp-server-linkedinContributing
See CONTRIBUTING.md for guidelines. In short:
Fork the repo and create a feature branch
Make your changes with type hints and docstrings
Run
pre-commit run --all-files(must pass)Open a pull request
License
MIT — see LICENSE.
Available Tools
10 toolslinkedin_authA
Authenticate with LinkedIn using OAuth 2.0. Opens a browser window for the user to log in and authorize. Must be called BEFORE any other LinkedIn tool if the user is not yet authenticated. Only needs to be run once — the token is saved and lasts 2 months.
Inputs: no named parameters. Returns: result
linkedin_delete_postA
Delete an existing LinkedIn post. Use when the user wants to remove a post they previously published. Requires: the post URN/ID (e.g., urn:li:ugcPost:123456 or urn:li:share:123456). This action is irreversible.
Inputs: post_id (required). Returns: result
linkedin_get_all_statsA
Get aggregated analytics across ALL LinkedIn posts (total impressions, clicks, likes, comments, shares). NOTE: Currently requires Community Management API access (r_member_postAnalytics scope) which must be applied for separately. Returns instructions on how to gain access if not available.
Inputs: metric, end_date, start_date, aggregation. Returns: result
linkedin_get_post_statsB
Get analytics (impressions, clicks, likes, comments, shares) for a specific LinkedIn post. NOTE: Currently requires Community Management API access (r_member_postAnalytics scope) which must be applied for separately at developer.linkedin.com. Returns instructions on how to gain access if not available.
Inputs: post_id (required), metric, end_date, start_date, +1 more. Returns: result
linkedin_get_profileA
Get the currently authenticated LinkedIn user's profile: name, email, person URN, and profile picture URL. Use this to confirm who is logged in or to retrieve the user's identity. Requires prior authentication.
Inputs: no named parameters. Returns: result
linkedin_logoutA
Log out of LinkedIn by deleting the stored OAuth token. Use when the user wants to switch accounts or revoke access. After logout, linkedin_auth must be called again before using any other tools.
Inputs: no named parameters. Returns: result
linkedin_post_articleA
Publish a LinkedIn post with a link/article preview card. Use when the user wants to share a URL with an auto-generated preview (title, description, thumbnail). Best for sharing blog posts, news articles, or web pages. Requires: text commentary AND a URL. Optional: custom title, description, visibility (PUBLIC or CONNECTIONS).
Inputs: url (required), text (required), title, visibility, +1 more. Returns: result
linkedin_post_imageA
Publish a LinkedIn post with an attached image. Use when the user wants to share a photo, infographic, screenshot, or any image file alongside text. Requires: text caption AND absolute file path to an image (JPEG, PNG, or GIF). Optional: visibility (PUBLIC or CONNECTIONS).
Inputs: text (required), image_path (required), visibility. Returns: result
linkedin_post_textA
Publish a text-only post to LinkedIn. Use when the user wants to share a written update, thought, or announcement WITHOUT any image, video, or link preview. Requires: text content. Optional: visibility (PUBLIC or CONNECTIONS).
Inputs: text (required), visibility. Returns: result
linkedin_post_videoA
Publish a LinkedIn post with an attached video. Use when the user wants to share a video file (MP4, max 200 MB) alongside text. Requires: text caption AND absolute file path to a video file. Optional: visibility (PUBLIC or CONNECTIONS).
Inputs: text (required), video_path (required), visibility. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 10 tools
Each tool targets a distinct action: authentication, profile retrieval, logout, various post types (text, image, video, article), deletion, and post stats. No overlapping functionality.
All tools follow a consistent 'linkedin_verb_noun' pattern in snake_case (e.g., linkedin_post_text, linkedin_get_profile). Minor exception: linkedin_auth omits a noun but is still clear.
With 10 tools, the set covers authentication, profile, posting (four types), deletion, and two levels of stats. Each tool serves a clear purpose, and no tool seems redundant or out of place.
Covers core posting and basic profile/stats, but notable gaps exist: no ability to list or edit posts, no comment operations, and stats tools require special API access not guaranteed. For a content-focused toolset, updates and retrieval would be expected.
Related MCP Connectors
Schedule and publish LinkedIn posts to profiles and company pages from AI agents.
Publish and schedule LinkedIn posts from your AI assistant.
LinkedIn actions for AI agents: search, messaging, posts and invites, as hosted MCP tools.
LinkedIn for AI agents: inbox, invitations, Sales Navigator search, posts, jobs, quotas, webhooks.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to interact with LinkedIn for posting, commenting, liking, and managing connections via OAuth2 authentication.18 npmMIT
- AlicenseBqualityCmaintenanceEnables AI agents to manage LinkedIn profiles, posts, connections, skills, education, and certifications through the LinkedIn API.18176 npm64MIT
- AlicenseBqualityCmaintenanceEnables AI agents with read/write access to LinkedIn API, including profile, posts, media, organizations, comments, reactions, and analytics.207 npmMIT
- AlicenseAqualityCmaintenanceEnables AI agents to publish posts, images, comments, and reactions to LinkedIn as the authenticated user, with built-in safety features like daily budgets and deduplication.918 npm1Apache 2.0