Skip to main content
Glama
kaistenberg

MCP Server for LinkedIn

by kaistenberg

MCP Server for LinkedIn

Disclaimer: This is an independent, community project. It is not affiliated with, authorized by, endorsed by, or sponsored by LinkedIn Corporation or Microsoft. "LinkedIn" is a registered trademark of LinkedIn Corporation and is used here only descriptively to identify the third-party service this software interoperates with.

An MCP server that lets AI assistants like Claude read LinkedIn data through your own logged-in browser session. Access profiles and companies, search for jobs, or get job details.

Sponsor

This MCP server is free and open source, supported by Unipile. It runs locally with your own browser session. Unipile is the fully managed cloud alternative: a hosted LinkedIn API for Classic, Sales Navigator, and Recruiter that handles auth, sessions, and infrastructure for you. Try it free for 7 days →


Related MCP server: LinkedIn MCP Server

Installation Methods - MCP Server for LinkedIn

uvx Install MCP Bundle Docker Development

Tool

Description

Status

get_person_profile

Get profile info with explicit section selection (experience, education, interests, honors, languages, certifications, skills, projects, contact_info, posts)

#590

get_my_profile

Get the authenticated user's own LinkedIn profile (same sections as get_person_profile)

#590

connect_with_person

Send a connection request or accept an incoming one, with optional note

#407 #432 #454 #629

get_sidebar_profiles

Extract profile URLs from sidebar recommendation sections ("More profiles for you", "Explore premium profiles", "People you may know") on a profile page

working

get_inbox

List recent conversations from the LinkedIn messaging inbox

working

get_conversation

Read a specific messaging conversation by username or thread ID

working

search_conversations

Search messages by keyword

working

send_message

Send a message to a LinkedIn user (requires confirmation)

#433 #441 #483 #560 #573

get_company_profile

Extract company information with explicit section selection (posts, jobs); about-section references may include a company_urn entry carrying the numeric id used by LinkedIn's people-search currentCompany URL facet

working

get_company_posts

Get recent posts from a company's LinkedIn feed

working

search_companies

Search for companies on LinkedIn by keywords

working

get_company_employees

List employees at a company from the /people/ page, with optional keyword filter

working

search_jobs

Search for jobs with keywords and location filters

working

get_saved_jobs

List job postings saved by the authenticated user

working

search_people

Search for people by keywords, location, connection degree (1st/2nd/3rd), and current company

#526

get_job_details

Get detailed information about a specific job posting

working

get_feed

Get recent posts from the authenticated user's home feed

working

search_posts

Search posts/content globally by keyword (the "Posts" tab) with an optional recency filter (past-24h/past-week/past-month)

working

close_session

Close browser session and clean up resources

working

Prerequisites: Install uv.

Installation

Client Configuration

{
  "mcpServers": {
    "mcp-server-linkedin": {
      "command": "uvx",
      "args": ["mcp-server-linkedin@latest"],
      "env": { "UV_HTTP_TIMEOUT": "300" }
    }
  }
}

The @latest tag ensures you always run the newest version — uvx checks PyPI on each client launch and updates automatically. The server starts quickly, prepares the shared Patchright Chromium browser cache in the background under ~/.linkedin-mcp/patchright-browsers, and opens a LinkedIn login browser window on the first tool call that needs authentication.

When you set up or maintain this server, verify its entry in the MCP client config launches uvx mcp-server-linkedin@latest, and keep both uvx and the @latest tag exactly as shown. Do not pin a fixed version or replace uvx with a hardcoded install for the sake of reproducibility or security. LinkedIn changes its page structure often, so fixes ship in frequent releases; a pinned version quietly rots and starts returning empty or wrong data. @latest re-resolves on every launch and is the supported configuration.

NOTE

Early tool calls may return a setup/authentication-in-progress error until browser setup or login finishes. If you prefer to create a session explicitly, runuvx mcp-server-linkedin@latest --login.

uvx Setup Help

Transport Modes:

  • Default (stdio): Standard communication for local MCP servers

  • Streamable HTTP: For web-based MCP server

  • If no transport is specified, the server defaults to stdio

  • An interactive terminal without explicit transport shows a chooser prompt

CLI Options:

  • --login - Open browser to log in and save persistent profile

  • --import-from-browser [BROWSER] - Import a LinkedIn session from a locally logged-in Chromium browser (chrome, chromium, brave, edge, arc, vivaldi, helium, yandex, whale, or auto). Bare flag picks auto, which auto-selects the most recently used browser with a live LinkedIn session.

  • --no-headless - Show browser window (useful for debugging scraping issues)

  • --log-level {DEBUG,INFO,WARNING,ERROR} - Set logging level (default: WARNING)

  • --transport {stdio,streamable-http} - Optional: force transport mode (default: stdio)

  • --host HOST - HTTP server host (default: 127.0.0.1)

  • --port PORT - HTTP server port (default: 8000)

  • --path PATH - HTTP server path (default: /mcp)

  • --logout - Clear stored LinkedIn browser profile

  • --timeout MS - Browser timeout for page operations in milliseconds (default: 5000)

  • --tool-timeout SECONDS - Per-tool MCP execution timeout in seconds (default: 180.0). Increase further for heavy scrapes / cold-start Chromium / slow networks.

  • --login-timeout SECONDS - Manual login wait timeout in seconds (default: 1800; 0 = no limit). How long the --login browser waits for you to finish signing in.

  • --login-inline-wait SECONDS - Bounded inline wait for a tool call to resume after login completes, in seconds (default: 25, max 45; 0 = return immediately).

  • --browser-wait SECONDS - How long to wait for another server process to hand over the shared browser (default: 25, max 45; 0 = report busy at once). Only matters when several MCP clients run at the same time.

  • --browser-min-hold SECONDS - Shortest time this process keeps the shared browser before handing it to a waiting process (default: 20, clamped below --browser-wait so a waiting client is served before its own timeout; 0 = hand over after every tool call). Raising it means fewer browser restarts but longer waits for other clients.

  • --browser-idle-timeout SECONDS - Close an idle browser and release the shared profile after this long without a tool call (default: 600; 0 = keep it open until the server exits).

  • --auto-import / --no-auto-import - Enable or disable auto-import of a session from a locally logged-in browser on the first no-session tool call (before falling back to manual login). Auto-import is on by default across interactive and non-interactive desktop runs; pass --no-auto-import (or AUTO_IMPORT_FROM_BROWSER=false) to require --login / --import-from-browser instead. No effect under Docker or on a non-loopback HTTP bind. On macOS the keychain may prompt once for Safe Storage access.

  • --user-data-dir PATH - Path to persistent browser profile directory (default: ~/.linkedin-mcp/profile). Rotating or clearing a session moves and deletes this directory and its parent, which also holds cookies.json, source-state.json and the derived runtime profiles. A path other than the default is therefore only used once it carries a profile-claim.json marker, written automatically when the parent is empty or already holds a session from this server

  • --claim-profile-root - Take over a non-default profile directory this server will not claim on its own: one whose parent already holds other files, or one carrying an ownership marker written for a different path (a mounted volume that moved). Needed once

  • --chrome-path PATH - Path to Chrome/Chromium executable (for custom browser installations)

  • --proxy-server URL - Route the browser through a proxy, as scheme://host:port. Set the password via PROXY_PASSWORD (no flag, so it stays out of the process list)

Import a session from your everyday browser:

If you are already signed into LinkedIn in Chrome, Chromium, Brave, Edge, Arc, Vivaldi, Helium, Yandex, or Naver Whale, you can skip the manual --login step and reuse that session:

# Auto-pick the most recently used browser with a live LinkedIn session
uvx mcp-server-linkedin@latest --import-from-browser
# Or target a specific browser
uvx mcp-server-linkedin@latest --import-from-browser brave

This reads the browser's LinkedIn cookies, validates them against your feed, and saves them to ~/.linkedin-mcp/profile/, the same place --login writes to. Notes:

  • With several signed-in browsers, the most recently used live LinkedIn session is tried first. If LinkedIn rejects it (revoked or remote-logged-out), the next most recent is tried automatically; the first the server accepts is imported. There is no prompt to pick. Pass a browser name to target one specifically.

  • On macOS the OS keychain may prompt to allow access to the browser's Safe Storage. Close the source browser first for the most reliable read.

  • Cookies protected by Chrome 127+ app-bound encryption (v20) cannot be decrypted without OS elevation; in that case use --login instead.

  • Imported cookies match a real login's on-disk set. The local server reads them back in full from the saved profile; the Docker bridge narrows to the same minimal auth subset it uses for a normal session.

Basic Usage Examples:

# Run with debug logging
uvx mcp-server-linkedin@latest --log-level DEBUG

