LinkedIn MCP Server
by akinabudu
README.md
# 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
```bash
# 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
```bash
# 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
1. Go to [LinkedIn Developers](https://www.linkedin.com/developers/apps)
2. Click **Create app**
3. 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
4. Click **Create app**
### 2. Get API Credentials
1. Navigate to **Auth** tab
2. Copy **Client ID** and **Client Secret**
3. Add redirect URL: `http://localhost:3000/callback`
4. Request necessary permissions:
- `w_member_social` - Create posts
- `r_liteprofile` - Read profile
- `r_organization_social` - Organization analytics
### 3. Get Access Token
There are two methods:
#### Method A: OAuth Flow (Recommended)
```typescript
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
1. Go to [LinkedIn Token Tools](https://www.linkedin.com/developers/tools/oauth)
2. Select your app
3. Select required scopes
4. Click **Request access token**
5. Copy the access token to `.env`
### 4. Configure Environment
Update `.env` file:
```env
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
```bash
# 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`):
```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.
```json
{
"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.
```json
{
"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.
```json
{
"name": "confirm_post",
"arguments": {
"request_id": "preview-1234567890",
"approved": true
}
}
```
### 4. `preview_post`
Preview a post before publishing.
```json
{
"name": "preview_post",
"arguments": {
"content": "My post content...",
"visibility": "PUBLIC"
}
}
```
### 5. `capture_screenshot`
Capture screenshot from URL.
```json
{
"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.
```json
{
"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.
```json
{
"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.
```json
{
"name": "create_screenshot_collage",
"arguments": {
"screenshot_paths": ["./img1.png", "./img2.png"],
"layout": "horizontal",
"spacing": 20
}
}
```
### 9. `get_profile_info`
Get LinkedIn profile information.
```json
{
"name": "get_profile_info",
"arguments": {}
}
```
### 10. `get_post_analytics`
Get post engagement metrics.
```json
{
"name": "get_post_analytics",
"arguments": {
"post_id": "urn:li:share:1234567890"
}
}
```
## Example Workflows
### Example 1: Full Project Announcement
```typescript
// 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
```typescript
// 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
```typescript
// 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"**
```bash
# 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_ms` parameter
- 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:
```typescript
// 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
```bash
bun test
```
### Building
```bash
bun run build
```
## Security Considerations
- **Never commit `.env` file** 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:
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests if applicable
5. 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](https://modelcontextprotocol.io)
- Uses [Puppeteer](https://pptr.dev) for screenshots
- Powered by [Bun](https://bun.sh) runtime
- AI providers: OpenAI, Google Gemini, OpenRouter
---
**Happy posting! π**
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues