LinkedIn MCP Server
Enables AI-powered LinkedIn post creation, content generation, and screenshot capture through a unified Model Context Protocol interface.
README
LinkedIn MCP Server
A production-ready Model Context Protocol (MCP) server for LinkedIn integration with AI-powered content generation and advanced screenshot capabilities. Automate LinkedIn posting, generate engaging content, and capture beautiful screenshotsβall through a unified MCP interface.
Features
- π€ AI-Powered Content Generation - Generate engaging LinkedIn posts using OpenAI, Google Gemini, or OpenRouter
- πΈ Advanced Screenshot Capture - Capture websites, code snippets, and project demos
- π Approval Workflow - Preview and approve posts before publishing
- π Analytics - Track post performance and engagement
- π¨ Image Processing - Create collages, optimize for LinkedIn, and format code beautifully
- π OAuth 2.0 Authentication - Secure LinkedIn API integration
- π Project Analysis - Automatically analyze projects and generate contextual posts
Installation
Prerequisites
- Bun runtime (latest stable version)
- Linux environment (tested on Ubuntu/Debian)
- Chromium browser for screenshots
- LinkedIn API credentials (see LinkedIn API Setup)
System Dependencies
# Install Chromium and required libraries for Puppeteer
sudo apt-get update
sudo apt-get install -y chromium-browser libgbm1 libasound2
# Optional: Native screenshot tools
sudo apt-get install -y imagemagick
Install Project
# Clone the repository
git clone <your-repo-url>
cd linkedin-mcpserver
# Install dependencies
bun install
# Copy environment template
cp .env.example .env
# Edit .env with your credentials
nano .env
LinkedIn API Setup
1. Create a LinkedIn App
- Go to LinkedIn Developers
- Click Create app
- Fill in app details:
- App name: Your MCP Server
- LinkedIn Page: Select or create a page
- App logo: Upload an icon
- Privacy policy URL: Your privacy policy
- Click Create app
2. Get API Credentials
- Navigate to Auth tab
- Copy Client ID and Client Secret
- Add redirect URL:
http://localhost:3000/callback - Request necessary permissions:
w_member_social- Create postsr_liteprofile- Read profiler_organization_social- Organization analytics
3. Get Access Token
There are two methods:
Method A: OAuth Flow (Recommended)
import { LinkedInAuth } from './src/linkedin/auth.js';
const auth = new LinkedInAuth();
const authUrl = auth.getAuthorizationUrl();
console.log('Visit:', authUrl);
// After authorization, exchange code for token
const tokens = await auth.exchangeCodeForToken(code);
// Save tokens to .env
Method B: LinkedIn Token Inspector
- Go to LinkedIn Token Tools
- Select your app
- Select required scopes
- Click Request access token
- Copy the access token to
.env
4. Configure Environment
Update .env file:
LINKEDIN_CLIENT_ID=your_client_id_here
LINKEDIN_CLIENT_SECRET=your_client_secret_here
LINKEDIN_ACCESS_TOKEN=your_access_token_here
LINKEDIN_REDIRECT_URI=http://localhost:3000/callback
AI_PROVIDER=openai
OPENAI_API_KEY=your_openai_key_here
Configuration
Environment Variables
| Variable | Description | Default |
|---|---|---|
LINKEDIN_CLIENT_ID |
LinkedIn app client ID | Required |
LINKEDIN_CLIENT_SECRET |
LinkedIn app client secret | Required |
LINKEDIN_ACCESS_TOKEN |
LinkedIn access token | Required |
LINKEDIN_REFRESH_TOKEN |
LinkedIn refresh token | Optional |
AI_PROVIDER |
AI provider: openai, gemini, openrouter | openai |
OPENAI_API_KEY |
OpenAI API key | Required if using OpenAI |
GEMINI_API_KEY |
Google Gemini API key | Required if using Gemini |
OPENROUTER_API_KEY |
OpenRouter API key | Required if using OpenRouter |
AI_MODEL |
AI model name | gpt-4 |
SCREENSHOT_OUTPUT_DIR |
Screenshot output directory | ./screenshots |
SCREENSHOT_DEFAULT_WIDTH |
Default viewport width | 1920 |
SCREENSHOT_DEFAULT_HEIGHT |
Default viewport height | 1080 |
SCREENSHOT_QUALITY |
Image quality (1-100) | 90 |
Usage
Running the Server
# Development mode
bun run dev
# Production mode
bun run start
Using with MCP Clients
VS Code / Cline Configuration
Add to your MCP settings (e.g., ~/.cline/mcp_settings.json):
{
"mcpServers": {
"linkedin": {
"command": "bun",
"args": ["run", "/path/to/linkedin-mcpserver/src/index.ts"],
"env": {
"LINKEDIN_CLIENT_ID": "your_client_id",
"LINKEDIN_CLIENT_SECRET": "your_client_secret",
"LINKEDIN_ACCESS_TOKEN": "your_access_token",
"OPENAI_API_KEY": "your_openai_key"
}
}
}
}
Available Tools
1. analyze_project
Analyze a project and generate LinkedIn post content.
{
"name": "analyze_project",
"arguments": {
"project_path": "./my-project",
"include_commits": true,
"commit_count": 5,
"tone": "professional",
"length": "medium",
"capture_screenshots": true,
"screenshot_config": {
"include_demo": true,
"localhost_url": "http://localhost:3000",
"pages_to_demo": ["/", "/dashboard", "/settings"]
}
}
}
2. create_linkedin_post
Create and publish a LinkedIn post.
{
"name": "create_linkedin_post",
"arguments": {
"content": "Excited to share my new project! π\n\nBuilt with React, TypeScript, and Tailwind CSS...",
"visibility": "PUBLIC",
"media_urls": ["/path/to/screenshot.png"],
"require_approval": true
}
}
3. confirm_post
Confirm or reject a pending post.
{
"name": "confirm_post",
"arguments": {
"request_id": "preview-1234567890",
"approved": true
}
}
4. preview_post
Preview a post before publishing.
{
"name": "preview_post",
"arguments": {
"content": "My post content...",
"visibility": "PUBLIC"
}
}
5. capture_screenshot
Capture screenshot from URL.
{
"name": "capture_screenshot",
"arguments": {
"source_type": "url",
"source": "https://example.com",
"viewport_width": 1920,
"viewport_height": 1080,
"full_page": false
}
}
6. capture_project_demo
Capture multiple pages for project demo.
{
"name": "capture_project_demo",
"arguments": {
"project_url": "http://localhost:3000",
"pages_to_capture": ["/", "/features", "/pricing"],
"include_mobile_view": true,
"create_collage": true
}
}
7. capture_code_snippet
Capture beautifully formatted code.
{
"name": "capture_code_snippet",
"arguments": {
"file_path": "./src/components/Hero.tsx",
"line_start": 10,
"line_end": 30,
"theme": "github-dark",
"show_line_numbers": true
}
}
8. create_screenshot_collage
Combine multiple screenshots.
{
"name": "create_screenshot_collage",
"arguments": {
"screenshot_paths": ["./img1.png", "./img2.png"],
"layout": "horizontal",
"spacing": 20
}
}
9. get_profile_info
Get LinkedIn profile information.
{
"name": "get_profile_info",
"arguments": {}
}
10. get_post_analytics
Get post engagement metrics.
{
"name": "get_post_analytics",
"arguments": {
"post_id": "urn:li:share:1234567890"
}
}
Example Workflows
Example 1: Full Project Announcement
// 1. Analyze project and generate content
const analysis = await analyzedProject({
project_path: "./my-app",
capture_screenshots: true,
screenshot_config: {
include_demo: true,
localhost_url: "http://localhost:3000",
pages_to_demo: ["/", "/dashboard"]
},
tone: "professional",
length: "medium"
});
// 2. Create post with preview
const post = await createLinkedInPost({
content: analysis.generated_content,
media_urls: analysis.screenshots,
visibility: "PUBLIC",
require_approval: true
});
// 3. Confirm after review
await confirmPost({
request_id: post.preview_id,
approved: true
});
Example 2: Code Snippet Share
// 1. Capture code screenshot
const code = await captureCodeSnippet({
file_path: "./src/auth/oauth.ts",
line_start: 45,
line_end: 75,
theme: "github-dark"
});
// 2. Post with manual content
await createLinkedInPost({
content: "Just implemented OAuth 2.0 authentication! π\n\nHere's the core logic...",
media_urls: [code.path],
require_approval: false
});
Example 3: Weekly Progress Update
// Analyze recent commits
const analysis = await analyzeProject({
include_commits: true,
commit_count: 20,
tone: "casual",
length: "short"
});
// Post update
await createLinkedInPost({
content: analysis.generated_content,
visibility: "PUBLIC"
});
Troubleshooting
Authentication Issues
Error: "Invalid access token"
- Verify token is correct in
.env - Check if token has expired (LinkedIn tokens expire)
- Request a new token from LinkedIn Developer Portal
Error: "Insufficient permissions"
- Verify your app has required scopes:
w_member_social,r_liteprofile - Re-authorize with correct permissions
Screenshot Issues
Error: "Failed to launch browser"
# Install Chromium
sudo apt-get install chromium-browser
# If on WSL, you may need:
export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
export PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
Error: "Page load timeout"
- Increase timeout in code or use
delay_msparameter - Check if localhost server is running
- Verify URL is accessible
API Rate Limits
LinkedIn has rate limits:
- Posts: 100 per day
- API calls: Varies by endpoint
The server implements rate limiting and will throw RateLimitError when exceeded.
Memory Issues
If browser instances aren't being cleaned up:
// The server automatically cleans up, but you can force cleanup
import { puppeteerService } from './src/screenshots/puppeteer-service.js';
await puppeteerService.cleanup();
Development
Project Structure
linkedin-mcpserver/
βββ src/
β βββ index.ts # MCP server entry point
β βββ config.ts # Configuration management
β βββ linkedin/ # LinkedIn API integration
β β βββ auth.ts
β β βββ client.ts
β β βββ posts.ts
β β βββ media.ts
β β βββ types.ts
β βββ project-analysis/ # Project analysis & AI
β β βββ file-reader.ts
β β βββ git-analyzer.ts
β β βββ content-generator.ts
β β βββ context-builder.ts
β β βββ ai-providers/
β βββ screenshots/ # Screenshot system
β β βββ capturer.ts
β β βββ puppeteer-service.ts
β β βββ code-formatter.ts
β β βββ image-processor.ts
β β βββ types.ts
β βββ tools/ # MCP tools
β β βββ analyze-project.ts
β β βββ create-post.ts
β β βββ capture-screenshot.ts
β β βββ ...
β βββ utils/ # Utilities
β βββ logger.ts
β βββ error-handler.ts
β βββ rate-limiter.ts
βββ .env.example
βββ package.json
βββ tsconfig.json
βββ README.md
Running Tests
bun test
Building
bun run build
Security Considerations
- Never commit
.envfile with credentials - Validate all inputs before posting to LinkedIn
- Be careful with screenshots - don't capture sensitive data
- Use approval workflow for important posts
- Monitor API usage to avoid rate limits
- Review generated content before posting
Rate Limits
LinkedIn API limits:
- Posts: 100 per day
- Profile reads: More lenient
- Analytics: Limited per hour
The server implements rate limiting to prevent exceeding these limits.
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
License
MIT License - see LICENSE file for details
Support
For issues and questions:
- GitHub Issues: [Your repo issues page]
- Documentation: This README
- LinkedIn API Docs: https://docs.microsoft.com/en-us/linkedin/
Acknowledgments
- Built with Model Context Protocol
- Uses Puppeteer for screenshots
- Powered by Bun runtime
- AI providers: OpenAI, Google Gemini, OpenRouter
Happy posting! π
Recommended Servers
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.
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.
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.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
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.
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.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
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.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.