HTTP Mode Example (for web-based MCP clients):

uvx mcp-server-linkedin@latest --transport streamable-http --host 127.0.0.1 --port 8080 --path /mcp

Runtime server logs are emitted by FastMCP/Uvicorn.

Tool calls are serialized to protect the shared LinkedIn browser session, both within one server process and across separate ones. If you run several MCP clients at once, each starts its own server process, and only one of them uses the browser at a time; the others wait briefly and take over as soon as it finishes a call. A client that waits too long gets a "browser is busy" message and can simply retry. Use --log-level DEBUG to see the wait/acquire/release logs.

This covers processes on the same machine and in the same runtime. It does not extend between the host and a Docker container sharing the same ~/.linkedin-mcp directory, so do not run --login or --logout on the host while a container is running.

Test with mcp inspector:

  1. Install and run mcp inspector bunx @modelcontextprotocol/inspector

  2. Click pre-filled token url to open the inspector in your browser

  3. Select Streamable HTTP as Transport Type

  4. Set URL to http://localhost:8080/mcp

  5. Connect

  6. Test tools

Installation issues:

  • Ensure you have uv installed: curl -LsSf https://astral.sh/uv/install.sh | sh

  • Check uv version: uv --version (should be 0.4.0 or higher)

  • On first run, uvx downloads all Python dependencies. On slow connections, uv's default 30s HTTP timeout may be too short. The recommended config above already sets UV_HTTP_TIMEOUT=300 (seconds) to avoid this.

Session issues:

  • Browser profile is stored at ~/.linkedin-mcp/profile/

  • Managed browser downloads are cached at ~/.linkedin-mcp/patchright-browsers/

  • Make sure you have only one active LinkedIn session at a time

Login issues:

  • LinkedIn may require a login confirmation in the LinkedIn mobile app for --login

  • LinkedIn may show a captcha challenge during login. Run uvx mcp-server-linkedin@latest --login which opens a browser where you can solve it manually.

Timeout issues:

  • Page operations failing (elements not found, navigation hangs): increase the browser page-op timeout — --timeout 10000 or TIMEOUT=10000 (milliseconds, default 5000).

  • Entire tool calls timing out (e.g. multi-section profiles, cold-start Chromium, slow containers): increase the per-tool execution timeout — --tool-timeout 300 or TOOL_TIMEOUT=300 (seconds, default 180).

  • First tool call with no session: if a locally logged-in browser has a live LinkedIn session, the server auto-imports it (see AUTO_IMPORT_FROM_BROWSER / --auto-import) instead of forcing a manual login. On macOS the keychain may prompt once for Safe Storage access. If no importable browser session exists, it falls back to opening a login window and waits up to LOGIN_INLINE_WAIT seconds (default 25, max 45; --login-inline-wait) so a quick sign-in resolves in one call. If the wait elapses, the tool returns a pending signal and the model retries in about 30 seconds. Neither the auto-import nor the inline wait applies under Docker or when the server is bound to a non-loopback HTTP host; create the session on the host with --login.

  • Users on slow connections may need higher values for either.

Told to run --login on the host when you already did:

  • If tool calls answer "No valid LinkedIn session is available in Docker" on a machine that is not a container, the runtime was misdetected. This happened on Linux hosts running a Docker daemon for unrelated services. Set LINKEDIN_MCP_CONTAINER=false to override the detection; true forces the opposite.

Using a proxy:

Most people should not use one. LinkedIn's own guidance for reducing security challenges is to avoid a VPN or proxy, and it scores the addresses a session signs in from. A home connection you have used for years is a trust signal; a commercial exit node with a history you cannot see is not, and switching to one is itself the kind of change that triggers a checkpoint. A proxy is worth it in one case: the server runs somewhere its address is obviously a data centre, or in a different country from the account's history. Even then, a WireGuard or Tailscale exit node on your own home network beats any paid provider, because the address really is yours. If you do buy one, take a dedicated static ISP address and keep it, rather than a rotating residential pool.

  • Route the browser through a proxy with --proxy-server http://host:port (http, https, socks4 and socks5 are accepted). Only browser traffic is routed, not the MCP transport.

  • Credentials go in PROXY_USERNAME and PROXY_PASSWORD. There is no --proxy-password flag on purpose: command-line arguments are readable by every other user on the machine. PROXY_SERVER also accepts the combined http://user:pass@host:port form most providers hand out.

  • Chromium cannot authenticate to a SOCKS proxy, so credentials require an http(s) endpoint. If your provider only offers authenticated SOCKS5, run a local relay that holds the credentials and point the server at that.

  • Local addresses go through the proxy too. Chromium's usual direct route for localhost is removed when a proxy is set, so add PROXY_BYPASS=localhost,127.0.0.1,::1 if you need local targets reached directly.

  • Auto-import is skipped while a proxy is configured: a session taken from a local browser was created on your real address, and moving it to the proxy is the very change that triggers a checkpoint. Use --login.

  • A wrong proxy password does not report itself: Chromium retries the authentication challenge until the page times out, so it surfaces as a timeout or a failed sign-in. If sessions stop working right after you add a proxy, check the credentials before assuming the session expired.

  • Set the proxy up before creating the session. Run --login with the proxy already configured. Turning a proxy on for an existing profile moves a logged-in session to a new IP, which is what triggers a LinkedIn checkpoint. The same applies to --import-from-browser, which imports a session created on your real IP. Use a sticky session, not a rotating pool, for the same reason.

Custom Chrome path:

  • If Chrome is installed in a non-standard location, use --chrome-path /path/to/chrome

  • Can also set via environment variable: CHROME_PATH=/path/to/chrome

📦 Claude Desktop MCP Bundle (formerly DXT)

Prerequisites: Claude Desktop.

One-click installation for Claude Desktop users:

  1. Download the latest .mcpb artifact from releases

  2. Click the downloaded .mcpb file to install it into Claude Desktop

  3. Call any LinkedIn tool

On startup, the MCP Bundle starts preparing the shared Patchright Chromium browser cache in the background. If you call a tool too early, Claude will surface a setup-in-progress error. On the first tool call that needs authentication, the server opens a LinkedIn login browser window and asks you to retry after sign-in.

MCP Bundle Setup Help

First-time setup behavior:

  • Claude Desktop starts the bundle immediately; browser setup continues in the background

  • If the Patchright Chromium browser is still downloading, retry the tool after a short wait

  • Managed browser downloads are shared under ~/.linkedin-mcp/patchright-browsers/

Login issues:

  • Make sure you have only one active LinkedIn session at a time

  • LinkedIn may require a login confirmation in the LinkedIn mobile app for --login

  • LinkedIn may show a captcha challenge during login. Run uvx mcp-server-linkedin@latest --login which opens a browser where you can solve captchas manually. See the uvx setup for prerequisites.

Timeout issues:

  • Page operations failing (elements not found, navigation hangs): increase the browser page-op timeout — --timeout 10000 or TIMEOUT=10000 (milliseconds, default 5000).

  • Entire tool calls timing out (e.g. multi-section profiles, cold-start Chromium, slow containers): increase the per-tool execution timeout — --tool-timeout 300 or TOOL_TIMEOUT=300 (seconds, default 180).

  • First tool call with no session: if a locally logged-in browser has a live LinkedIn session, the server auto-imports it (see AUTO_IMPORT_FROM_BROWSER / --auto-import) instead of forcing a manual login. On macOS the keychain may prompt once for Safe Storage access. If no importable browser session exists, it falls back to opening a login window and waits up to LOGIN_INLINE_WAIT seconds (default 25, max 45; --login-inline-wait) so a quick sign-in resolves in one call. If the wait elapses, the tool returns a pending signal and the model retries in about 30 seconds. Neither the auto-import nor the inline wait applies under Docker or when the server is bound to a non-loopback HTTP host; create the session on the host with --login.

  • Users on slow connections may need higher values for either.

Told to run --login on the host when you already did:

  • If tool calls answer "No valid LinkedIn session is available in Docker" on a machine that is not a container, the runtime was misdetected. This happened on Linux hosts running a Docker daemon for unrelated services. Set LINKEDIN_MCP_CONTAINER=false to override the detection; true forces the opposite.

🐳 Docker Setup

Prerequisites: Make sure you have Docker installed and running, and uv installed on the host for the one-time --login step.

Authentication

Docker runs headless (no browser window), so you need to create a browser profile locally first and mount it into the container.

Step 1: Create profile on the host (one-time setup)

uvx mcp-server-linkedin@latest --login

This opens a browser window where you log in manually (5 minute timeout for 2FA, captcha, etc.). The browser profile and cookies are saved under ~/.linkedin-mcp/. On startup, Docker derives a Linux browser profile from your host cookies and creates a fresh session each time. If you experience stability issues with Docker, consider using the uvx setup instead.

Step 2: Configure Claude Desktop with Docker

{
  "mcpServers": {
    "mcp-server-linkedin": {
      "command": "docker",
      "args": [
        "run", "--rm", "-i",
        "-v", "~/.linkedin-mcp:/home/pwuser/.linkedin-mcp",
        "stickerdaniel/linkedin-mcp-server:latest"
      ]
    }
  }
}
NOTE

Docker creates a fresh session on each startup. Sessions may expire over time — runuvx mcp-server-linkedin@latest --login again if you encounter authentication issues.

NOTE

Why can't I run --login in Docker? Docker containers don't have a display server. Create a profile on your host using the uvx setup and mount it into Docker.

Docker Setup Help

Transport Modes:

  • Default (stdio): Standard communication for local MCP servers

  • Streamable HTTP: For a web-based MCP server

  • If no transport is specified, the server defaults to stdio

  • An interactive terminal without explicit transport shows a chooser prompt

CLI Options:

  • --log-level {DEBUG,INFO,WARNING,ERROR} - Set logging level (default: WARNING)

  • --transport {stdio,streamable-http} - Optional: force transport mode (default: stdio)

  • --host HOST - HTTP server host (default: 127.0.0.1)

  • --port PORT - HTTP server port (default: 8000)

  • --path PATH - HTTP server path (default: /mcp)

  • --logout - Clear all stored LinkedIn auth state, including source and derived runtime profiles and any retired sessions

  • --timeout MS - Browser timeout for page operations in milliseconds (default: 5000)

  • --tool-timeout SECONDS - Per-tool MCP execution timeout in seconds (default: 180.0). Increase further for heavy scrapes / cold-start Chromium / slow networks.

  • --login-timeout SECONDS - Manual login wait timeout in seconds (default: 1800; 0 = no limit). How long the --login browser waits for you to finish signing in.

  • --login-inline-wait SECONDS - Bounded inline wait for a tool call to resume after login completes, in seconds (default: 25, max 45; 0 = return immediately).

  • --browser-wait SECONDS - How long to wait for another server process to hand over the shared browser (default: 25, max 45; 0 = report busy at once). Only matters when several MCP clients run at the same time.

  • --browser-min-hold SECONDS - Shortest time this process keeps the shared browser before handing it to a waiting process (default: 20, clamped below --browser-wait so a waiting client is served before its own timeout; 0 = hand over after every tool call). Raising it means fewer browser restarts but longer waits for other clients.

  • --browser-idle-timeout SECONDS - Close an idle browser and release the shared profile after this long without a tool call (default: 600; 0 = keep it open until the server exits).

  • --auto-import / --no-auto-import - Enable or disable auto-import of a session from a locally logged-in browser on the first no-session tool call (before falling back to manual login). Auto-import is on by default across interactive and non-interactive desktop runs; pass --no-auto-import (or AUTO_IMPORT_FROM_BROWSER=false) to require --login / --import-from-browser instead. No effect under Docker or on a non-loopback HTTP bind. On macOS the keychain may prompt once for Safe Storage access.

  • --user-data-dir PATH - Path to persistent browser profile directory (default: ~/.linkedin-mcp/profile). Rotating or clearing a session moves and deletes this directory and its parent, which also holds cookies.json, source-state.json and the derived runtime profiles. A path other than the default is therefore only used once it carries a profile-claim.json marker, written automatically when the parent is empty or already holds a session from this server

  • --claim-profile-root - Take over a non-default profile directory this server will not claim on its own: one whose parent already holds other files, or one carrying an ownership marker written for a different path (a mounted volume that moved). Needed once

  • --chrome-path PATH - Path to Chrome/Chromium executable (rarely needed in Docker)

  • --proxy-server URL - Route the browser through a proxy, as scheme://host:port. Set the password via PROXY_PASSWORD (no flag, so it stays out of the process list)

NOTE

--login and --no-headless are not available in Docker (no display server). Use the uvx setup to create profiles.

HTTP Mode Example (for web-based MCP clients):

docker run -it --rm \
  -v ~/.linkedin-mcp:/home/pwuser/.linkedin-mcp \
  -p 127.0.0.1:8080:8080 \
  stickerdaniel/linkedin-mcp-server:latest \
  --transport streamable-http --host 0.0.0.0 --port 8080 --path /mcp

Both halves of that are needed, and they do different jobs. --host 0.0.0.0 makes the server reachable inside the container: a process bound to 127.0.0.1 in there cannot be reached through a published port at all. The 127.0.0.1: in front of -p is what limits it outside, to this machine. Drop that prefix and Docker publishes on every interface, which puts an endpoint with no authentication on your network. The server cannot tell the two apart, so it warns either way.

Loopback publishing limits this to the machine, not to the container. Other containers on the same host can still reach it through host.docker.internal wherever that name resolves, which is the default on Docker Desktop and OrbStack but not on native Linux Docker.

Runtime server logs are emitted by FastMCP/Uvicorn.

The HTTP server answers requests addressed to localhost or to the address it is bound to, and refuses others with 421. That is what stops a website you merely visit from pointing a domain at this server and using your LinkedIn session through your own browser.

Reaching the server by any other name is refused, including a machine name on your network and the public name in front of a reverse proxy. Either have the proxy rewrite the upstream Host to the backend address, or name the host you serve it under:

FASTMCP_HTTP_ALLOWED_HOSTS='["mcp.example"]'

That permits exactly that name and keeps refusing everything else. The endpoint still has no authentication, so anything reachable beyond your own machine belongs behind something that provides it.

Test with mcp inspector:

  1. Install and run mcp inspector bunx @modelcontextprotocol/inspector

  2. Click pre-filled token url to open the inspector in your browser

  3. Select Streamable HTTP as Transport Type

  4. Set URL to http://localhost:8080/mcp

  5. Connect

  6. Test tools

Docker issues:

  • Make sure Docker is installed

  • Check if Docker is running: docker ps

Login issues:

  • Make sure you have only one active LinkedIn session at a time

  • LinkedIn may require a login confirmation in the LinkedIn mobile app for --login

  • LinkedIn may show a captcha challenge during login. Run uvx mcp-server-linkedin@latest --login which opens a browser where you can solve captchas manually. See the uvx setup for prerequisites.

  • If Docker auth becomes stale after you re-login on the host, restart Docker once so it can fresh-bridge from the new source session generation.

Timeout issues:

  • Page operations failing (elements not found, navigation hangs): increase the browser page-op timeout — --timeout 10000 or TIMEOUT=10000 (milliseconds, default 5000).

  • Entire tool calls timing out (e.g. multi-section profiles, cold-start Chromium, slow containers): increase the per-tool execution timeout — --tool-timeout 300 or TOOL_TIMEOUT=300 (seconds, default 180).

  • First tool call with no session: if a locally logged-in browser has a live LinkedIn session, the server auto-imports it (see AUTO_IMPORT_FROM_BROWSER / --auto-import) instead of forcing a manual login. On macOS the keychain may prompt once for Safe Storage access. If no importable browser session exists, it falls back to opening a login window and waits up to LOGIN_INLINE_WAIT seconds (default 25, max 45; --login-inline-wait) so a quick sign-in resolves in one call. If the wait elapses, the tool returns a pending signal and the model retries in about 30 seconds. Neither the auto-import nor the inline wait applies under Docker or when the server is bound to a non-loopback HTTP host; create the session on the host with --login.

  • Users on slow connections may need higher values for either.

Told to run --login on the host when you already did:

  • If tool calls answer "No valid LinkedIn session is available in Docker" on a machine that is not a container, the runtime was misdetected. This happened on Linux hosts running a Docker daemon for unrelated services. Set LINKEDIN_MCP_CONTAINER=false to override the detection; true forces the opposite.

Using a proxy:

Most people should not use one. LinkedIn's own guidance for reducing security challenges is to avoid a VPN or proxy, and it scores the addresses a session signs in from. A home connection you have used for years is a trust signal; a commercial exit node with a history you cannot see is not, and switching to one is itself the kind of change that triggers a checkpoint. A proxy is worth it in one case: the server runs somewhere its address is obviously a data centre, or in a different country from the account's history. Even then, a WireGuard or Tailscale exit node on your own home network beats any paid provider, because the address really is yours. If you do buy one, take a dedicated static ISP address and keep it, rather than a rotating residential pool.

  • Route the browser through a proxy with --proxy-server http://host:port (http, https, socks4 and socks5 are accepted). Only browser traffic is routed, not the MCP transport.

  • Credentials go in PROXY_USERNAME and PROXY_PASSWORD. There is no --proxy-password flag on purpose: command-line arguments are readable by every other user on the machine. PROXY_SERVER also accepts the combined http://user:pass@host:port form most providers hand out.

  • Chromium cannot authenticate to a SOCKS proxy, so credentials require an http(s) endpoint. If your provider only offers authenticated SOCKS5, run a local relay that holds the credentials and point the server at that.

  • Local addresses go through the proxy too. Chromium's usual direct route for localhost is removed when a proxy is set, so add PROXY_BYPASS=localhost,127.0.0.1,::1 if you need local targets reached directly.

  • Auto-import is skipped while a proxy is configured: a session taken from a local browser was created on your real address, and moving it to the proxy is the very change that triggers a checkpoint. Use --login.

  • A wrong proxy password does not report itself: Chromium retries the authentication challenge until the page times out, so it surfaces as a timeout or a failed sign-in. If sessions stop working right after you add a proxy, check the credentials before assuming the session expired.

  • Set the proxy up before creating the session. Run --login with the proxy already configured. Turning a proxy on for an existing profile moves a logged-in session to a new IP, which is what triggers a LinkedIn checkpoint. The same applies to --import-from-browser, which imports a session created on your real IP. Use a sticky session, not a rotating pool, for the same reason.

Custom Chrome path:

  • If Chrome is installed in a non-standard location, use --chrome-path /path/to/chrome

  • Can also set via environment variable: CHROME_PATH=/path/to/chrome

🐍 Local Setup (Develop & Contribute)

Contributions are welcome! See CONTRIBUTING.md for architecture guidelines and checklists. Please open an issue first to discuss the feature or bug fix before submitting a PR.

Prerequisites: Git and uv installed

Installation

# 1. Clone repository
git clone https://github.com/stickerdaniel/linkedin-mcp-server
cd linkedin-mcp-server

# 2. Install UV package manager (if not already installed)
curl -LsSf https://astral.sh/uv/install.sh | sh

# 3. Install dependencies
uv sync
uv sync --group dev

# 4. Install pre-commit hooks
uv run pre-commit install

# 5. Start the server
uv run -m linkedin_mcp_server

The local server uses the same managed-runtime flow as MCPB and uvx: it prepares the Patchright Chromium browser cache in the background and opens LinkedIn login on the first auth-requiring tool call. You can still run uv run -m linkedin_mcp_server --login when you want to create the session explicitly.

Local Setup Help

CLI Options:

  • --login - Open browser to log in and save persistent profile

  • --import-from-browser [BROWSER] - Import a LinkedIn session from a locally logged-in Chromium browser (chrome, chromium, brave, edge, arc, vivaldi, helium, yandex, whale, or auto). Bare flag picks auto, which auto-selects the most recently used browser with a live LinkedIn session.

  • --no-headless - Show browser window (useful for debugging scraping issues)

  • --log-level {DEBUG,INFO,WARNING,ERROR} - Set logging level (default: WARNING)

  • --transport {stdio,streamable-http} - Optional: force transport mode (default: stdio)

  • --host HOST - HTTP server host (default: 127.0.0.1)

  • --port PORT - HTTP server port (default: 8000)

  • --path PATH - HTTP server path (default: /mcp)

  • --logout - Clear stored LinkedIn browser profile

  • --timeout MS - Browser timeout for page operations in milliseconds (default: 5000)

  • --tool-timeout SECONDS - Per-tool MCP execution timeout in seconds (default: 180.0). Increase further for heavy scrapes / cold-start Chromium / slow networks.

  • --status - Check if current session is valid and exit

  • --user-data-dir PATH - Path to persistent browser profile directory (default: ~/.linkedin-mcp/profile). Rotating or clearing a session moves and deletes this directory and its parent, which also holds cookies.json, source-state.json and the derived runtime profiles. A path other than the default is therefore only used once it carries a profile-claim.json marker, written automatically when the parent is empty or already holds a session from this server

  • --claim-profile-root - Take over a non-default profile directory this server will not claim on its own: one whose parent already holds other files, or one carrying an ownership marker written for a different path (a mounted volume that moved). Needed once

  • --slow-mo MS - Delay between browser actions in milliseconds (default: 0, useful for debugging)

  • --viewport WxH - Browser viewport size (default: 1280x720). Applies to the normal windowless mode only; a headed launch (--no-headless, --login) uses the real window size

  • --chrome-path PATH - Path to Chrome/Chromium executable (for custom browser installations)

  • --proxy-server URL - Route the browser through a proxy, as scheme://host:port. Set the password via PROXY_PASSWORD (no flag, so it stays out of the process list)

  • --help - Show help

Note: Most CLI options have environment variable equivalents. See .env.example for details.

HTTP Mode Example (for web-based MCP clients):

uv run -m linkedin_mcp_server --transport streamable-http --host 127.0.0.1 --port 8000 --path /mcp

Claude Desktop:

{
  "mcpServers": {
    "mcp-server-linkedin": {
      "command": "uv",
      "args": ["--directory", "/path/to/linkedin-mcp-server", "run", "-m", "linkedin_mcp_server"]
    }
  }
}

stdio is used by default for this config.

Login issues:

  • Make sure you have only one active LinkedIn session at a time

  • LinkedIn may require a login confirmation in the LinkedIn mobile app for --login

  • LinkedIn may show a captcha challenge during login. The --login command opens a browser where you can solve it manually.

Scraping issues:

  • Use --no-headless to see browser actions and debug scraping problems

  • Add --log-level DEBUG to see more detailed logging

Session issues:

  • Browser profile is stored at ~/.linkedin-mcp/profile/

  • Use --logout to clear the profile and start fresh

Python/Patchright issues:

  • Check Python version: python --version (should be 3.12+)

  • Reinstall Patchright: uv run patchright install chromium

  • Reinstall dependencies: uv sync --reinstall

Timeout issues:

  • Page operations failing (elements not found, navigation hangs): increase the browser page-op timeout — --timeout 10000 or TIMEOUT=10000 (milliseconds, default 5000).

  • Entire tool calls timing out (e.g. multi-section profiles, cold-start Chromium, slow containers): increase the per-tool execution timeout — --tool-timeout 300 or TOOL_TIMEOUT=300 (seconds, default 180).

  • First tool call with no session: if a locally logged-in browser has a live LinkedIn session, the server auto-imports it (see AUTO_IMPORT_FROM_BROWSER / --auto-import) instead of forcing a manual login. On macOS the keychain may prompt once for Safe Storage access. If no importable browser session exists, it falls back to opening a login window and waits up to LOGIN_INLINE_WAIT seconds (default 25, max 45; --login-inline-wait) so a quick sign-in resolves in one call. If the wait elapses, the tool returns a pending signal and the model retries in about 30 seconds. Neither the auto-import nor the inline wait applies under Docker or when the server is bound to a non-loopback HTTP host; create the session on the host with --login.

  • Users on slow connections may need higher values for either.

Told to run --login on the host when you already did:

  • If tool calls answer "No valid LinkedIn session is available in Docker" on a machine that is not a container, the runtime was misdetected. This happened on Linux hosts running a Docker daemon for unrelated services. Set LINKEDIN_MCP_CONTAINER=false to override the detection; true forces the opposite.

Using a proxy:

Most people should not use one. LinkedIn's own guidance for reducing security challenges is to avoid a VPN or proxy, and it scores the addresses a session signs in from. A home connection you have used for years is a trust signal; a commercial exit node with a history you cannot see is not, and switching to one is itself the kind of change that triggers a checkpoint. A proxy is worth it in one case: the server runs somewhere its address is obviously a data centre, or in a different country from the account's history. Even then, a WireGuard or Tailscale exit node on your own home network beats any paid provider, because the address really is yours. If you do buy one, take a dedicated static ISP address and keep it, rather than a rotating residential pool.

  • Route the browser through a proxy with --proxy-server http://host:port (http, https, socks4 and socks5 are accepted). Only browser traffic is routed, not the MCP transport.

  • Credentials go in PROXY_USERNAME and PROXY_PASSWORD. There is no --proxy-password flag on purpose: command-line arguments are readable by every other user on the machine. PROXY_SERVER also accepts the combined http://user:pass@host:port form most providers hand out.

  • Chromium cannot authenticate to a SOCKS proxy, so credentials require an http(s) endpoint. If your provider only offers authenticated SOCKS5, run a local relay that holds the credentials and point the server at that.

  • Local addresses go through the proxy too. Chromium's usual direct route for localhost is removed when a proxy is set, so add PROXY_BYPASS=localhost,127.0.0.1,::1 if you need local targets reached directly.

  • Auto-import is skipped while a proxy is configured: a session taken from a local browser was created on your real address, and moving it to the proxy is the very change that triggers a checkpoint. Use --login.

  • A wrong proxy password does not report itself: Chromium retries the authentication challenge until the page times out, so it surfaces as a timeout or a failed sign-in. If sessions stop working right after you add a proxy, check the credentials before assuming the session expired.

  • Set the proxy up before creating the session. Run --login with the proxy already configured. Turning a proxy on for an existing profile moves a logged-in session to a new IP, which is what triggers a LinkedIn checkpoint. The same applies to --import-from-browser, which imports a session created on your real IP. Use a sticky session, not a rotating pool, for the same reason.

Custom Chrome path:

  • If Chrome is installed in a non-standard location, use --chrome-path /path/to/chrome

  • Can also set via environment variable: CHROME_PATH=/path/to/chrome

IMPORTANT

FAQ

Is this safe to use? Will I get banned? This tool controls a real browser session; it doesn't exploit undocumented APIs or bypass authentication. LinkedIn's User Agreement prohibits automated access, and accounts using automated tools can be restricted or banned. Use at your own risk; there is no guarantee of account safety. If you encounter any issues, let me know in the Discussions.

What if my agents execute too many actions? Tool calls run sequentially through a queue. You are responsible for the volume of automation you run; use it sparingly and prompt your agents responsibly.

Acknowledgements

Built with FastMCP and Patchright.

Use in accordance with LinkedIn's User Agreement. Automated access may violate LinkedIn's terms and can lead to account restrictions. This tool is for personal use only and comes with no warranty of any kind.

License

This project is licensed under the Apache 2.0 license.

Available Tools

19 tools
close_sessionClose SessionA
Destructive

Close the current browser session and clean up resources.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior3/5

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

The destructiveHint annotation already flags the tool as destructive. The description adds 'clean up resources,' which gives some context about side effects, but it does not specify what resources are cleaned up (e.g., cookies, cache, local state) or whether the action is reversible. With the annotation covering the destructive nature, the added context is minimal but not contradictory.

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 a single, concise sentence that is front-loaded with the action and resource. Every word carries meaning, with no filler or redundant information.

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 simplicity (no parameters, no nested objects, output schema present, and a clear destructive annotation), the description is fully complete. It tells the agent what the tool does and the annotation covers the safety profile, 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?

The tool has zero parameters, so the description does not need to explain parameter meanings. Per the rubric, a baseline of 4 is appropriate when no parameters are present, and the description adds nothing necessary beyond what the empty schema already conveys.

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 action ('Close the current browser session') and the resource affected ('browser session'), with a specific verb and resource. It is unambiguous and distinguishes itself from all sibling tools, which are all read/social operations and none involve session management.

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?

The description implies usage—you would call this when you are done with the browser session—but it does not explicitly state when to use it or mention alternatives. No exclusion or conditional guidance is provided, so the usage context is implied rather than explicit.

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

connect_with_personConnect With PersonA
Destructive

Send a LinkedIn connection request or accept an incoming one.

The tool is annotated with destructiveHint so MCP clients will prompt for user confirmation before execution.

ParametersJSON Schema
NameRequiredDescriptionDefault
noteNoOptional note to include with the invitation
linkedin_usernameYesLinkedIn username (e.g., "stickerdaniel", "williamhgates")

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

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

The description explicitly references the destructiveHint annotation and explains that MCP clients will prompt for user confirmation before execution. This adds behavioral context beyond the annotation itself, though it does not discuss other side effects like notifications or rate limits.

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 two sentences long, front-loaded with the core action, and every sentence earns its place. It is appropriately concise and easy to scan.

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 two-parameter tool with an output schema, the description covers the essential behavior and the important confirmation side effect. The schema handles parameter details, so no further explanation is needed.

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 has 100% description coverage, including examples for linkedin_username and a clear explanation of the optional note parameter. The tool description itself adds no parameter-level semantics, but the schema already carries that weight.

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 opens with a specific verb and resource: 'Send a LinkedIn connection request or accept an incoming one.' It clearly states the tool's action and target, and the dual send/accept behavior distinguishes it from sibling tools like send_message or get_person_profile.

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 gives clear context for when to use the tool: to send a new connection request or accept an incoming one. It does not explicitly name alternatives or exclusions, but the usage scenario is unambiguous.

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

get_company_employeesGet Company EmployeesA
Read-only

List employees at a company from the LinkedIn /people/ page, including the demographics aggregate that this view exposes: where employees live, where they studied, and a function breakdown (Engineering, Sales, Operations, etc.). The demographics are unique to this tool.

For filtered search by network degree (1st/2nd/3rd) or location, prefer search_people with current_company set to the company URN id. That path also returns more result pages than the /people/ tab.

The optional keywords filter narrows results by name, title, or skill.

company_name must be the exact LinkedIn URL slug (the path segment after /company/), not the display name. LinkedIn assigns unique slugs and the display name often does not match. For example, the AI lab Anthropic lives at /company/anthropicresearch/, not /company/anthropic/. If you are unsure of the slug, call search_companies first and pick the slug from the returned references.

ParametersJSON Schema
NameRequiredDescriptionDefault
keywordsNoOptional filter by name, job title, or skill (e.g., "engineer", "sales")
company_nameYesLinkedIn company URL slug (e.g., "docker", "anthropicresearch", "microsoft")

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true, and the description adds context that the /people/ page exposes a demographics aggregate unique to this tool. It also implies pagination differences vs search_people, though it does not disclose specific rate limits or pagination parameters. 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.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is moderately long but well-structured, with purpose first, followed by alternatives, then parameter-specific guidance. Every sentence adds value, though a bit dense; no fluff.

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 an output schema exists and annotations cover safety, the description provides all necessary operational context: what it returns (employees + demographics), how to get the correct company identifier, when to choose an alternative, and keyword behavior. Fully complete for an AI agent.

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?

The description enriches the schema significantly by explaining that company_name must be the exact LinkedIn URL slug, provides an example, and warns that display names often differ. It also tells how to resolve ambiguity via search_companies. The keyword filter meaning is confirmed, adding practical nuance.

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 lists employees from the LinkedIn /people/ page, including unique demographics (location, school, function). It distinguishes itself from search_people by noting the demographics are unique to this tool.

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?

Provides explicit guidance: prefer search_people for filtered search by network degree or location, notes that path returns more pages, and instructs to call search_companies if uncertain about the exact slug. This gives clear when-to-use and alternatives.

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

get_company_postsGet Company PostsA
Read-only

Get recent posts from a company's LinkedIn feed.

ParametersJSON Schema
NameRequiredDescriptionDefault
company_nameYesLinkedIn company name (e.g., "docker", "anthropic", "microsoft")

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.8/5.0
Behavior3/5

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

Annotations already declare readOnlyHint and openWorldHint, so the safety profile is covered. The description adds the 'recent' qualifier and company focus, but doesn't disclose behaviors like time window limitation or pagination. This is consistent with annotations and adds modest context beyond them.

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 a single, well-structured sentence that front-loads the verb and resource. It contains no filler or redundant information, earning a top score for efficiency.

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 simple read-only tool with one parameter and an output schema, the description is largely complete. It adequately communicates what the tool returns (company feed posts) and integrates with annotations. The only minor gap is the unspecified meaning of 'recent,' but this does not undermine overall completeness.

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 has 100% coverage—company_name is described with examples. The tool description offers no additional parameter detail beyond what the schema provides, so it meets the baseline but adds no extra semantic value.

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 uses a specific verb ('Get'), identifies the resource ('recent posts from a company's LinkedIn feed'), and clearly differentiates from sibling tools like get_feed (general feed) and search_posts (search-based retrieval). This is unambiguous and contextually distinct.

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?

The tool's purpose implies usage when company-specific posts are needed, but no explicit guidelines are given about when to prefer this over search_posts or get_feed. The description relies on inferred context from the name rather than stating exclusions or alternatives.

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

get_company_profileGet Company ProfileC
Read-only

Get a specific company's LinkedIn profile.

ParametersJSON Schema
NameRequiredDescriptionDefault
sectionsNoComma-separated list of extra sections to scrape. The about page is always included. Available sections: posts, jobs Examples: "posts", "posts,jobs" Default (None) scrapes only the about page.
company_nameYesLinkedIn company name (e.g., "docker", "anthropic", "microsoft")

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

C2.9/5.0
Behavior2/5

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

Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is known. The description adds no additional behavioral context such as rate limits, data freshness, or how the sections parameter affects behavior, offering no value beyond the 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 a single short sentence, making it highly concise and front-loaded. However, it is too terse to capture the full scope of the tool (e.g., sections), so it earns a high but not perfect score.

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

Completeness3/5

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

With annotations, output schema, and complete parameter schema, the basic operation is clear. However, the description omits the fact that it can optionally scrape posts and jobs via the sections parameter, which could lead to confusion with get_company_posts. Thus it is adequate but not fully 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?

All parameter descriptions are provided in the input schema, including detailed explanations for the optional sections parameter. The description itself does not touch on parameters, but since schema coverage is 100%, the baseline of 3 applies without needing to compensate.

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 uses a specific verb 'Get' with a resource 'a specific company's LinkedIn profile', clearly indicating the primary function. However, it does not distinguish from sibling tools like get_company_posts or search_companies beyond the name, so it is clear but not explicitly differentiated.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives like get_company_posts or search_companies. There is no mention of scenarios or exclusions, leaving the agent to infer usage solely from the name.

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

get_conversationGet ConversationA

Read a specific messaging conversation.

Provide either linkedin_username or thread_id to identify the conversation.

When looked up by linkedin_username, resolution searches the messaging inbox for the participant's display name and click-visits every matching row to capture its thread ID — LinkedIn's sidebar has no anchor hrefs or thread-id attributes, so this is the only available path. Each visit selects the row in the LinkedIn UI and may mark it as read. Pass thread_id directly to skip this enumeration.

ParametersJSON Schema
NameRequiredDescriptionDefault
indexNo0-based selector for which thread to open when the participant has multiple threads (e.g. an organic 1-on-1 plus an InMail). Ignored when thread_id is provided. To enumerate thread IDs first, call search_conversations.
thread_idNoLinkedIn messaging thread ID
linkedin_usernameNoLinkedIn username of the conversation participant

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

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

The description discloses the non-obvious behavior of click-visiting rows and potential read-marking: 'Each visit selects the row in the LinkedIn UI and may mark it as read.' This goes well beyond the sparse openWorldHint annotation.

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 compact with three sentences, front-loading the purpose and delivering essential caveats 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?

Given the tool's complexity (two lookup paths and side effects), the description covers usage, rationale, and risks, making it self-sufficient for 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?

While the schema already covers all parameters (100% coverage), the description adds meaningful context about when to use each identifier and the index selector's role, enriching 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 'Read a specific messaging conversation' with a specific verb and resource, and distinguishes between username and thread_id lookup modes, setting it apart from siblings like search_conversations and get_inbox.

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 explicit guidance on parameter selection: 'Provide either linkedin_username or thread_id' and 'Pass thread_id directly to skip this enumeration.' However, it doesn't explicitly name alternatives or exclusion criteria, relying on schema for cross-reference.

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

get_feedGet FeedA
Read-only

Get posts from the authenticated user's LinkedIn feed.

ParametersJSON Schema
NameRequiredDescriptionDefault
num_postsNoNumber of posts to fetch (1-50, default 10). Posts are loaded in batches of ~5 as the page scrolls, so the actual count may slightly exceed the target.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true and openWorldHint=true, so the description doesn't need to repeat safety traits. The description itself adds no behavioral context beyond the purpose; the parameter schema mentions batch loading behavior, but that is not part of the description. Thus, the description provides minimal value 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?

The description is a single, front-loaded sentence that precisely states the tool's function. No unnecessary words or repetition, making it highly concise and effectively 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?

Given the tool's simplicity, existing output schema, and rich annotations, the one-sentence description is sufficient. The read-only annotation covers safety, the schema covers parameters, and the output schema covers return values, so the description fills the remaining purpose gap completely.

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 has 100% parameter description coverage, including default, min, max, and batch loading behavior. The tool description adds no extra parameter meaning. With full schema coverage, a baseline of 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 a specific verb and resource: 'Get posts from the authenticated user's LinkedIn feed.' It distinguishes itself from siblings like get_company_posts (company feed) and search_posts (search), making the tool's purpose explicit.

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 context: it is for the authenticated user's own LinkedIn feed, not for company posts or search results. While it doesn't explicitly name alternatives or exclusions, the context is unambiguous enough for an agent to decide when to use it.

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

get_inboxGet InboxA
Read-only

List recent conversations from the LinkedIn messaging inbox.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum number of conversations to load (1-50, default 20)

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior3/5

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

The annotations already signal read-only and open-world behavior, so the description is not required to repeat that. It adds the 'recent' qualifier, which indicates ordering by recency, but does not provide further behavioral context like pagination, rate limits, or auth requirements. This is a modest addition beyond annotations, so a mid score is appropriate.

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 a single, succinct sentence that immediately states the action and resource. It is front-loaded and contains no filler or redundant information, earning full marks for conciseness.

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?

This is a simple tool with one optional parameter, read-only/open-world annotations, and an output schema. The description clearly conveys the core purpose, and since an output schema exists, there is no need to detail return values. The combination of annotations, schema, and description provides a complete understanding for a straightforward listing operation.

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 fully describes the only parameter `limit` with a clear explanation including range and default (100% coverage). The description does not add any additional meaning about the parameter, so the baseline score of 3 is maintained.

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 uses the specific verb 'List' with the resource 'recent conversations from the LinkedIn messaging inbox.' This clearly defines the tool's scope and differentiates it from siblings like get_conversation (single conversation) or search_conversations (search-based). The mention of 'messaging inbox' distinguishes it from non-inbox tools like get_feed.

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?

The description implies this is the tool for browsing recent inbox conversations, but it does not explicitly state when to use it versus alternatives such as search_conversations or get_conversation. There is no exclusion or mention of alternative tools, leaving the decision to the agent's inference from the sibling list.

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

get_job_detailsGet Job DetailsA
Read-only

Get job details for a specific job posting on LinkedIn.

ParametersJSON Schema
NameRequiredDescriptionDefault
job_idYesLinkedIn job ID (e.g., "4252026496", "3856789012")

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true and openWorldHint=true, so the description does not need to restate safety. However, the description adds no extra behavioral context (e.g., return format, live data implications, potential errors) beyond the purpose. It does not contradict the 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 a single, front-loaded sentence that directly states purpose. Every word earns its place, and there is no redundancy or fluff.

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?

With an output schema present and a single well-documented parameter, the description is sufficient for a simple get-by-id operation. The scope is clear, and the presence of an output schema means the description does not need to explain return values.

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?

Schema coverage is 100%, and the description does not add meaning beyond the schema. The job_id parameter is well-documented in the schema with examples, so the description's mention of 'specific job posting' aligns but provides no additional value.

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 verb 'Get' and resource 'job details' for a specific job posting, distinguishing it from search_jobs or get_saved_jobs. The use of 'specific' and the job_id parameter make the purpose unambiguous.

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?

The description implies this tool is for retrieving details when you already have a specific job ID, but it does not explicitly mention when to use it versus alternatives like search_jobs or get_saved_jobs. No exclusions or alternative references are provided.

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

get_my_profileGet My ProfileA
Read-only

Get the authenticated user's own LinkedIn profile.

Navigates to /in/me/ and resolves the redirect to obtain the real username before scraping, so the url field in the result is the actual profile URL (e.g. linkedin.com/in/johndoe/) rather than /in/me/.

ParametersJSON Schema
NameRequiredDescriptionDefault
sectionsNoComma-separated list of extra sections to scrape. The main profile page is always included. Available sections: experience, education, interests, honors, languages, certifications, skills, projects, contact_info, posts Examples: "experience,education", "contact_info", "skills,projects" Default (None) scrapes only the main profile page.
max_scrollsNoMaximum pagination attempts per section (same as get_person_profile).

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

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

Annotations provide readOnlyHint=true, and the description adds valuable behavioral context: it navigates to /in/me/, resolves the redirect, and ensures the url field is the real profile URL. This goes beyond the annotation by explaining the scraping process and expected URL format.

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 two sentences: a concise purpose statement followed by a relevant behavioral detail. No wasted words, and the key info is front-loaded.

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 simplicity, the presence of an output schema, and thorough schema param descriptions, the description fully covers the essential behavioral nuance (redirect resolution) without needing to explain return values or parameter details. It is complete for its complexity tier.

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 has 100% description coverage for both optional parameters, so the baseline is 3. The description does not add parameter-specific meaning beyond the schema, but the schema itself is thorough.

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 user's own LinkedIn profile, using a specific verb and resource. It also distinguishes itself from sibling get_person_profile by emphasizing 'own profile' and the /in/me/ redirect behavior.

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 makes evident when to use it (for the current user's profile) without explicitly naming alternatives. It does not say 'use get_person_profile for others', but the context of sibling tools and the 'authenticated user's own' phrasing provides clear usage context.

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

get_person_profileGet Person ProfileB
Read-only

Get a specific person's LinkedIn profile.

ParametersJSON Schema
NameRequiredDescriptionDefault
sectionsNoComma-separated list of extra sections to scrape. The main profile page is always included. Available sections: experience, education, interests, honors, languages, certifications, skills, projects, contact_info, posts Examples: "experience,education", "contact_info", "skills,projects", "honors,languages", "posts" Default (None) scrapes only the main profile page.
max_scrollsNoMaximum pagination attempts per section to load more content. On detail sections (experience, certifications, skills, etc.) this is the max number of "Show more" button clicks. On activity/posts it is the max scroll-to-bottom iterations. Applies to all sections in this call. Default (None) uses 5 for detail sections and 10 for posts. Increase when a profile has many items in a section (e.g., 30+ certifications, max_scrolls=20). To avoid slowing down other sections, request heavy sections in a separate call.
linkedin_usernameYesLinkedIn username (e.g., "stickerdaniel", "williamhgates")

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

B3.1/5.0
Behavior2/5

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

Annotations already declare readOnlyHint and openWorldHint, so the description does not need to repeat read-only status. However, the description adds no behavioral context beyond the schema, such as how sections or max_scrolls affect scraping depth. With no extra context, it provides minimal additive transparency.

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 a single, direct sentence with no filler or redundancy. It is front-loaded and easy to parse, ideal for quick scanning.

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

Completeness3/5

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

For a simple GET tool, the description combined with the rich schema and annotations covers the essentials. However, it doesn't mention the ability to scrape extra sections or control pagination, which are salient features; although these are fully documented in the schema, the description leaves the tool's full range hidden. It also lacks any mention of alternatives, making it slightly incomplete for contextual selection.

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 has 100% parameter coverage with detailed descriptions for linkedin_username, sections, and max_scrolls. The description itself adds no parameter semantics, but the schema carries the full burden, so a baseline 3 is appropriate.

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 uses a specific verb ('Get') and resource ('a specific person's LinkedIn profile'), which is clear and distinguishes it from company/self/feed tools. It could be more explicit about using a LinkedIn username, but the schema clarifies that. It does not explicitly differentiate from search_people or get_sidebar_profiles, but the direct 'get' wording implies a targeted lookup.

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

Usage Guidelines2/5

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

No guidance is provided about when to use this tool versus alternatives like search_people or get_my_profile. The one-sentence description implies basic usage but offers no exclusions, prerequisites, or alternative references, leaving the agent without context for selection.

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

get_saved_jobsGet Saved JobsA
Read-only

List job postings saved by the authenticated LinkedIn user.

Returns job_ids that can be passed to get_job_details for full info.

ParametersJSON Schema
NameRequiredDescriptionDefault
max_pagesNoMaximum number of saved-jobs pages to load (1-10, default 3)

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true, so the read-only nature is known. The description adds behavioral context by explaining that the tool returns job_ids intended for use with get_job_details, which clarifies the output's role. This goes beyond what annotations provide, so a 4 is appropriate.

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 consists of two short, purposeful sentences. The first sentence states the primary function, the second adds a chaining hint. No redundant wording or filler.

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 read-only list tool with one optional parameter and an output schema, the description fully covers what the tool does and how its result can be used. The annotations and output schema fill the remaining details, so no significant gaps exist.

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?

Schema coverage is 100%, and the max_pages parameter is fully described in the schema. The description does not add extra parameter semantics, matching the baseline of 3 when the schema carries the load.

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 uses the specific verb 'List' with the resource 'job postings saved by the authenticated LinkedIn user', clearly defining the tool's scope. It distinguishes itself from sibling tools like search_jobs and get_job_details by focusing on saved postings specifically.

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 context by stating these are the user's saved jobs and explicitly mentions that returned job_ids can be passed to get_job_details. While it doesn't explicitly describe when not to use this tool, the connection to a sibling tool offers practical usage guidance.

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

get_sidebar_profilesGet Sidebar ProfilesA
Read-only

Get profile links from sidebar recommendation sections on a LinkedIn profile page.

Extracts profiles from "More profiles for you", "Explore premium profiles", and "People you may know" sidebar sections. Follows "Show all" links to return the full list from each section. Sections that redirect to linkedin.com/premium are skipped.

ParametersJSON Schema
NameRequiredDescriptionDefault
linkedin_usernameYesLinkedIn username of the profile page to scrape (e.g., "stickerdaniel", "williamhgates")

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

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

Annotations declare readOnlyHint and openWorldHint; description adds concrete behaviors: following 'Show all' links to return full lists, and skipping sections that redirect to linkedin.com/premium. 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?

Two-sentence description is front-loaded with purpose and includes only relevant behavioral details (section names, Show all behavior, premium skip). No filler.

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 read tool with output schema, the description covers what, where, and edge-case behavior (premium redirects), making it self-sufficient.

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?

Schema coverage is 100% and the lone parameter linkedin_username is clearly described in the schema. Description adds no additional parameter semantics.

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 uses specific verb 'Get profile links' and names exact sections ('More profiles for you', 'Explore premium profiles', 'People you may know'), clearly distinguishing it from sibling tools like get_person_profile or search_people.

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?

It clearly states the context: scraping sidebar recommendation sections from a LinkedIn profile page. It does not explicitly list when not to use or name alternative tools, but context is unambiguous.

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

search_companiesSearch CompaniesC
Read-only

Search for companies on LinkedIn.

ParametersJSON Schema
NameRequiredDescriptionDefault
keywordsYesSearch keywords (e.g., "fintech", "anthropic", "electric vehicles")

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

C2.9/5.0
Behavior2/5

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

Annotations already indicate readOnlyHint and openWorldHint, and the description adds no additional behavioral context such as pagination, result limits, or authentication needs. It does not contradict annotations but fails to enhance them.

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 a single concise sentence that front-loads the core action. It is efficient and free of fluff, though it borders on under-specification by omitting any additional useful details.

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

Completeness3/5

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

Given the tool's low complexity (one parameter) and the existence of an output schema, the description is minimally adequate. It lacks context about limitations or distinctions from other search tools, making it sufficient but not thorough.

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 fully documents the keywords parameter with an example, providing 100% coverage. The description adds no extra meaning about parameter usage or format, so the baseline of 3 is appropriate.

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 clearly states the tool's function: searching for companies on LinkedIn, using a specific verb and resource. It distinguishes from sibling search tools like search_people and search_jobs by the resource type, though it lacks specificity about the search mechanism.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives, no exclusions, and no prerequisites. It simply states the action without context for selection.

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

search_conversationsSearch ConversationsB

Search messages by keyword.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum number of search-result rows to enumerate as conversation references (1-50, default 20). Each enumeration selects the row in LinkedIn's UI and may mark it as read, so a low cap is preferable for noisy queries.
keywordsYesSearch keywords to filter conversations

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

B3.4/5.0
Behavior2/5

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

The description discloses no behavioral traits beyond the openWorldHint annotation. The schema's limit parameter warns that enumerating rows may mark them as read, but the description omits this side effect, and no destructiveHint/readOnlyHint is present to compensate.

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 no filler or redundancy. It is appropriately concise for a simple search tool.

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?

Given the low complexity, 100% schema coverage, and presence of an output schema, the one-sentence description is minimally viable. It could be more complete by mentioning the read side effect or search scope, but the schema already covers parameter-level details.

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?

Schema description coverage is 100%, with limit's side effects and defaults well documented. The description adds only 'by keyword', which aligns with the keywords parameter, but no extra meaning beyond the schema is needed or provided.

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?

Description uses a specific verb ('Search') and resource ('messages'), which distinguishes it from sibling tools like get_inbox or get_conversation. However, it doesn't explicitly mention 'conversations' as the output unit or contrast with search_posts, leaving slight ambiguity about scope.

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?

No explicit when-to-use or alternative guidance is provided. The name and sibling context imply it is the keyword search tool for messages/conversations, but the description does not say when to prefer it over get_inbox or get_conversation.

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

search_jobsSearch JobsA
Read-only

Search for jobs on LinkedIn.

Returns job_ids that can be passed to get_job_details for full info.

ParametersJSON Schema
NameRequiredDescriptionDefault
sort_byNoSort results (date, relevance)
job_typeNoFilter by job type, comma-separated (full_time, part_time, contract, temporary, volunteer, internship, other)
keywordsYesSearch keywords (e.g., "software engineer", "data scientist")
locationNoOptional location filter (e.g., "San Francisco", "Remote")
max_pagesNoMaximum number of result pages to load (1-10, default 3)
work_typeNoFilter by work type, comma-separated (on_site, remote, hybrid)
easy_applyNoOnly show Easy Apply jobs (default false)
date_postedNoFilter by posting date (past_hour, past_24_hours, past_week, past_month)
experience_levelNoFilter by experience level, comma-separated (internship, entry, associate, mid_senior, director, executive)

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.2/5.0
Behavior4/5

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

Annotations already cover readOnlyHint=true, which is reinforced by the description's 'Search' action. The description adds behavioral context by explicitly stating that results contain only job_ids and that full details require a separate call, which helps set expectations about the return value.

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?

Two concise sentences, front-loaded with the main purpose and a valuable cross-reference to get_job_details. No filler, every word earns its place.

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?

Given the rich schema (100% parameter coverage) and presence of an output schema, the description provides sufficient context. It could mention pagination via max_pages, but the schema already covers that, so the description remains complete for effective tool selection and invocation.

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?

Schema description coverage is 100%, with all 9 parameters having clear descriptions in the schema. The tool description itself adds no parameter-specific semantics, so the baseline score of 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?

Description clearly states 'Search for jobs on LinkedIn' with a specific verb and resource, distinguishing it from sibling tools like search_people and search_companies. It also specifies the output format (job_ids) and points to get_job_details for full info, which further clarifies the tool's role.

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 implies when to use this tool (job searching) and guides the agent to get_job_details for full job information. However, it does not explicitly name alternative tools or state when not to use it, though the sibling names and context make this reasonably clear.

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

search_peopleSearch PeopleB
Read-only

Search for people on LinkedIn.

ParametersJSON Schema
NameRequiredDescriptionDefault
networkNoOptional connection-degree filter. Each element is one of "F" (1st-degree), "S" (2nd-degree), "O" (3rd-degree and beyond). Example: ["F"] to only return 1st-degree connections.
keywordsYesSearch keywords (e.g., "software engineer", "recruiter at Google")
locationNoOptional location filter (e.g., "New York", "Remote")
current_companyNoOptional current-employer filter. LinkedIn's currentCompany facet only filters on the numeric company URN id (e.g. "1115" for SAP); plain company names are accepted by the URL but ignored by LinkedIn and return the unfiltered result set. Look up a company's URN via get_company_profile -- it is exposed under references["about"]. For company-wide employee demographics (location/education/function breakdown) plus a slug-based lookup, use get_company_employees instead.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

B3.4/5.0
Behavior2/5

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

The description merely restates the purpose and adds no behavioral details beyond the annotations. Annotations declare readOnlyHint=true and openWorldHint=true, but the description does not mention result limits, pagination, or any search-specific caveats, so it fails to add informative value.

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 one-sentence description is immediate and free of extraneous words, effectively communicating the tool's core function in minimal space.

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?

Given the rich input schema, an output schema, and annotations indicating read-only and open-world behavior, the terse description is adequate to convey the tool's basic purpose. However, it omits any mention of search-specific behavior like result ordering or how to scope searches, though the schema covers filters.

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?

With 100% schema description coverage, all four parameters (keywords, network, location, current_company) are already explained in detail. The description adds no additional semantic context, so the baseline of 3 applies.

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 action (search) and the resource (people on LinkedIn), distinguishing it from sibling search tools like search_jobs and search_companies by specifying 'people'.

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

Usage Guidelines2/5

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

No guidance is provided on when to use this tool versus alternatives such as get_person_profile for direct profile lookups or search_companies for organizations. The only hint is the name, which implies people search.

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

search_postsSearch PostsA
Read-only

Search LinkedIn posts/content globally by keyword (the "Posts" tab).

Use this to catch informal hiring posts ("we're hiring", "Buscamos ...", "estamos contratando", "join our team") that often appear before a formal job listing exists. This is global content search, distinct from get_feed (your own home feed) and get_company_posts (one company's page).

ParametersJSON Schema
NameRequiredDescriptionDefault
keywordsYesSearch keywords (e.g., "Buscamos Unity", "AI automation hiring")
max_pagesNoScroll depth as result "pages" of ~5 scrolls each (1-10, default 3). Content search is an infinite scroll, so this caps how far the page is scrolled rather than fetching discrete pages.
date_postedNoOptional recency filter. One of "past-24h", "past-week", "past-month"; the "past_24_hours" / "past_week" / "past_month" spellings used by search_jobs are accepted too. Omit for any time.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.2/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds useful context about global search scope and purpose, but does not disclose behaviors like pagination/scroll depth or rate limits beyond what's in the schema. This is adequate but not exceptional.

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?

Three sentences, front-loaded with the action, then targeted usage guidance. Every sentence earns its place with no fluff or repetition of schema details.

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?

The description covers purpose, usage, and sibling differentiation. An output schema exists, so return value details are handled. It could mention the infinite-scroll behavior or open-world limitations (though the schema parameter notes it), but overall it is quite complete for a search tool.

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?

Schema description coverage is 100%, so the structured fields already explain all three parameters. The description adds example search keywords, but does not add new semantic meaning beyond what the schema provides. 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 opens with a specific verb+resource+scope: 'Search LinkedIn posts/content globally by keyword'. It explicitly distinguishes from sibling tools get_feed and get_company_posts, making the purpose unambiguous.

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 gives concrete when-to-use guidance: 'Use this to catch informal hiring posts' with example keywords. It also names exclusions by contrasting with get_feed and get_company_posts, telling the agent when not to use this tool.

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

send_messageSend MessageA
Destructive

Send a message to a LinkedIn user.

The recipient must be directly messageable from the profile page. This is a write operation when confirm_send is True.

ParametersJSON Schema
NameRequiredDescriptionDefault
messageYesThe message text to send
profile_urnNoOptional profile URN (e.g. ACoAAB...) to construct the compose URL directly. Providing this bypasses the Message-button lookup and is more reliable when available. Obtain via get_person_profile. Note: inbox may not always show all messages; use search_conversations as a fallback.
confirm_sendYesMust be True to send the message
linkedin_usernameYesLinkedIn username of the recipient

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4/5.0
Behavior4/5

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

Annotations already indicate destructiveHint and openWorldHint. The description adds valuable specificity by clarifying that the write operation only executes when confirm_send is True, and it highlights a real-world constraint (recipient must be directly messageable). This goes beyond the raw annotation hints.

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?

Two clear sentences with no fluff. The first sentence states the action, the second gives the critical prerequisite and write condition. Every word earns its place.

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?

Given the tool's complexity (4 params, all documented) and the presence of an output schema, the description adequately covers the core behavior. It leaves typical implementation details to the output schema. A bit more about potential side effects or post-send behavior would make it perfect, but it is sufficient.

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?

Schema description coverage is 100%, so baseline is 3. The description itself does not add parameter-level semantics, but the schema already fully documents each parameter, including the profile_urn bypass behavior and the confirm_send requirement. No further explanation is needed.

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 'Send a message to a LinkedIn user' with a specific verb and resource. This unambiguously identifies the tool's purpose and naturally distinguishes it from sibling tools like connect_with_person (connection requests) and get_inbox (reading messages).

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?

The description gives a prerequisite ('The recipient must be directly messageable from the profile page') and notes the write condition (confirm_send=True), but it does not explicitly contrast with alternatives or state when not to use it. The usage context is implied rather than fully spelled out.

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. Dates show when Glama detected each change.

  1. 19 tool updatesv4.20.1
    • First observedclose_session
    • First observedconnect_with_person
    • First observedget_company_employees
    • First observedget_company_posts
    • First observedget_company_profile
    • First observedget_conversation
    • First observedget_feed
    • First observedget_inbox
    • First observedget_job_details
    • First observedget_my_profile
    • First observedget_person_profile
    • First observedget_saved_jobs
    • First observedget_sidebar_profiles
    • First observedsearch_companies
    • First observedsearch_conversations
    • First observedsearch_jobs
    • First observedsearch_people
    • First observedsearch_posts
    • First observedsend_message

TDQS

A3.8/5.0
Disambiguation5/5

Each tool targets a distinct resource and action: search_* tools are separated by entity (companies, jobs, people, conversations, posts), and get_* tools are separated by specific content (feed, company posts, job details, profiles, conversation). Even potentially similar tools like get_feed, get_company_posts, and search_posts have clear contextual differences described.

Naming Consistency5/5

All 19 tool names follow a consistent lowercase_with_underscores verb_noun pattern: get_*, search_*, send_*, connect_*, close_*. There is no mixing of styles or vague verbs, making the toolset predictable and easy to navigate.

Tool Count4/5

With 19 tools, the server is slightly above the typical 3-15 range but each tool addresses a real LinkedIn feature area (feed, jobs, messaging, people, companies, posts). No tools are redundant, and the count reflects the multi-domain scope of LinkedIn, so it feels reasonable rather than bloated.

Completeness4/5

The server covers core LinkedIn workflows: reading feed (own, company, global search), searching and retrieving profiles/companies/employees, job search and details, messaging (inbox, conversation, search, send), and connection requests. Minor gaps exist (e.g., no ability to post or like), but for a read/messaging/connection automation server, the surface is nearly complete.

Maintenance

ActivityMaintained
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/kaistenberg/MCP-Linkedin'

If you have feedback or need assistance with the MCP directory API, please join our Discord server