LinkedIn MCP
This server lets an AI assistant help you prepare and approve LinkedIn text and single-image posts while keeping publishing under your control.
Connect a LinkedIn account via OAuth 2.0 (
start_linkedin_connection,complete_linkedin_connection)Check whether LinkedIn is configured without exposing credentials (
linkedin_connection_status)Prepare a LinkedIn post for review without publishing anything (
prepare_linkedin_post)Publish an already-reviewed text post, optionally with a single image, only after explicit human approval (
publish_linkedin_post)Support local image uploads accompanying text posts
Work with MCP-compatible AI clients like Claude Desktop
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., "@LinkedIn MCPprepare a LinkedIn post announcing our new product launch"
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.
LinkedIn MCP
An open-source MCP server that lets an AI assistant help you prepare and publish LinkedIn posts while keeping you in control of the final publish action.
You do not need to understand MCP or the LinkedIn API to try this project. This guide walks through the setup from the beginning.
What can it do?
Today the project can:
Connect your LinkedIn account using OAuth 2.0
Prepare a LinkedIn text post for review
Publish a text post after you explicitly approve it
Upload and publish a single image with a post
Work with MCP-compatible AI clients such as Claude Desktop
Handwritten/whiteboard-style diagram generation and publishing is the next feature being developed.
Related MCP server: linkedin-mcp
Before you start
You need:
A LinkedIn account
A LinkedIn Developer App
Node.js 20 or newer
Git
An MCP-compatible client such as Claude Desktop
You do not need to manually create LinkedIn access tokens.
Step 1: Download the project
Open Terminal, PowerShell, or Command Prompt and run:
git clone https://github.com/nitishnaidi/linkedin-mcp.git
cd linkedin-mcp
npm install
npm run buildIf the build completes without an error, the project is ready locally.
Step 2: Create a LinkedIn Developer App
Go to the LinkedIn Developer portal and create an application.
Inside your application, enable these products:
Share on LinkedIn
Sign In with LinkedIn using OpenID Connect
These give the application the permissions needed to identify you and publish posts after your approval.
The OAuth scopes used by this project are:
openid
profile
w_member_socialStep 3: Configure the LinkedIn callback URL
In your LinkedIn Developer App, open the OAuth settings.
Add this exact Authorized Redirect URL:
http://127.0.0.1:8787/callbackDo not replace 127.0.0.1 with localhost unless you also change the application configuration.
From the LinkedIn Developer App, copy your:
Client ID
Client Secret
Keep the Client Secret private. Never commit it to GitHub.
Step 4: Configure your MCP client
Your MCP client needs to start the compiled server and provide the LinkedIn credentials as environment variables.
A typical configuration looks like this:
{
"mcpServers": {
"linkedin": {
"command": "node",
"args": ["/FULL/PATH/TO/linkedin-mcp/dist/index.js"],
"env": {
"LINKEDIN_CLIENT_ID": "YOUR_CLIENT_ID",
"LINKEDIN_CLIENT_SECRET": "YOUR_CLIENT_SECRET",
"LINKEDIN_REDIRECT_URI": "http://127.0.0.1:8787/callback"
}
}
}
}Replace /FULL/PATH/TO/linkedin-mcp with the folder where you cloned this repository.
Restart your MCP client after saving the configuration.
Step 5: Connect LinkedIn
Ask your AI client to start the LinkedIn connection.
Behind the scenes it calls:
start_linkedin_connectionThe tool returns a LinkedIn authorization link. Open it in your browser and approve access.
Then ask the client to complete the connection. It calls:
complete_linkedin_connectionTo confirm everything worked, the client can call:
linkedin_connection_statusYou should see:
{"configured":true}Your first LinkedIn post
Ask your AI assistant something like:
Prepare a LinkedIn post saying: Testing my LinkedIn MCP integration.The assistant uses prepare_linkedin_post. This step does not publish anything.
Review the text. When you are satisfied, explicitly tell the assistant to publish it.
Publishing uses publish_linkedin_post with approval set to true.
This separation is intentional: preparing content and publishing content are two different actions so an AI assistant cannot silently publish a draft.
Posting an image
You can also prepare a post with a local image path.
Example request:
Prepare a LinkedIn post with the image at /Users/me/Pictures/diagram.png and the text "A simple architecture diagram."The MCP prepares the post first. After you review and approve it, the image is uploaded to LinkedIn and the post is published.
The single-image implementation exists, but the project still tracks a separate live image smoke test as a validation item.
Handwritten diagrams
The next feature is designed for requests such as:
Create a handwritten diagram explaining how an AI agent uses RAG and publish it to LinkedIn.The intended workflow is:
Idea
↓
Generate diagram specification
↓
Render handwritten-style image
↓
Preview image + post text
↓
Human approval
↓
Upload image
↓
Publish to LinkedInDiagram generation must remain separate from publication so the generated image can always be reviewed before it reaches LinkedIn.
Security
The project follows a few important rules:
Client secrets are never returned by MCP tools.
Access tokens are never returned by the connection-status tool.
OAuth state is validated.
Preparing a post never publishes it.
Publishing requires an explicit approval flag.
Access tokens currently live only in the running process.
Restarting the MCP server currently requires reconnecting LinkedIn.
Do not expose this local MCP server directly to the public internet.
Troubleshooting
linkedin_connection_status says false
Make sure you completed both the browser authorization and complete_linkedin_connection steps.
LinkedIn says the redirect URL is invalid
Verify the Developer App contains exactly:
http://127.0.0.1:8787/callbackThe MCP client cannot start the server
First verify this succeeds inside the repository:
npm install
npm run buildThen verify the path to dist/index.js in your MCP configuration is absolute and correct.
It worked before restarting but is disconnected now
That is expected in the current MVP. Tokens are process-local. Persistent encrypted token storage is planned for a later iteration.
Development
Before submitting changes, run:
npm run typecheck
npm run buildGitHub Actions runs the same validation on pull requests.
Implementation checkpoints are maintained in docs/PROGRESS.md so development can resume safely after interruptions.
Current validation status
OAuth and human-approved text publishing were successfully smoke-tested against a real LinkedIn member account on September 16, 2026.
Single-image publishing is implemented and awaiting its separate live smoke test.
License
MIT
Available Tools
5 toolscomplete_linkedin_connectionB
Complete LinkedIn OAuth after authorization in the browser.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must carry the full burden of behavioral disclosure. It indicates a state-changing operation ('complete') but gives no details on prerequisites beyond timing, potential side effects, error conditions, or what the function returns. For an OAuth completion step, an agent might need to know whether it can be called multiple times, what happens if called before authorization, or how to handle failures. This is a significant gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence with zero wasted words. It places the essential condition ('after authorization in the browser') right at the start. Every word contributes to the meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 0-parameter tool with no output schema, the description covers the essential usage timing but omits other operational context. It does not explain the return value (which could be critical for the agent to know whether the connection succeeded), nor does it note any prerequisites beyond the browser step. The lack of an output schema raises the burden on the description to describe the result, which it fails to do. Still, given the simplicity, it is minimally adequate.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the schema is trivially 100% covered. Per the calibration guidance, a 0-parameter tool gets a baseline of 4. The description does not add parameter-specific details (there are none), and that is acceptable because there is nothing to document.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool completes the LinkedIn OAuth flow after browser authorization. The verb 'complete' and the specific context 'after authorization in the browser' make the purpose unambiguous and distinguishable from sibling tools like start_linkedin_connection, which initiates the flow. It is specific enough for an agent to understand the tool's role, though it does not explicitly name the alternative.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides a usage condition: 'after authorization in the browser' – implying this tool should be called only after the user has completed the browser-based OAuth step. However, it does not explicitly state when NOT to use it or mention alternative tools like start_linkedin_connection. The guidance is implied rather than explicit, so it meets the 'clear context, no exclusions' level.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
linkedin_connection_statusA
Check LinkedIn publishing configuration without exposing credentials.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. The phrase 'without exposing credentials' is a useful behavioral disclosure about output sanitization. However, it does not mention side effects, preconditions, or what the tool actually returns.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One compact sentence with the main action front-loaded and a valuable security qualifier appended. There is no filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Adequate for a zero-parameter status check, but because there is no output schema and no annotations, an agent is left guessing about the return shape and whether any connection must exist before calling it. A little more context would make it fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the schema coverage is trivially complete. There is nothing for the description to add about parameter meaning, and the baseline for zero-parameter tools applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description is precise: it names a specific verb ('Check'), a resource ('LinkedIn publishing configuration'), and adds a meaningful safety qualifier. It clearly distinguishes this from sibling tools that start/complete connections or prepare/publish posts.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No explicit when-to-use or when-not-to-use guidance is provided. The tool name and sibling list imply this is for inspecting connection/publishing state rather than mutating it, but the description does not state this directly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
prepare_linkedin_postA
Prepare a LinkedIn post for human review. This never publishes.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | ||
| altText | No | ||
| imagePath | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure. It provides one valuable safety guarantee: the tool never publishes. However, it does not explain what 'prepare' actually does—whether it creates a draft, stores content, or simply returns a representation—so the behavior remains underspecified.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, zero filler, and the most important behavioral fact ('This never publishes') is front-loaded in the second sentence. Every word earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple three-parameter tool, the description is nearly sufficient: the required text parameter is inferable, and the safety boundary is clear. Still, with no output schema and no parameter-level guidance, an agent does not know what the tool returns or what side effects, if any, 'prepare' has.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, and the description adds no meaning to text, altText, or imagePath beyond their names and schema constraints. The phrase 'for human review' hints that text is the reviewed content, but the description does not compensate for the absent parameter documentation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb ('prepare'), a resource ('LinkedIn post'), and a clear goal ('for human review'). The explicit statement 'This never publishes' separates it from the sibling publish_linkedin_post without any ambiguity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'For human review' gives clear context for when to use the tool, and 'This never publishes' rules out the main alternative action. It does not explicitly name publish_linkedin_post or spell out 'use this when you want a draft instead of publishing,' but the intended usage is strongly implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
publish_linkedin_postA
Publish an already-reviewed LinkedIn post only after explicit human approval.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | ||
| altText | No | ||
| approved | Yes | ||
| imagePath | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral disclosure burden. It usefully discloses the human-approval gate and the reviewed-status precondition, which are important behavioral traits. However, it does not mention that publishing is a public, likely irreversible action, nor any authentication or connection requirements.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single efficient sentence with no filler. The key action and the critical safety condition are front-loaded, making it easy for an agent to grasp the tool's purpose quickly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a publishing tool with no annotations, no output schema, and 0% schema description coverage, the description is too thin. It omits parameter details, return behavior, error conditions, and workflow integration with prepare_linkedin_post, leaving an agent with only partial guidance for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, and the description does not explain any parameter beyond implying that approval is required. Parameter names like text, altText, imagePath, and approved are somewhat self-explanatory, but the description adds no semantic detail to compensate for the absence of schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Publish'), a clear resource ('already-reviewed LinkedIn post'), and a defining condition ('only after explicit human approval'). This clearly distinguishes it from sibling tools like prepare_linkedin_post, which would handle drafting/review rather than final publication.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description conveys the key usage condition: this tool should only be used after a post has been reviewed and explicitly approved by a human. It does not explicitly name prepare_linkedin_post as the prerequisite alternative, but 'already-reviewed' strongly implies the correct workflow position.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
start_linkedin_connectionA
Start LinkedIn OAuth and return the authorization URL.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral transparency burden. It states the action and return value clearly, but it does not disclose whether invoking this tool creates persistent state, whether the authorization URL expires, or whether user interaction is required to complete the flow.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence with no filler. It communicates both the action and the expected result efficiently, containing only information needed for the agent.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter tool with no output schema, the description sufficiently covers what the agent needs to know to invoke it: it initiates OAuth and returns the authorization URL. Minor context about the broader OAuth flow and how this relates to complete_linkedin_connection could add value but is not essential.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the input schema is complete and there is nothing for the description to add. The description correctly focuses on the tool's action and output rather than inventing unnecessary parameter details.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Start') with a clear resource ('LinkedIn OAuth') and states the concrete output ('return the authorization URL'). This clearly identifies the tool's role and differentiates it from siblings like complete_linkedin_connection and linkedin_connection_status.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies this is the first step in the LinkedIn OAuth flow, which is useful context alongside the sibling tool complete_linkedin_connection. However, it does not explicitly state when to use this tool versus alternatives, nor does it mention prerequisites or exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v0.3.0- First observed
complete_linkedin_connection - First observed
linkedin_connection_status - First observed
prepare_linkedin_post - First observed
publish_linkedin_post - First observed
start_linkedin_connection
TDQS
Scored across 5 tools
Each tool has a clearly distinct purpose: connection status, OAuth start, OAuth completion, post preparation, and post publishing. There is no overlap between these operations, and the prepare/publish distinction is explicit. An agent can easily select the right tool for each step.
All tool names are snake_case and share the 'linkedin_' prefix, and four use a verb_noun pattern (start/complete/prepare/publish). The one exception is 'linkedin_connection_status', which uses a noun phrase instead of 'get_connection_status', a minor deviation. Overall the pattern is predictable and readable.
With 5 tools, the set is well-scoped for a LinkedIn publishing/OAuth workflow. It covers the essential steps without unnecessary redundancy, and the count is typical for a focused integration server.
The tools cover the full intended workflow: connection status, OAuth initiation/completion, post preparation, and post publishing. Minor gaps exist (e.g., no explicit disconnect or post-history tool), but these do not break the core human-in-the-loop publishing flow the server is designed for.
Maintenance
Related MCP Connectors
Draft, schedule, and publish posts to 8 social platforms with human approval via Socialync OAuth.
LinkedIn API as MCP tools to retrieve profile data and publish content. Powered by HAPI MCP.
Schedule and publish social posts with OAuth, drafts, media, workspaces, and brand memory.
Draft, schedule and publish LinkedIn posts, reply to comments and read analytics via 2pr.io.
Related MCP Servers
- AlicenseAqualityDmaintenanceEnables posting content, sharing articles, and managing LinkedIn profile through natural language using the official LinkedIn REST API with OAuth 2.0.78 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.915 npmApache 2.0
- AlicenseAqualityCmaintenanceEnables publishing and scheduling LinkedIn posts through the official API, with content calendar and post brief tools for consistent growth.7MIT
- AlicenseAqualityBmaintenanceEnables local-only use of LinkedIn's official API to authenticate via OAuth, publish text posts, and read or reply to comments with explicit confirmation. Keeps access tokens in the OS keychain and avoids scraping or browser automation.4MIT