Skip to main content
Glama
abhineet34

linkedin-mcp-server

by abhineet34

LinkedIn MCP Server

Post to LinkedIn from Claude. A Model Context Protocol (MCP) server that lets Claude Desktop, Claude Code, and any MCP-compatible AI assistant publish posts, upload images, and manage company pages on LinkedIn — using natural language.

Glama License: MIT Node.js TypeScript MCP PRs Welcome

Imagine asking Claude "draft a LinkedIn post about my latest project and publish it" — and it just happens. That's what this MCP server enables.


✨ Features

📝 Create posts

Publish text, image, or article/link posts

🖼️ Upload images

Attach images to posts in one workflow

✏️ Edit & delete

Update post text/visibility or remove posts entirely

👤 Profile

Fetch your name, email, photo, and LinkedIn URN

🏢 Companies

Look up company pages by name or ID

📊 Follower counts

Get follower stats for any company page

🤖 Works with any MCP client

Claude Desktop, Claude Code, Cline, Continue, etc.

🔐 OAuth 2.0 secured

Industry-standard auth, runs locally on your machine



Related MCP server: linkedin-mcp-server

💬 What it looks like

Once connected, just talk to Claude naturally:

You:    Draft a LinkedIn post announcing my new open-source project and publish it.

Claude: Here's a draft:

        🚀 Just open-sourced linkedin-mcp-server — an MCP server that lets
        Claude post to LinkedIn directly. No more copy-pasting drafts.

        Built with TypeScript and the LinkedIn REST API. Star on GitHub if
        you find it useful!

        Should I post this?

You:    Yes, publish it.

Claude: ✅ Posted. URN: urn:li:share:7339284...

Other things you can ask:

  • "Look up the LinkedIn page for OpenAI and tell me how many followers they have"

  • "Delete my last LinkedIn post"

  • "Edit my latest post to add a link to the docs"

  • "Share this article on LinkedIn with a short intro: https://..."


Before you start

You need three things installed on your computer:

  1. Node.js (v18 or later) — download here

  2. Claude Desktopdownload here

  3. A LinkedIn access token (explained in Step 2 below)


Step 1 — Download and build the server

Open your Terminal and run these commands one by one:

git clone https://github.com/abhineet34/linkedin-mcp-server.git
cd linkedin-mcp-server
npm install
npm run build

When it finishes, you'll have a dist/ folder. That's the built server.

Note down the full path to this folder — you'll need it in Step 3. To get it, run:

pwd

It will print something like /Users/yourname/linkedin-mcp-server. Remember this.


Step 2 — Get a LinkedIn Access Token

This is the trickiest part. LinkedIn's developer portal has some quirks — follow these steps in order and you'll be fine.

2a. Create a LinkedIn Company Page (required, even for personal use)

LinkedIn forces every developer app to be linked to a Company Page — a personal profile URL will not work, and the "Member Data Portability" default page blocks access to all useful products. So you must create a real Company Page first.

  1. Go to linkedin.com/company/setup/new

  2. Choose Company

  3. Fill in:

    • Name — your name, brand, or anything (e.g. "Your Name", "Yourname Dev")

    • LinkedIn public URL — auto-fills from the name

    • Industry — pick Software Development (or whatever fits your actual work)

    • Organization size0–1 employees

    • Organization typeSelf-employed

    • Logo — optional, any image

  4. Check the verification box and click Create page

The page can stay empty — it just needs to exist.

