linkedin-mcp
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-mcpShare a LinkedIn post: Excited to launch our new open-source MCP server!"
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
Let your AI agent read your LinkedIn profile basics and publish posts, through LinkedIn's official API.
Website · Changelog · Contributing · Report a bug
Not affiliated with or endorsed by LinkedIn. "LinkedIn" is a trademark of LinkedIn Corporation.
What it is
linkedin-mcp is a local Model Context Protocol server. It runs on your machine, talks to your AI agent over stdio, and calls LinkedIn's official OAuth 2.0 API with your own developer app. Your keys and token never leave your computer.
Tool | Description | Inputs |
| Basic profile of the signed-in member: name, email, picture, locale | none |
| Publish a text post to your feed |
|
LinkedIn does not offer profile editing, messaging, search or analytics to individual developers, so those are out of scope. See the limits table.
Related MCP server: LinkedIn MCP Server
Fastest: the hosted connector
No app to create, no keys, nothing to install. Add this URL as a remote MCP connector, click Connect and sign in to LinkedIn:
https://linkedin-mcp.hariharankvasn.workers.dev/mcpClient | How |
Claude (web, desktop) and other apps with a connectors screen | Settings → Connectors → Add custom connector → paste the URL |
Claude Code |
|
OpenClaw |
|
Cursor | add |
VS Code | add |
Any other MCP client | Use the URL; the server supports OAuth 2.1 with dynamic client registration |
Or add it to every agent detected on your machine with one command (no Node, clone or build needed for the CLI-based agents):
curl -fsSL https://raw.githubusercontent.com/aigamer-dev/linkedin-mcp/main/install.sh | bash -s -- --hostedAdd --agents claude,cursor to choose, --dry-run to preview, --uninstall to remove, or --url https://your-own-deployment/mcp to point at your own deployment of worker/.
You approve on a consent page (including whether posting is allowed) and then on LinkedIn's own screen. LinkedIn's access lasts about 60 days, after which you reconnect. Posting is limited to 10 posts per day per member. See the privacy policy for exactly what is stored (your LinkedIn member ID, name and an encrypted access token; never the text of your posts).
Prefer to keep everything on your own machine, or to use your own LinkedIn app? Use the local version below.
Run it locally (your own LinkedIn app)
curl -fsSL https://raw.githubusercontent.com/aigamer-dev/linkedin-mcp/main/install.sh | bashThe script clones the repo to ~/.local/share/linkedin-mcp, builds it, and registers it with every supported agent it finds. Then connect your LinkedIn account (one time) and restart your agent.
Prefer to read the script first, or choose agents yourself:
git clone https://github.com/aigamer-dev/linkedin-mcp.git && cd linkedin-mcp
./install.sh --list # which agents were detected
./install.sh --agents claude,codex # only these
./install.sh --dry-run # show what would change
./install.sh --uninstall # remove from detected agentsRequires Node.js 20+, npm and git (macOS or Linux). Each config file is backed up as *.bak.<timestamp> before it is edited.
Install per agent
The installer runs the commands below for you. They are listed so you can run them by hand. Replace /path/to/linkedin-mcp with your install directory (default ~/.local/share/linkedin-mcp).
Agent | Command |
Claude Code |
|
Codex CLI |
|
OpenClaw |
|
Gemini CLI |
|
For editors and apps that use a JSON config, add this entry under mcpServers (servers for VS Code):
{
"mcpServers": {
"linkedin": {
"command": "node",
"args": ["/path/to/linkedin-mcp/dist/index.js"]
}
}
}App | Config file |
Cursor |
|
Windsurf |
|
Claude Desktop |
|
VS Code | user |
OpenCode |
|
Gemini CLI (no CLI on PATH) |
|
Codex without its CLI on PATH, add to ~/.codex/config.toml:
[mcp_servers.linkedin]
command = "node"
args = ["/path/to/linkedin-mcp/dist/index.js"]Any other MCP client works too: launch node dist/index.js and speak MCP over stdio.
Connect your LinkedIn account (local version only)
The hosted connector does this for you. For the local server, one time, about five minutes.
Create a LinkedIn Page you administer (a small personal-brand page is fine) and an app at https://www.linkedin.com/developers/apps. App names cannot contain "LinkedIn".
On the Products tab, add Share on LinkedIn and Sign In with LinkedIn using OpenID Connect.
On the Auth tab, add the redirect URL
http://localhost:3000/callback.Put the client ID and secret in
.envinside the install directory (the installer creates it from.env.example):LINKEDIN_CLIENT_ID=your-client-id LINKEDIN_CLIENT_SECRET=your-client-secret LINKEDIN_REDIRECT_URI=http://localhost:3000/callbackAuthorize once, open the printed URL and approve:
cd ~/.local/share/linkedin-mcp && npm run authRestart your agent.
The token is stored at ~/.config/linkedin-mcp/token.json (mode 600), outside the repo, and lasts about 60 days. Re-run npm run auth to refresh it.
Usage examples
Once connected, just ask your agent:
"Who am I signed in as on LinkedIn?"
"Draft a post about this week's release from CHANGELOG.md. Show it to me first, then publish it to my connections only."
Security
Local version: credentials live only in your
.envand token file. Nothing is sent anywhere exceptapi.linkedin.comandwww.linkedin.com.Hosted connector: runs on Cloudflare Workers. The LinkedIn app secret is held as a Worker secret, and each member's access token is stored encrypted and only released to the connection they approved. Source is in
worker/, so you can audit it or deploy your own copy.create_postpublishes as you, publicly by default. Set your agent to ask for approval on tool calls so every post is confirmed.Never commit
.env; it is git-ignored. Report vulnerabilities privately through the repository's Security tab.
Troubleshooting
Symptom | Fix |
| Run |
| Re-run |
| The redirect URL in your LinkedIn app must be exactly |
| Add both products (Share on LinkedIn, Sign In with OpenID Connect) to your app |
Port 3000 busy during | Free the port, or change the URL in both |
Server not listed in the agent | Restart the agent; run |
App flagged for its name | Rename the app in the LinkedIn developer portal so it doesn't imitate LinkedIn branding |
Contributing
Pull requests are welcome. Direct pushes to main are limited to the maintainer; everything else goes through a PR that needs 2 approvals and passing CI. See CONTRIBUTING.md for setup, tests, the release process and how to add support for another agent. Notable changes are tracked in CHANGELOG.md.
License
Available Tools
2 toolscreate_postC
Publish a text post to the authenticated member's LinkedIn feed.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | ||
| visibility | No | PUBLIC |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are supplied, so the description carries the full burden of behavioral disclosure. It does clarify the important identity aspect (the post is attributed to the authenticated member), but for a mutation it omits whether the action is reversible, what permissions/scopes are required, rate limits, and what the response contains (e.g., a post URN).
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?
A single front-loaded sentence with no filler or redundancy. It is efficient, though its brevity is part of why key details like visibility semantics are missing.
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 write operation with no annotations, no output schema, and undocumented parameters, the description is thin. An agent still lacks the visibility enum meaning, permission requirements, and what a successful call returns, all of which matter for a publishing action.
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?
With 0% schema description coverage across 2 parameters, the description must compensate. 'Text post' loosely signals that the required text field is the body content, but nothing explains the visibility enum values PUBLIC vs CONNECTIONS or the PUBLIC default — the one parameter where an agent is most likely to make a wrong choice.
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 gives a specific verb ('Publish') and resource ('a text post') scoped to 'the authenticated member's LinkedIn feed', which tells an agent exactly what gets created and under whose identity. It does not name or differentiate from the only sibling, get_profile, but the two are functionally distinct enough that confusion is unlikely.
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?
Usage is implied by 'Publish ... to the feed' — this is the tool for creating a post rather than reading profile data. There is no explicit when-to-use/when-not-to-use statement, no mention of prerequisites such as granted scopes, and no guidance on choosing between visibility options.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_profileA
Get the authenticated member's basic LinkedIn profile (name, email, picture, locale).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are supplied, so the description carries the full behavioral burden. 'Get' implies a non-mutating read and 'authenticated member's' hints at an OAuth requirement, but the description never states that it is read-only, what happens when the token is missing or expired, or whether results are cached. It also does not describe the return shape beyond a field list.
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?
A single front-loaded sentence with the resource and returned fields up front and no filler wording. Nothing could be removed without losing information.
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 annotations and no output schema, the description covers the essentials, and the enumerated field list partially compensates for the absent output schema. The remaining gap is failure behavior when no authenticated session exists, which an agent may need to handle.
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 takes zero parameters, so there is nothing for the description to disambiguate; baseline 4 applies. The parenthetical field list is a small bonus that tells the agent what the call yields, though it is really return-value information rather than parameter meaning.
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?
Specific verb ('Get') plus a precisely scoped resource ('the authenticated member's basic LinkedIn profile'), and it enumerates the returned fields (name, email, picture, locale). The 'authenticated member's' phrasing also disambiguates scope. It does not explicitly name a sibling, but with only create_post alongside it, the read/write distinction is self-evident.
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?
Usage is only implied: an agent can infer this is the tool to call to identify the current user, and there is no alternative read tool to choose between. There is no explicit statement of when to use it, no precondition (e.g. requires a valid access token), and no note about what to do on failure.
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.
2 tool updates
v0.1.0- First observed
create_post - First observed
get_profile
TDQS
Scored across 2 tools
The two tools perform clearly separate operations on different resources: reading the authenticated profile versus publishing a post. There is no realistic way to confuse get_profile with create_post.
Both names follow the same verb_noun snake_case convention (get_profile, create_post) with unambiguous verbs and resources.
Two tools is thin for a LinkedIn integration, which naturally spans profiles, posts, feeds, and connections. It is a reasonable minimal pair but feels under-scoped rather than well-developed.
The surface only supports reading one's own profile and publishing a text post. There is no way to update the profile, read/list one's posts, delete or edit a post, or interact with others, leaving obvious lifecycle gaps.
Maintenance
Related MCP Connectors
LinkedIn for AI agents: search people, read profiles, posts and connections via a connected account
Schedule and publish LinkedIn posts to profiles and company pages from AI agents.
LinkedIn jobs, companies and people for AI agents, plus messages and invites via your own account.
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.15 npmMIT
- AlicenseBqualityCmaintenanceEnables AI agents with read/write access to LinkedIn API, including profile, posts, media, organizations, comments, reactions, and analytics.2012 npmMIT
- AlicenseBqualityCmaintenanceAllows AI agents to authenticate with LinkedIn and share posts or links via the Model Context Protocol.2119 npmMIT
- AlicenseNot gradedqualityCmaintenanceEnables AI assistants to create and manage LinkedIn posts via OAuth, including text posts, URL shares, deletions, profile lookup, and company page posting.2 npmMIT