mcp-linkedin
Publish LinkedIn posts, comments, and reactions via Unipile — dry_run by default for safety.
mcp-linkedin
An MCP server that lets AI assistants publish to LinkedIn on your behalf.
What it does
This is a Model Context Protocol (MCP) server that wraps the Unipile API to give AI assistants (Claude Code, Claude Desktop, or any MCP-compatible client) the ability to create posts, comments, and reactions on LinkedIn. The AI writes the content; this tool handles the publishing. All publishing actions default to preview mode — nothing goes live without explicit confirmation.
Features
- 3 tools: publish, comment, react
- Dry run by default (preview before publishing)
- Auto-likes posts immediately after publishing
- Media attachments (local files or URLs — images and video)
- Company @mentions (auto-resolved via Unipile)
- Works with Claude Code, Claude Desktop, and any MCP client
Prerequisites
- Node.js 18+ — uses ES modules,
node:test, and top-level await - Unipile account — Unipile is the service that connects to LinkedIn's API. Sign up, connect your LinkedIn account, and get your API key and DSN from the dashboard.
Installation
git clone https://github.com/timkulbaev/mcp-linkedin.git
cd mcp-linkedin
npm install
Configuration
Claude Code
Add to ~/.claude/mcp.json:
{
"mcpServers": {
"linkedin": {
"command": "node",
"args": ["/absolute/path/to/mcp-linkedin/index.js"],
"env": {
"UNIPILE_API_KEY": "your-unipile-api-key",
"UNIPILE_DSN": "apiXX.unipile.com:XXXXX"
}
}
}
}
Claude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS):
{
"mcpServers": {
"linkedin": {
"command": "node",
"args": ["/absolute/path/to/mcp-linkedin/index.js"],
"env": {
"UNIPILE_API_KEY": "your-unipile-api-key",
"UNIPILE_DSN": "apiXX.unipile.com:XXXXX"
}
}
}
}
Restart Claude Code or Claude Desktop after editing the config.
Environment variables
| Variable | Required | Description |
|---|---|---|
UNIPILE_API_KEY | Yes | Your Unipile API key (from the Unipile dashboard) |
UNIPILE_DSN | Yes | Your Unipile DSN (e.g. api16.unipile.com:14648) |
These are passed via the MCP config, not a .env file. The server reads them from process.env at startup.
Tools
linkedin_publish
Creates an original LinkedIn post.
dry_run defaults to true. Call with dry_run: true first to get a preview, then call again with dry_run: false to actually publish.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
text | string | yes | — | Post body, max 3000 characters |
media | string[] | no | [] | Local file paths or URLs (jpg, png, gif, webp, mp4) |
mentions | string[] | no | [] | Company names to @mention (auto-resolved) |
dry_run | boolean | no | true | Preview without publishing |
Preview response (dry_run: true):
{
"status": "preview",
"post_text": "Hello LinkedIn!",
"character_count": 16,
"character_limit": 3000,
"media": [],
"mentions": [],
"warnings": [],
"ready_to_publish": true
}
Publish response (dry_run: false):
{
"status": "published",
"post_id": "7437514186450104320",
"post_text": "Hello LinkedIn!",
"posted_at": "2026-03-11T15:06:04.849Z",
"auto_like": "liked"
}
After publish, save the post_id and construct the post URL:
https://www.linkedin.com/feed/update/urn:li:activity:{post_id}/
linkedin_comment
Posts a comment on an existing LinkedIn post.
dry_run defaults to true.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
post_url | string | yes | — | LinkedIn post URL or raw URN (urn:li:activity:... or urn:li:ugcPost:...) |
text | string | yes | — | Comment text |
dry_run | boolean | no | true | Preview without posting |
linkedin_react
Reacts to a LinkedIn post. This action is immediate — there is no dry_run.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
post_url | string | yes | — | LinkedIn post URL or raw URN |
reaction_type | string | no | "like" | One of: like, celebrate, support, love, insightful, funny |
How it works
┌──────────────────────────────────┐
│ mcp-linkedin │
AI Assistant ──► │ │
(via MCP stdio) │ Posts/Comments/Reactions ──► Unipile API ──► LinkedIn
└──────────────────────────────────┘
- The AI assistant calls tools via MCP's JSON-RPC protocol over stdio
- Calls Unipile API which handles LinkedIn OAuth — no token management needed
Safe publishing workflow
The dry_run default exists to prevent accidental publishing. The intended flow:
- AI calls the tool with
dry_run: true(the default) - You see the preview: final text, character count, media validation, resolved mentions, warnings
- You confirm or ask for changes
- AI calls again with
dry_run: false - Post goes live
dry_run is true by default. The AI cannot publish without explicitly setting it to false, which requires going through the preview step first.
Media handling
- Pass local file paths (
/path/to/image.jpg) or URLs (https://example.com/img.png) - URLs are downloaded to
/tmp/mcp-linkedin-media/and cleaned up after publish (whether it succeeds or fails) - Supported formats: jpg, jpeg, png, gif, webp (images), mp4 (video)
- Each file is validated before upload: must exist, be non-empty, and be a supported type
- Failed files appear in the preview's
mediaarray with"valid": falseand an error message
Company @mentions
- Pass company names as strings:
mentions: ["Microsoft", "OpenAI"] - The server slugifies each name and looks it up via Unipile's LinkedIn company search
- Resolved companies are injected as
{{0}},{{1}}placeholders in the post text — LinkedIn renders these as clickable @mentions - If a company name appears in the post text, it gets replaced in place; if not, the placeholder is appended
- Unresolved names appear as warnings in the preview. The post can still be published without them.
Testing
npm test # 28 unit tests, zero extra dependencies (Node.js built-in test runner)
npm run lint # Biome linter
Project structure
mcp-linkedin/
index.js Entry point (stdio transport)
package.json
src/
server.js MCP server and tool registration
unipile-client.js Unipile API wrapper (posts, comments, reactions)
media-handler.js URL download and file validation
tools/
publish.js linkedin_publish handler
comment.js linkedin_comment handler
react.js linkedin_react handler
tests/
unit.test.js 28 unit tests
Getting a Unipile account
- Sign up for a Unipile account
- In the dashboard, connect your LinkedIn account
- Copy your API key and DSN from the dashboard settings
- Paste them into the MCP config (see Configuration above)
Unipile has a free tier that covers basic usage.
License
MIT — see LICENSE.
Credits
Built by Timur Kulbaev. Uses the Model Context Protocol by Anthropic and the Unipile API.
Servidores relacionados
Reddit MCP Server
A server for fetching and creating content on Reddit using its API.
DingTalk
A server for interacting with DingTalk workspaces using the Model Context Protocol.
Pearl
Official MCP Server to interact with Pearl API. Connect your AI Agents with 12,000+ certified experts instantly.
Reddit
Access Reddit's public API to browse frontpage posts, subreddit information, and read post comments.
Telnet MCP Server
A secure telnet client for LLM applications, designed for defensive security analysis of network devices.
VRChat MCP OSC
A bridge between AI assistants and VRChat using MCP and OSC, enabling AI-driven avatar control and interactions in virtual reality.
MCP Feedback Collector
An MCP server for collecting interactive user feedback, including text and images, through a graphical interface.
Discord MCP Server
Interact with Discord channels to send and read messages using the Discord API.
BotEmail MCP Server
Give your AI agent its own email address — instant bot inboxes via API, no human setup required.
Reddit Outreach
The only AI tool that connects directly to a proprietary Reddit outreach network — find your prospects, personalize your pitch, and send thousands of DMs per day.