2b. Create the developer app

  1. Go to LinkedIn Developer Portal and sign in

  2. Click Create app

    • App name — anything (e.g. "My MCP")

    • LinkedIn Page — search for the page you just created and select it (don't paste a URL)

    • App logo — any image

    • Accept the legal agreement, click Create app

2c. Add required Products to the app

This is the step most people miss. Adding scopes alone is not enough — you also have to add the Products that provide those scopes.

  1. Open your app and go to the Products tab

  2. Click Request access on these two products:

    • Sign In with LinkedIn using OpenID Connect — provides openid, profile, email

    • Share on LinkedIn — provides w_member_social

  3. Both are auto-approved instantly (no waiting). Refresh the page — they should appear under "Added products"

If "Request access" is grayed out with a tooltip about Member Data Portability, you skipped Step 2a. Create a real Company Page, then create a new app linked to it (the old app cannot be fixed).

2d. Add a redirect URL

  1. Go to the Auth tab of your app

  2. Find "Authorized redirect URLs for your app" and click the pencil icon

  3. Add this URL exactly:

    https://www.linkedin.com/developers/tools/oauth/redirect
  4. Save

This is LinkedIn's own redirect URL — required for the token generator to work.

2e. Generate the access token

  1. Go to linkedin.com/developers/tools/oauth/token-generator

  2. Select your app from the dropdown

  3. Check all four scopes:

    • openid

    • profile

    • email

    • w_member_social

  4. Click Request access token

  5. LinkedIn will pop up an authorization screen — click Allow

  6. You'll see a long token starting with AQX...copy it now (you only see it once)

Your token expires after 60 days. When it stops working, come back to this step and generate a new one.


Step 3 — Connect to Claude Desktop

  1. Open Claude Desktop

  2. Go to Settings → Developer → Edit Config

    This opens a file called claude_desktop_config.json. Add the following inside it (replace the placeholder values):

{
  "mcpServers": {
    "linkedin": {
      "command": "node",
      "args": ["/Users/yourname/linkedin-mcp-server/dist/index.js"],
      "env": {
        "LINKEDIN_ACCESS_TOKEN": "paste-your-token-here"
      }
    }
  }
}
  • Replace /Users/yourname/linkedin-mcp-server with the path you noted in Step 1

  • Replace paste-your-token-here with the token from Step 2

  1. Save the file and restart Claude Desktop


Step 4 — Test it

In Claude Desktop, try:

"What's my LinkedIn profile?"

Claude should respond with your name, email, and a long ID starting with urn:li:person:.... If it does — you're all set!

💡 Save your URN. The response includes something like urn:li:person:izbpuvq9Vz. This is your unique LinkedIn ID — Claude needs it as the author_urn when creating posts. You can just ask Claude "remember my LinkedIn URN" or copy it somewhere safe.


Example things you can ask Claude

Once connected, just talk to Claude naturally:

  • "Post on LinkedIn: Excited to share my new project!"

  • "Create a LinkedIn post sharing this article: https://..."

  • "Delete my last LinkedIn post"

  • "How many followers does the Microsoft LinkedIn page have?"

  • "Look up the LinkedIn page for OpenAI"


Troubleshooting

LinkedIn rejects my personal profile URL when creating an app

  • LinkedIn only accepts Company Page URLs, not personal profile URLs (/in/...)

  • Go to Step 2a and create a Company Page first — your "company" can be just your name

"Request access" buttons are grayed out on the Products tab

  • This happens if you selected "Member Data Portability (Member-only default Company Page)" when creating the app

  • That default page locks all products. You need to create a real Company Page (Step 2a) and then create a brand new app linked to it — the existing app can't be fixed

Token generator says "no scopes available"

  • You skipped Step 2c. Go to your app's Products tab and add "Sign In with LinkedIn using OpenID Connect" and "Share on LinkedIn"

  • Wait a minute, refresh, then try the token generator again

"redirect_uri does not match" error in the token generator

  • You skipped Step 2d. Go to the Auth tab and add https://www.linkedin.com/developers/tools/oauth/redirect as an authorized redirect URL

Claude says it can't find the LinkedIn tool

  • Make sure you restarted Claude Desktop completely after editing the config file (Quit and reopen, not just close the window)

  • Double-check the file path in the config points to dist/index.js and the file actually exists at that path

  • Run the path in Terminal with ls <path> to confirm

"Unauthorized" or 401 error

  • Your access token may have expired (they last 60 days)

  • Go back to Step 2e and generate a new one, then update the config file and restart Claude Desktop

"Permission denied" or 403 error

  • The action requires a scope you didn't include

  • For posting, make sure all four scopes were checked in Step 2e

  • Some tools (like reading other people's posts) require LinkedIn-approved scopes that aren't available to all developers

Node.js not found


Available Tools

✅ Verified working with self-serve scopes

These tools work with the standard scopes anyone can grant themselves (openid, profile, email, w_member_social) and have been tested end-to-end:

Tool

Description

Required scope

linkedin_get_profile

Get your LinkedIn profile (name, email, photo, URN)

openid profile email

linkedin_create_post

Create a post (text, image, or article/link)

w_member_social

linkedin_update_post

Edit a post's text or visibility

w_member_social

linkedin_delete_post

Delete a post

w_member_social

linkedin_upload_image

Upload an image to use in a post

w_member_social

⚠️ Approval-gated (not tested with self-serve scopes)

These tools require LinkedIn-approved scopes that are not available to all developers. They're included in the codebase for users who have partner-level access (e.g., approved Marketing Developer Platform, Community Management API, or Page Admin programs), but they have not been verified end-to-end with the standard self-serve flow described in this README.

Tool

Description

Required scope

LinkedIn approval needed?

linkedin_get_post

Get a post by its URN

r_member_social or r_organization_social

Yes

linkedin_list_posts

List posts by a member or company

r_member_social or r_organization_social

Yes

linkedin_get_organization

Look up a company page

rw_organization_admin

Yes (Page admin role)

linkedin_get_org_follower_count

Get a company page's follower count

rw_organization_admin

Yes (Page admin role)

If you have approved access to these scopes and successfully use any of these tools, please open an issue or PR — we'd love to confirm them as verified and document any quirks.


🛠️ Tech stack

  • TypeScript — fully typed, strict mode

  • @modelcontextprotocol/sdk — official MCP SDK

  • Zod — runtime schema validation

  • Axios — HTTP client

  • LinkedIn REST API v202604 (configurable via LINKEDIN_API_VERSION env var; v2 fallback used only for OIDC userinfo)

The codebase is intentionally small and easy to extend — one file per tool domain (profile, posts, media, organizations).


🤝 Contributing

Issues and PRs are welcome! If you have an idea, find a bug, or want to add a new LinkedIn API tool, open an issue first to discuss.

Ideas for contributions:

  • Add tools for LinkedIn comments and reactions

  • Add scheduled post support

  • Add carousel post support (multi-image)

  • Improve error messages with more context

  • Add a CLI mode for direct usage outside MCP clients



⚠️ Disclaimer

This is an unofficial integration. It is not affiliated with, endorsed by, or sponsored by LinkedIn Corporation. Use responsibly and within LinkedIn's API terms of service.


⭐ Star the repo

If this saved you time, star the repo — it helps other developers find it.


License

MIT © Abhineet Pratap Singh

Available Tools

9 tools
linkedin_create_postCreate LinkedIn PostA

Create a new post on LinkedIn on behalf of a member or organization.

Supports text-only posts, image posts (after uploading via linkedin_upload_image), and article/link posts. Post length is capped at 3000 characters.

Requires scope: w_member_social (for member posts) or w_organization_social (for org posts)

Args:

  • author_urn (string): URN of the post author. Format: 'urn:li:person:{id}' for members. Get your ID from linkedin_get_profile's 'sub' field.

  • text (string): Post text (1–3000 characters, required)

  • visibility ('PUBLIC' | 'CONNECTIONS' | 'LOGGED_IN'): Who can see the post (default: 'PUBLIC')

  • image_asset_urn (string, optional): Asset URN from linkedin_upload_image

  • article_url (string, optional): URL to share as a link post

  • article_title (string, optional): Link preview title (used with article_url)

  • article_description (string, optional): Link preview description (used with article_url)

Returns: The URN of the newly created post (e.g., 'urn:li:share:7123456789')

Examples:

  • Text post: { author_urn: "urn:li:person:abc", text: "Hello LinkedIn!" }

  • Image post: { author_urn: "urn:li:person:abc", text: "Check this out", image_asset_urn: "urn:li:digitalmediaAsset:..." }

  • Article share: { author_urn: "urn:li:person:abc", text: "Great read", article_url: "https://..." }

Error Handling:

  • 403 if w_member_social scope is missing

  • 400 if text exceeds 3000 chars or author URN is invalid

ParametersJSON Schema
NameRequiredDescriptionDefault
author_urnYesURN of the author. Use 'urn:li:person:{id}' for member posts. Get your person ID from linkedin_get_profile (the 'sub' field).
textYesPost text content (max 3000 characters)
visibilityNoPost visibility: PUBLIC (anyone), CONNECTIONS (1st-degree connections), LOGGED_IN (LinkedIn members)PUBLIC
image_asset_urnNoAsset URN of an uploaded image to attach (from linkedin_upload_image). Optional. Omit for text-only posts.
article_urlNoURL of an article to share as a link post. Optional.
article_titleNoTitle for the article link preview. Used only when article_url is provided.
article_descriptionNoDescription for the article link preview. Used only when article_url is provided.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Discloses post creation behavior, character limit (3000), required scopes (w_member_social, w_organization_social), error handling (403, 400), and return type (post URN). Annotations indicate it's not read-only or destructive, and description aligns with no contradictions.

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?

Well-structured with front-loaded purpose, followed by supported types, scope, args, return, examples, and errors. Each section is concise and informative, no unnecessary repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Comprehensive for a 7-param tool with no output schema: explains all parameters, return value, error cases, prerequisites, and includes examples. Missing no critical behavioral or usage details.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Adds significant value beyond schema: explains author_urn format and source, visibility enum meanings, optional parameters' conditions (e.g., article_url requires article_title/article_description), and provides examples. Schema coverage is 100% but description elaborates further.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states it creates a new LinkedIn post for a member or organization, specifying supported post types (text, image, article). Distinguishes from sibling tools like linkedin_delete_post, linkedin_update_post, and linkedin_upload_image.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides context on when to use this tool (creating posts) and mentions prerequisites like uploading images via linkedin_upload_image and required scopes. Does not explicitly contrast with sibling tools like update or delete, but the examples and structure implicitly guide usage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

linkedin_delete_postDelete LinkedIn PostA
Destructive

Permanently delete a LinkedIn post by its URN.

Only the author of the post can delete it. This action cannot be undone.

Requires scope: w_member_social (member posts) or w_organization_social (org posts)

Args:

  • post_urn (string): URN of the post to delete (e.g., 'urn:li:share:7123456789')

Returns: Confirmation message on success.

Error Handling:

  • 403 if you are not the author of the post

  • 404 if the post does not exist or is already deleted

ParametersJSON Schema
NameRequiredDescriptionDefault
post_urnYesURN of the post to delete (e.g., 'urn:li:share:7123456789')

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond annotations (destructiveHint=true), the description adds critical context: permanence, author-only restriction, error codes (403/404), and required scopes. This fully informs the agent of behavioral traits.

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?

The description is concise, using structured sections (Args, Returns, Error Handling) and front-loading key facts. Every sentence adds value without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple one-parameter tool with no output schema, the description fully covers purpose, preconditions, side effects, and error handling. It is contextually complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already covers post_urn with a description and example. The description's Args section repeats the same information, adding no new semantics beyond the schema. Schema coverage is 100%, so baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool permanently deletes a LinkedIn post by its URN, which is a specific verb and resource. It distinguishes itself from sibling tools like linkedin_update_post or linkedin_create_post by being the only delete operation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description specifies that only the author can delete, the action is irreversible, and requires specific OAuth scopes. While it does not explicitly mention alternatives, the destructive nature and unique purpose make usage clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

linkedin_get_organizationGet LinkedIn OrganizationA
Read-onlyIdempotent

Retrieve a LinkedIn organization (company) page by its numeric ID or vanity name.

Without admin access, returns public fields: id, localizedName, vanityName, localizedWebsite, primaryOrganizationType, locations, and logoV2. With admin access (rw_organization_admin scope), returns additional fields like description, industries, staffCountRange, foundedOn, and specialties.

Requires scope: rw_organization_admin

Args:

  • lookup_by ('id' | 'vanity_name'): How to identify the org (default: 'id')

  • organization_id (string): Numeric org ID — required when lookup_by='id'

  • vanity_name (string): URL slug — required when lookup_by='vanity_name' E.g., 'microsoft' for linkedin.com/company/microsoft

  • response_format ('markdown' | 'json'): Output format (default: 'markdown')

Returns: For JSON format: { "id": string, "localizedName": string, "vanityName": string, "localizedWebsite": string, "primaryOrganizationType": string, "locations": [...], // Additional fields if you have admin access }

Examples:

  • By ID: { lookup_by: "id", organization_id: "1441" } ← LinkedIn's own page

  • By vanity: { lookup_by: "vanity_name", vanity_name: "microsoft" }

Error Handling:

  • 403 if rw_organization_admin scope is missing

  • 404 if the organization ID or vanity name does not exist

ParametersJSON Schema
NameRequiredDescriptionDefault
lookup_byNoHow to look up the organization: by numeric 'id' or by 'vanity_name' (URL slug)id
organization_idNoNumeric organization ID (required when lookup_by='id'). Example: '1234567' from linkedin.com/company/1234567
vanity_nameNoOrganization vanity name — the slug in the LinkedIn URL. E.g., 'microsoft' for linkedin.com/company/microsoft (required when lookup_by='vanity_name')
response_formatNoOutput format: 'markdown' for human-readable or 'json' for machine-readablemarkdown

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond annotations (readOnlyHint, idempotentHint), the description discloses critical behavioral details: auth scope (rw_organization_admin), how public vs admin access differs, return fields, and error codes (403, 404). No contradiction with annotations.

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?

The description is well-structured with logical sections: summary, access-level details, Args, Returns, Examples, Error Handling. Every sentence adds necessary information without redundancy. It is front-loaded with the core purpose and then elaborates.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (4 params, no output schema), the description covers all aspects: parameter explanations, output format options, examples, error conditions, and scope requirements. It leaves no significant gap for an agent to misinvoke the tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although schema coverage is 100%, the description significantly adds value by explaining parameter dependencies (e.g., organization_id required when lookup_by='id'), providing concrete examples, default values, and contextual usage like 'vanity_name' from URL. This goes well beyond the schema definitions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Retrieve a LinkedIn organization (company) page by its numeric ID or vanity name.' It identifies the specific resource and action, and distinguishes from sibling tools like linkedin_create_post or linkedin_get_org_follower_count by focusing on retrieval of organization details.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear guidance on when to use the tool (to get organization info) and what to expect with different access levels. It mentions required scope and error handling, but could explicitly state not to use it for follower counts or posts, though sibling names make that implicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

linkedin_get_org_follower_countGet LinkedIn Organization Follower CountA
Read-onlyIdempotent

Get the total number of LinkedIn members following an organization page.

Requires scope: rw_organization_admin

Args:

  • organization_id (string): Numeric organization ID (e.g., '1234567')

Returns: { "organization_id": string, "follower_count": number }

Examples:

  • Use when: "How many followers does our company page have?"

  • Use when: "Compare follower counts across organizations"

Error Handling:

  • 403 if rw_organization_admin scope is missing or you are not an admin of the org

  • 404 if the organization ID does not exist

ParametersJSON Schema
NameRequiredDescriptionDefault
organization_idYesNumeric organization ID (e.g., '1234567')

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Discloses required scope (rw_organization_admin), error codes (403, 404), and follows annotations (readOnlyHint, idempotentHint). No contradictions; adds context beyond annotations.

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?

Description is well-structured with sections for introduction, scope, args, returns, examples, and error handling. Each sentence adds value, and the most critical information is front-loaded.

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?

Covers scope, parameters, return format, error codes, and usage examples. However, it omits potential details like rate limits or data freshness, but given the tool's simplicity, it is largely complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema covers the single parameter with full description. The description repeats the same information (e.g., 'Numeric organization ID') without adding new meaning or clarification beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it retrieves the follower count for a LinkedIn organization. The verb 'get' and resource 'follower count' are explicit, and it distinguishes itself from siblings (e.g., linkedin_get_organization) by focusing solely on followers.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides concrete usage examples and error handling scenarios. While it lacks explicit 'when not to use' guidance, the examples clearly illustrate appropriate contexts such as checking or comparing follower counts.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

linkedin_get_postGet LinkedIn PostA
Read-onlyIdempotent

Retrieve a LinkedIn post by its URN.

NOTE: Reading posts requires the r_member_social scope for member posts or r_organization_social for org posts. These scopes require LinkedIn approval and are not available to all developers. If you only have w_member_social, use linkedin_create_post and linkedin_list_posts instead.

Requires scope: r_member_social or r_organization_social

Args:

  • post_urn (string): Post URN (e.g., 'urn:li:share:7123456789')

  • response_format ('markdown' | 'json'): Output format (default: 'markdown')

Returns: For JSON format: { "id": string, // Post URN "author": string, // Author URN "commentary": string, // Post text "visibility": string, // PUBLIC | CONNECTIONS | LOGGED_IN "lifecycleState": string, // PUBLISHED | DRAFT | DELETED "createdAt": number, // Unix timestamp (ms) "lastModifiedAt": number, "content": object // Media/article content (if any) }

Error Handling:

  • 403 if r_member_social scope is not approved for your app

ParametersJSON Schema
NameRequiredDescriptionDefault
post_urnYesURN of the post to retrieve (e.g., 'urn:li:share:7123456789')
response_formatNoOutput format: 'markdown' for human-readable or 'json' for machine-readablemarkdown

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate read-only and idempotent behavior. The description adds valuable context: scope requirements, error cases (403), and the return structure. It fully discloses behavioral traits beyond what annotations provide.

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?

The description is well-structured with clear sections (purpose, scopes, args, returns, error handling). Each sentence adds value, though it is somewhat verbose. It is front-loaded and organized, earning a high score.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's two parameters, no output schema, and the need for special scopes, the description covers all necessary aspects: purpose, usage, parameters, return format, and error handling. It is complete for an AI agent to select and invoke the tool correctly.

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?

Schema coverage is 100%, providing baseline 3. The description adds meaning beyond the schema with concrete examples like 'urn:li:share:7123456789' and clarifies response_format as 'human-readable or machine-readable', justifying a higher score.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Retrieve a LinkedIn post by its URN.' This is a specific verb and resource, and it effectively distinguishes the tool from its siblings like linkedin_create_post and linkedin_list_posts.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly covers when to use the tool, required scopes, and provides an alternative: 'If you only have w_member_social, use linkedin_create_post and linkedin_list_posts instead.' It also includes error handling for 403.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

linkedin_get_profileGet LinkedIn ProfileA
Read-onlyIdempotent

Retrieve the authenticated LinkedIn member's profile information via the OIDC userinfo endpoint.

Returns the member's name, profile picture, email address, and locale.

Requires scopes: openid, profile, email

Args:

  • response_format ('markdown' | 'json'): Output format (default: 'markdown')

Returns: For JSON format: { "sub": string, // LinkedIn member URN (e.g., "urn:li:person:abc123") "name": string, // Full display name "given_name": string, // First name "family_name": string, // Last name "picture": string, // Profile picture URL (optional) "email": string, // Primary email address (optional) "email_verified": bool, // Whether email is verified (optional) "locale": { "country": string, // Country code "language": string // Language code } }

Examples:

  • Use when: "Who am I logged in as?" → call with default params

  • Use when: "Get my LinkedIn email" → call with response_format='json', read email field

  • Don't use when: You need to look up someone else's profile (LinkedIn doesn't expose that via standard API)

Error Handling:

  • Returns auth error if LINKEDIN_ACCESS_TOKEN is missing or expired

  • Returns permission error if 'profile' scope is not granted

ParametersJSON Schema
NameRequiredDescriptionDefault
response_formatNoOutput format: 'markdown' for human-readable or 'json' for machine-readablemarkdown

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond annotations (readOnlyHint, idempotentHint, openWorldHint), the description details the authentication requirements (scopes), error cases (missing token, permission issues), and the exact structure of the response. No contradictions with annotations.

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?

The description is well-structured with clear sections (Args, Returns, Examples, Error Handling) and front-loaded with the core purpose. It is slightly verbose but every section adds value, making it efficient for an agent.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the simple parameter set, the presence of annotations, and no output schema, the description is remarkably complete. It includes the endpoint, scopes, all return fields, error handling, and example usage, leaving no critical gaps.

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?

Schema coverage is 100%, and the description adds context by explaining the default value and providing usage examples for both formats. While the schema already defines the parameter, the description enhances it with practical guidance.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool retrieves the authenticated LinkedIn member's profile information via the OIDC userinfo endpoint, listing specific fields returned. It is easily distinguished from sibling tools like linkedin_create_post or linkedin_get_organization, which have different purposes.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use examples are provided (e.g., 'Who am I logged in as?'), a 'Don't use when' exclusion for looking up others' profiles, and required OAuth scopes are listed. This gives clear guidance on appropriate usage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

linkedin_list_postsList LinkedIn PostsA
Read-onlyIdempotent

List posts by a LinkedIn member or organization.

NOTE: Listing posts requires the r_member_social scope (member) or r_organization_social scope (org). These are approval-gated scopes. For org posts, you also need to be an admin of the organization.

Requires scope: r_member_social or r_organization_social

Args:

  • author_urn (string): Author URN — 'urn:li:person:{id}' or 'urn:li:organization:{id}'

  • limit (number): Max posts to return, 1–50 (default: 20)

  • offset (number): Posts to skip for pagination (default: 0)

  • response_format ('markdown' | 'json'): Output format (default: 'markdown')

Returns: { "total": number, "count": number, "offset": number, "items": [Post], "has_more": boolean, "next_offset": number }

Error Handling:

  • 403 if r_member_social / r_organization_social scope is missing or not approved

ParametersJSON Schema
NameRequiredDescriptionDefault
author_urnYesURN of the author whose posts to list. Use 'urn:li:person:{id}' for members or 'urn:li:organization:{id}' for companies.
limitNoMaximum number of posts to return (1–50, default: 20)
offsetNoNumber of posts to skip for pagination (default: 0)
response_formatNoOutput format: 'markdown' for human-readable or 'json' for machine-readablemarkdown

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate read-only, idempotent, not destructive. The description adds substantial value: scope requirements, error handling (403), return structure with pagination fields (total, count, offset, has_more, next_offset), and output format options.

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?

The description is well-organized into sections (NOTE, Requires scope, Args, Returns, Error Handling). Each section is concise and informative without being bloated. A bit longer than ideal but well-structured.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with 4 parameters, no output schema, and no nested objects, the description covers all necessary aspects: prerequisites, parameter details, return format with pagination, and error handling. It is complete and self-contained.

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?

Schema description coverage is 100%, so baseline is 3. The description adds contextual meaning beyond schema: it clarifies scope dependency for author_urn, documents default values and constraints for limit/offset, and explains response_format purpose.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'List posts by a LinkedIn member or organization' — a specific verb and resource. It distinguishes from sibling tools like create, delete, get, and update posts by its listing function.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly mentions required scopes (r_member_social, r_organization_social) and admin status for org posts. It does not discuss when not to use, but the prerequisites are clear and helpful.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

linkedin_update_postUpdate LinkedIn PostA

Update the text or visibility of an existing LinkedIn post.

Only the author of the post can update it. Note that LinkedIn only allows updating the commentary (text) and visibility after posting — content attachments (images, articles) cannot be changed post-publish.

Requires scope: w_member_social (member posts) or w_organization_social (org posts)

Args:

  • post_urn (string): URN of the post to update (e.g., 'urn:li:share:7123456789')

  • text (string): New text content (1–3000 characters)

  • visibility ('PUBLIC' | 'CONNECTIONS' | 'LOGGED_IN', optional): New visibility setting

Returns: Confirmation message on success.

Error Handling:

  • 403 if you are not the author of the post

  • 404 if the post does not exist

ParametersJSON Schema
NameRequiredDescriptionDefault
post_urnYesURN of the post to update (e.g., 'urn:li:share:7123456789')
textYesNew text content for the post (max 3000 characters)
visibilityNoUpdated visibility. Omit to keep the existing value.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Adds significant context beyond annotations: author constraint, non-modifiable fields, scope requirements, error codes. No contradiction with readOnlyHint=false.

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?

Well-structured with sections (description, requirements, args, returns, errors). Slightly long but each sentence adds value. Could be slightly more concise.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 3 params and no output schema, description covers inputs, errors, permissions, and success response. Leaves no critical gaps for agent invocation.

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?

Schema coverage is 100%, baseline 3. Description adds value by explaining post_urn format, text length, and visibility options including default behavior when omitted.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states it updates text or visibility of an existing post. Distinguishes from siblings like create_post and delete_post through the verb 'update' and specific resource.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states only the author can update, and notes limitations on attachments. Mentions required scopes. Could add direct comparison to siblings like 'use this instead of deleting and re-creating'.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

linkedin_upload_imageUpload LinkedIn ImageA

Upload an image to LinkedIn and get an image URN to use when creating an image post.

This is a two-step process handled automatically:

  1. Initialize the upload via /rest/images to get a pre-signed upload URL

  2. PUT the image binary to that URL

After upload, use the returned image URN as image_asset_urn in linkedin_create_post.

Requires scope: w_member_social

Args:

  • author_urn (string): Owner URN — 'urn:li:person:{id}' from linkedin_get_profile

  • image_base64 (string): Base64-encoded image file contents

  • mime_type ('image/jpeg' | 'image/png' | 'image/gif'): Image MIME type (default: image/jpeg)

Returns: { "asset_urn": string, // e.g., "urn:li:image:C5622AQH..." "upload_url": string // The URL that was used for upload (informational) }

Examples:

  • Use when: "Post an image to LinkedIn" → upload first, then create_post with asset URN

  • Don't use when: You only want a text post (image upload not needed)

Error Handling:

  • 403 if w_member_social scope is not granted

  • 400 if the author_urn format is invalid

ParametersJSON Schema
NameRequiredDescriptionDefault
author_urnYesURN of the owner of this asset. Use 'urn:li:person:{id}' for members. Get your ID from linkedin_get_profile's 'sub' field.
image_base64YesBase64-encoded image data (JPEG or PNG)
mime_typeNoMIME type of the image (default: image/jpeg)image/jpeg

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Discloses the upload process (two steps), required scope w_member_scope, and error handling (403, 400). Adds behavioral context beyond annotations (which only indicate non-readonly, non-destructive, open-world). No contradiction.

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?

Well-structured with clear sections (description, process, args, returns, examples, errors). Every sentence is informative and earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Comprehensive coverage of return values, error scenarios, and prerequisites despite no output schema. The two-step upload complexity is fully described, making it complete for agent invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 100% schema coverage, description adds value by specifying author_urn format from linkedin_get_profile, base64 encoding, and default mime_type. Examples and return shape further clarify parameter usage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states the tool uploads an image to LinkedIn and returns an image URN for use in creating an image post. Distinguishes from sibling linkedin_create_post by explaining it's a prerequisite step.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly provides when-to-use ('Post an image to LinkedIn') and when-not-to-use ('only a text post'), names the alternative, and describes the two-step process handled automatically.

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. 9 tool updatesv0.1.0
    • First observedlinkedin_create_post
    • First observedlinkedin_delete_post
    • First observedlinkedin_get_org_follower_count
    • First observedlinkedin_get_organization
    • First observedlinkedin_get_post
    • First observedlinkedin_get_profile
    • First observedlinkedin_list_posts
    • First observedlinkedin_update_post
    • First observedlinkedin_upload_image

TDQS

A4.7/5.0

Scored across 9 tools

Disambiguation5/5

Each tool targets a distinct action: creating, updating, deleting, listing, or retrieving posts; retrieving profile or organization data; uploading images. No two tools have overlapping purposes, and descriptions clearly differentiate them.

Naming Consistency5/5

All tools follow a 'linkedin_verb_noun' pattern with consistent snake_case (e.g., create_post, get_organization, upload_image). No mixed conventions or ambiguous verbs.

Tool Count5/5

9 tools cover the core use cases for LinkedIn post management and organization information without being excessive. The count is well-scoped for the server's purpose.

Completeness4/5

CRUD operations for posts are fully covered (create, read, update, delete, list), plus profile retrieval, org info, and image upload. Minor gaps exist (e.g., no comment or search functionality), but the surface is solid for the intended domain.

Maintenance

ActivityInactive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers