Skip to main content
Glama
linkedin-mcp

linkedin-mcp

by aigamer-dev

linkedin-mcp

Let your AI agent read your LinkedIn profile basics and publish posts, through LinkedIn's official API.

CI License: MIT MCP Node

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

get_profile

Basic profile of the signed-in member: name, email, picture, locale

none

create_post

Publish a text post to your feed

text (1-3000 chars), visibility (PUBLIC or CONNECTIONS, default PUBLIC)

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/mcp

Client

How

Claude (web, desktop) and other apps with a connectors screen

Settings → Connectors → Add custom connector → paste the URL

Claude Code

claude mcp add --transport http --scope user linkedin https://linkedin-mcp.hariharankvasn.workers.dev/mcp, then /mcp to sign in

OpenClaw

openclaw mcp add linkedin --url https://linkedin-mcp.hariharankvasn.workers.dev/mcp --transport streamable-http --auth oauth

Cursor

add {"mcpServers":{"linkedin":{"url":"https://linkedin-mcp.hariharankvasn.workers.dev/mcp"}}} to ~/.cursor/mcp.json

VS Code

add {"servers":{"linkedin":{"type":"http","url":"https://linkedin-mcp.hariharankvasn.workers.dev/mcp"}}} to your user mcp.json

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 -- --hosted

Add --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 | bash

The 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 agents

Requires 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

claude mcp add linkedin --scope user -- node /path/to/linkedin-mcp/dist/index.js

Codex CLI

codex mcp add linkedin -- node /path/to/linkedin-mcp/dist/index.js

OpenClaw

openclaw mcp add linkedin --command node --arg /path/to/linkedin-mcp/dist/index.js

Gemini CLI

gemini mcp add --scope user linkedin node /path/to/linkedin-mcp/dist/index.js

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

~/.cursor/mcp.json

Windsurf

~/.codeium/windsurf/mcp_config.json

Claude Desktop

~/.config/Claude/claude_desktop_config.json (Linux), ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)

VS Code

user mcp.json (uses a top-level servers key and "type": "stdio")

OpenCode

~/.config/opencode/opencode.json (uses "mcp" with "type": "local" and a command array)

Gemini CLI (no CLI on PATH)

~/.gemini/settings.json

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.

  1. 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".

  2. On the Products tab, add Share on LinkedIn and Sign In with LinkedIn using OpenID Connect.

  3. On the Auth tab, add the redirect URL http://localhost:3000/callback.

  4. Put the client ID and secret in .env inside 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/callback
  5. Authorize once, open the printed URL and approve:

    cd ~/.local/share/linkedin-mcp && npm run auth
  6. Restart 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 .env and token file. Nothing is sent anywhere except api.linkedin.com and www.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_post publishes 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

Not authenticated

Run npm run auth in the install directory

LinkedIn token expired

Re-run npm run auth (tokens last about 60 days)

redirect_uri mismatch

The redirect URL in your LinkedIn app must be exactly http://localhost:3000/callback

unauthorized_scope_error

Add both products (Share on LinkedIn, Sign In with OpenID Connect) to your app

Port 3000 busy during npm run auth

Free the port, or change the URL in both .env and the LinkedIn app

Server not listed in the agent

Restart the agent; run ./install.sh --list and check the config file path

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

MIT

Available Tools

2 tools
create_postC

Publish a text post to the authenticated member's LinkedIn feed.

NameRequiredDescriptionDefault
textYes
visibilityNoPUBLIC

TDQS

C2.9/5.0
Behavior2/5

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.

Conciseness4/5

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.

Completeness2/5

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.

Parameters2/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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).

NameRequiredDescriptionDefault

No parameters

TDQS

A3.7/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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.

  1. 2 tool updatesv0.1.0
    • First observedcreate_post
    • First observedget_profile

TDQS

B3.3/5.0

Scored across 2 tools

Disambiguation5/5

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.

Naming Consistency5/5

Both names follow the same verb_noun snake_case convention (get_profile, create_post) with unambiguous verbs and resources.

Tool Count3/5

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.

Completeness2/5

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

ActivityMaintained
ResponsivenessNo recent community issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    C
    maintenance
    Enables AI agents with read/write access to LinkedIn API, including profile, posts, media, organizations, comments, reactions, and analytics.
    20
    12 npm
    MIT
  • A
    license
    B
    quality
    C
    maintenance
    Allows AI agents to authenticate with LinkedIn and share posts or links via the Model Context Protocol.
    2
    119 npm
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI assistants to create and manage LinkedIn posts via OAuth, including text posts, URL shares, deletions, profile lookup, and company page posting.
    2 npm
    MIT