Skip to main content
Glama

LinkBridge MCP

LinkBridge MCP is a community-maintained fork of the upstream LinkedIn MCP server. It gives AI agents access to LinkedIn through your own browser session. Read profiles, research companies, find jobs, and manage conversations and connection requests.

This is an independent open-source project, not affiliated with LinkedIn or Microsoft. LinkedIn is a trademark of LinkedIn Corporation, used here only to identify the service this software interacts with.

Deploy on Render

This repository includes a render.yaml blueprint for a Docker-based web service. In Render, create a new Blueprint from this repository and deploy the linkbridge-mcp service. The service uses Streamable HTTP on Render’s assigned port and a persistent disk for the browser profile. Complete LinkedIn sign-in separately and keep the profile disk attached across deploys.

Running LinkedIn agents in production? LinkupAPI is the hosted outreach API built for scale, across LinkedIn Classic, Sales Navigator, and Recruiter, plus email, WhatsApp, and iMessage.

Try LinkupAPI free →

Cadenza is the single hosted MCP server for all your LinkedIn needs. It covers Classic, Sales Navigator, and Recruiter with 100+ actions, each within limits you set. Works on web, desktop, and mobile.

Use code FOUNDING20 for 20% off your first year. Try Cadenza →

This MCP server is supported by Unipile. Unipile is the fully managed cloud option for developers: a hosted LinkedIn API for Classic, Sales Navigator, and Recruiter that handles auth, sessions, and infrastructure for you.

Try Unipile free for 7 days →

Zernio gives your agents official APIs for every social channel. Post, reply, and run ads on Instagram, TikTok, X, YouTube, Threads, and more, through one API or MCP server.

Try Zernio free →


Related MCP server: LinkedIn MCP Server

Installation Methods - LinkedIn MCP Server

uvx Install MCP Bundle Codex Plugin Claude Code Plugin Cursor Plugin Docker

Tool

Description

get_person_profile

Read profile sections: experience, education, skills, projects, volunteering, posts.

get_my_profile

Read your own profile, with the same section selection as other profiles.

connect_with_person

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

get_sidebar_profiles

Find recommended profile links, including people you may know.

get_inbox

List recent inbox conversations, with links to open individual threads.

get_conversation

Read a conversation's messages using a LinkedIn username or thread ID.

search_conversations

Search messages by keyword and return links to matching conversation threads.

archive_conversation

Archive a conversation by thread ID; a repeat call reports it already archived.

send_message

Send after confirmation; profile targets may open a new DM (#483).

reply_to_conversation

Reply inside an existing thread or InMail by thread ID. Sends after confirmation.

get_company_profile

Read company information, with optional sections for posts and open jobs.

get_company_posts

Read recent posts from a company's feed, with links to the original posts.

search_companies

Find companies by keyword and return links to their LinkedIn profiles.

get_company_employees

Find company employees, optionally filtered by name, title, or skill.

search_jobs

Find job postings by keyword and location, with job IDs for reading details.

get_saved_jobs

List your saved job postings, with job IDs for looking up their details.

dismiss_job

Dismiss a job from job search so later searches no longer show it. Irreversible.

search_people

Find people by keyword, location, connection degree, and current company.

get_job_details

Read a job posting's description, requirements, and company details.

get_job_apply_url

Check whether a job uses Easy Apply or links to an employer's application.

get_easy_apply_form

Read an Easy Apply form's fields, options and prefilled values. Never submits.

get_feed

Read recent posts from your home feed, with links to the original posts.

search_posts

Search posts by keyword, optionally filtered by recency or content type.

get_session_status

Check your saved login and browser state without opening a browser.

close_session

Close the shared browser session without deleting your saved login.

Prerequisites: Install uv.

Installation

Add to your MCP client's mcpServers configuration

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

The @latest tag turns on automatic updates, which keep the server working with LinkedIn's current page structure. The server starts quickly and prepares the shared Patchright Chromium browser cache in the background under ~/.linkedin-mcp/patchright-browsers. On the first tool call that needs authentication, it reuses a LinkedIn session from a signed-in local browser if it finds one, and otherwise opens a LinkedIn login browser window.

AI agent? Get a quick confirmation from the user before enabling automatic updates.

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 linkbridge-mcp@latest --login.

Setup Help

  • 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

Session:

  • --login - Open a browser to sign in and save the session

  • --import-from-browser [BROWSER] - Reuse a session from a locally signed-in Chromium browser (chrome, chromium, brave, edge, arc, vivaldi, helium, yandex, whale, coccoc, opera, opera_gx, auto). Bare flag picks auto, the most recently used browser with a live LinkedIn session.

  • --auto-import / --no-auto-import - Import a session from a signed-in local browser on the first tool call that needs one, before falling back to manual login (default: on). Skipped in Docker, behind a proxy, and on a non-loopback HTTP bind. On macOS the keychain may prompt once.

  • --logout - Clear the stored session

  • --login-viewer - Docker only: show the --login browser at a token-protected URL on port 6080 (see Authentication)

  • --user-data-dir PATH - Browser profile directory (default: ~/.linkedin-mcp/profile). Rotating or clearing a session deletes this directory and its parent, which holds the stored cookies and derived profiles.

  • --claim-profile-root - Take over a profile directory the server will not claim on its own, such as one whose parent already holds other files. Needed once per directory.

Transport:

  • --transport {stdio,streamable-http} - Force the transport mode (default: stdio)

  • --host HOST / --port PORT / --path PATH - HTTP server address (defaults: 127.0.0.1, 8000, /mcp)

Timeouts:

  • --timeout MS - Timeout for a single page operation (default: 5000)

  • --tool-timeout SECONDS - Timeout for a whole tool call (default: 180). Raise it for calls that read many pages, slow networks, or a cold-start browser.

  • --login-timeout SECONDS - How long the login browser waits for you to finish signing in (default: 1800; 0 = no limit). --login-viewer ends the session after 30 minutes either way.

  • --login-inline-wait SECONDS - How long a tool call waits for a login to finish before telling the model to retry (default: 25, max 45; 0 = return at once)

Shared browser:

  • --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 with several MCP clients running at once.

  • --browser-min-hold SECONDS - Shortest time this process keeps the shared browser before handing it over (default: 20). Clamped to 3 seconds below --browser-wait, so raise that one along with it. Higher means fewer browser restarts but longer waits for other clients.

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

Browser:

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

  • --chrome-path PATH - Path to a Chrome/Chromium executable

  • --proxy-server URL - Route browser traffic through a proxy, as scheme://host:port. Set it up before --login; see Using a proxy.

Other:

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

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

# Auto-pick the most recently used browser with a live LinkedIn session
uvx linkbridge-mcp@latest --import-from-browser
# Or target a specific browser
uvx linkbridge-mcp@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 linkbridge-mcp@latest --log-level DEBUG

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

uvx linkbridge-mcp@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

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

  • Windows, DLL load failed while importing _greenlet: move to greenlet 3.5.5 or newer, whose published Windows wheels carry the C++ runtime inside the extension again. A fresh uvx run resolves that on its own; an environment that pins its dependencies needs uv lock --upgrade-package greenlet. Only greenlet 3.3.1 through 3.5.4 need MSVCP140.dll, which neither the python.org installer nor the uv-managed builds carry, and a greenlet built from source can need it at any version. Where the version cannot be moved, the Microsoft Visual C++ Redistributable supplies that DLL. Reported as greenlet#525, fixed in greenlet#526.

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

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

  • The browser cache keeps growing: a server upgrade can bring a new Chromium revision, and Patchright keeps the old one for as long as any installed version still references it. uvx keeps one archive per version you have ever run, so every one of them holds such a reference and the old revisions stay. The server logs a warning naming the revisions it is holding and how much space they take. To reclaim it, stop every LinkedIn MCP Server instance, delete ~/.linkedin-mcp/patchright-browsers/, and let the next launch download the current browser.

  • 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 linkbridge-mcp@latest --login which opens a browser where you can solve it manually.

  • 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, or use the explicit Docker --login --login-viewer command.

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

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

  • 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

  • On macOS and Linux the browser must be at least as new as the one that last opened your profile, and the server refuses the launch otherwise. (Not on Windows: a browser there cannot be asked its version without starting one, so the check is off.) An older browser can silently drop stores a newer one wrote, the saved session among them, and the failure then looks exactly like an expired login. The message names both versions. Going back to the bundled Chromium after running a newer Chrome once is the usual way to meet this; either run the newer browser again, whichever one that was, or run --login, which moves the stored session aside and signs in fresh with the browser you have. --logout also clears it but discards the old session instead of keeping it recoverable, and it asks for confirmation on the terminal, so it is not usable from a server an MCP client started.

  • Only Chrome, Chromium and Chrome for Testing are compared this way. Forks number themselves differently (Vivaldi is on 7.x, Edge's build number sits far below Chrome's under the same major), so pointing CHROME_PATH at one turns the check off rather than producing a refusal nothing could satisfy.

Claude Desktop MCP Bundle (formerly DXT)

Prerequisites: Claude Desktop.

Installation

  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 prepares the shared Patchright Chromium browser cache in the background. On the first tool call that needs authentication, the server reuses a LinkedIn session from a signed-in local browser if it finds one, and otherwise opens a LinkedIn login browser window.

NOTE

Early tool calls may return a setup/authentication-in-progress error until browser setup or login finishes. Retry the tool call once the browser download or sign-in completes.

Setup Help

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

  • The browser cache keeps growing: Patchright keeps an old Chromium revision for as long as any installed version still references it, so an upgrade can leave both on disk. The server logs a warning naming what it holds. To reclaim the space, stop every LinkedIn MCP Server instance, delete ~/.linkedin-mcp/patchright-browsers/, and let the next launch download the current browser.

  • Windows, the bundle exits with DLL load failed while importing _greenlet: install the Microsoft Visual C++ Redistributable, or reinstall a bundle pinning greenlet 3.5.5 or newer, whose published Windows wheels carry the C++ runtime inside the extension again. A bundle pinning greenlet 3.3.1 through 3.5.4 needs MSVCP140.dll from that redistributable, which neither the python.org installer nor the uv-managed builds carry, and a greenlet built from source can need it at any version. The server names this itself on startup, and only after checking that the loader cannot produce that DLL. Reported as greenlet#525, fixed in greenlet#526.

  • 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 linkbridge-mcp@latest --login which opens a browser where you can solve captchas manually. See the uvx setup for prerequisites.

  • 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, or use the explicit Docker --login --login-viewer command.

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

  • Set Chrome executable in the extension's settings to a Chrome, Chromium or Chrome for Testing binary, such as /usr/bin/google-chrome. Leave it blank to keep the bundled Chromium. It sets CHROME_PATH, described under Custom Chrome path in the uvx setup help.

  • This is the fix when tool calls refuse to open the profile because a newer browser last opened it: point the setting at that newer browser instead of signing in again.

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

Codex Plugin

Prerequisites: Codex and uv.

Installation

Run in a terminal

codex plugin marketplace add stickerdaniel/linkedin-mcp-server
codex plugin add linkedin-mcp-server@linkedin-mcp-server

The plugin runs the latest server release. On the first tool call that needs authentication, the server reuses a LinkedIn session from a signed-in local browser or opens a login window.

NOTE

Early tool calls may return a setup/authentication-in-progress error until browser setup or login finishes. Retry the tool call once the browser download or sign-in completes.

Claude Code Plugin

Prerequisites: Claude Code and uv.

Installation

Run in a terminal

claude plugin marketplace add stickerdaniel/linkedin-mcp-server
claude plugin install linkedin-mcp-server@linkedin-mcp-server

The plugin runs the latest server release. On the first tool call that needs authentication, the server reuses a LinkedIn session from a signed-in local browser or opens a login window.

NOTE

Early tool calls may return a setup/authentication-in-progress error until browser setup or login finishes. Retry the tool call once the browser download or sign-in completes.

Cursor Plugin

Prerequisites: Cursor and uv on your PATH.

Installation

From the Cursor Marketplace: open Customize in the sidebar, search for LinkedIn MCP, and choose Install. The plugin bundles the LinkedIn skill.

One-click MCP install (server only, without the skill):

Add to Cursor

Both run the latest server release. On the first tool call that needs authentication, the server reuses a LinkedIn session from a signed-in local browser or opens a login window.

NOTE

Early tool calls may return a setup/authentication-in-progress error until browser setup or login finishes. Retry the tool call once the browser download or sign-in completes.

Setup with Docker

Prerequisites: Make sure Docker is installed and running.

Authentication

Log in once. The container opens a LinkedIn login browser that you drive from your own browser tab.

macOS / Linux:

# Create the directory first so the container can save your session into it
mkdir -p ~/.linkedin-mcp
docker run -it --rm \
  -v ~/.linkedin-mcp:/home/pwuser/.linkedin-mcp \
  -p 127.0.0.1:6080:6080 \
  stickerdaniel/linkedin-mcp-server:latest \
  --login --login-viewer

PowerShell (Windows):

$sessionDir = Join-Path $env:USERPROFILE ".linkedin-mcp"
New-Item -ItemType Directory -Force -Path $sessionDir | Out-Null
docker run -it --rm `
  -v "${sessionDir}:/home/pwuser/.linkedin-mcp" `
  -p 127.0.0.1:6080:6080 `
  stickerdaniel/linkedin-mcp-server:latest `
  --login --login-viewer

Open the full URL the command prints (it carries the access token) and sign in. Ctrl+V (Cmd+V on a Mac) pastes plain ASCII text, such as a password from your password manager, into the login browser. The viewer closes itself afterwards; let the command exit on its own so the session is stored completely. It gives up after 30 minutes.

Keep the same host directory mounted at /home/pwuser/.linkedin-mcp on every later docker run, otherwise the server cannot find the session.

Add to your MCP client's mcpServers configuration

macOS / Linux (absolute path in JSON):

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

Spell that first path out in full. A client runs docker directly rather than through a shell, so a leading ~ reaches Docker unexpanded and it refuses the mount.

PowerShell (Windows): use a forward-slash JSON path. A backslash path like C:\Users\Alice\.linkedin-mcp fails JSON parsing because \U is an invalid escape. Use C:/Users/Alice/.linkedin-mcp instead, replacing Alice with your username.

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

In PowerShell,~ is not expanded inside a composite Docker -v argument. Use C:/Users/<you>/.linkedin-mcp or build the path with $env:USERPROFILE\.linkedin-mcp before passing it to Docker.

NOTE

Sessions expire over time. When tool calls start asking for authentication, repeat the login command above, or runuvx linkbridge-mcp@latest --login on the host.

Setup Help

  • 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

Session:

  • --auto-import / --no-auto-import - Import a session from a signed-in local browser on the first tool call that needs one, before falling back to manual login (ignored in Docker). On macOS the keychain may prompt once.

  • --logout - Clear the stored session and every profile derived from it

  • --login-viewer - With --login, show the login browser at a token-protected URL on port 6080. Needs the profile mount from Authentication.

  • --user-data-dir PATH - Browser profile directory (default: ~/.linkedin-mcp/profile). Rotating or clearing a session deletes this directory and its parent, which holds the stored cookies and derived profiles.

  • --claim-profile-root - Take over a profile directory the server will not claim on its own, such as one whose parent already holds other files. Needed once per directory.

Transport:

  • --transport {stdio,streamable-http} - Force the transport mode (default: stdio)

  • --host HOST / --port PORT / --path PATH - HTTP server address (defaults: 127.0.0.1, 8000, /mcp)

Timeouts:

  • --timeout MS - Timeout for a single page operation (default: 5000)

  • --tool-timeout SECONDS - Timeout for a whole tool call (default: 180). Raise it for calls that read many pages, slow networks, or a cold-start browser.

  • --login-timeout SECONDS - How long the login browser waits for you to finish signing in (default: 1800; 0 = no limit). --login-viewer ends the session after 30 minutes either way.

  • --login-inline-wait SECONDS - How long a tool call waits for a login to finish before telling the model to retry (default: 25, max 45; 0 = return at once)

Shared browser:

  • --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 with several MCP clients running at once.

  • --browser-min-hold SECONDS - Shortest time this process keeps the shared browser before handing it over (default: 20). Clamped to 3 seconds below --browser-wait, so raise that one along with it. Higher means fewer browser restarts but longer waits for other clients.

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

Browser:

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

  • --proxy-server URL - Route browser traffic through a proxy, as scheme://host:port. Set it up before --login; see Using a proxy.

Other:

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

NOTE

Plain--login still has no visible window in Docker. Add --login-viewer and publish 127.0.0.1:6080:6080 only for the one-shot login command. Docker is already headed by default, so --no-headless changes nothing. The experimental --daemon is ignored in Docker because its owner can outlive the virtual display.

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

Bash / macOS / Linux:

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

PowerShell (Windows):

$sessionDir = Join-Path $env:USERPROFILE ".linkedin-mcp"
docker run -it --rm `
  -v "${sessionDir}:/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

  • Make sure Docker is installed

  • Check if Docker is running: docker ps

  • Permission errors on ~/.linkedin-mcp: an older rootful Docker run may have created the directory as root. Fix it with sudo chown -R "$(id -u):$(id -g)" ~/.linkedin-mcp.

  • 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 linkbridge-mcp@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.

  • 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, or use the explicit Docker --login --login-viewer command.

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

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

  • 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

  • On macOS and Linux the browser must be at least as new as the one that last opened your profile, and the server refuses the launch otherwise. (Not on Windows: a browser there cannot be asked its version without starting one, so the check is off.) An older browser can silently drop stores a newer one wrote, the saved session among them, and the failure then looks exactly like an expired login. The message names both versions. Going back to the bundled Chromium after running a newer Chrome once is the usual way to meet this; either run the newer browser again, whichever one that was, or run --login, which moves the stored session aside and signs in fresh with the browser you have. --logout also clears it but discards the old session instead of keeping it recoverable, and it asks for confirmation on the terminal, so it is not usable from a server an MCP client started.

  • Only Chrome, Chromium and Chrome for Testing are compared this way. Forks number themselves differently (Vivaldi is on 7.x, Edge's build number sits far below Chrome's under the same major), so pointing CHROME_PATH at one turns the check off rather than producing a refusal nothing could satisfy.

  • In the documented Docker setup this check does not apply. The container never opens the profile you created with --login; it derives its own from your cookies, and by default rebuilds that from scratch on every start, so there is nothing for an older image to downgrade. With EXPERIMENTAL_PERSIST_DERIVED_RUNTIME the derived profile is kept, and an image tag that moves backwards then throws it away and re-derives it, again with nothing for you to do. The check matters on the host, where the server opens that profile directly. Not during --login itself, which moves the old profile aside before it starts a browser and so can never trip it.

Using a proxy

LinkedIn scores the address a session signs in from. Your account's usual IP address is the safe one. You should use a proxy in your country when the server cannot use it: a VPS, another country, or a second account that must not share the first one's address.

With a paid provider, use a sticky residential session that holds one address (never per-request rotation). A WireGuard full tunnel or Tailscale exit node on your home network works when the server should use your usual home address.

Setup Help

  • Set the proxy up before --login. Moving an existing session to a new address triggers a LinkedIn checkpoint. That includes a session from --import-from-browser, which was created on your real address.

  • --proxy-server scheme://host:port or PROXY_SERVER, with http, https, socks4 or socks5. Only browser traffic is routed, not the MCP transport.

  • Pass credentials through PROXY_USERNAME and PROXY_PASSWORD, or include them in PROXY_SERVER using the combined http://user:pass@host:port form. The combined form is not accepted by the --proxy-server CLI option.

  • PROXY_BYPASS=localhost,127.0.0.1,::1 reaches local targets directly. With a proxy set, Chromium routes localhost through it too.

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

  • A wrong proxy password shows up as a timeout or a failed sign-in, because Chromium retries the authentication challenge until the page times out. If sessions stop working right after you add a proxy, check the proxy credentials first.

  • Auto-import is skipped while a proxy is configured: the imported session would move from your real address to the proxy. Use --login.

  • Inside a container 127.0.0.1 is the container itself, so a relay on the host is host.docker.internal; native Linux Docker also needs --add-host=host.docker.internal:host-gateway.

Setup from Source (Develop & Contribute)

Contributions are welcome. See CONTRIBUTING.md for architecture guidelines and checklists. Search existing issues first, then use the issue forms for anything new. AI agents follow the issue-packet skill.

Prerequisites: Git and uv installed

Installation

Run in a terminal

# 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

Setup Help

Session:

  • --login - Open a browser to sign in and save the session

  • --import-from-browser [BROWSER] - Reuse a session from a locally signed-in Chromium browser (chrome, chromium, brave, edge, arc, vivaldi, helium, yandex, whale, coccoc, opera, opera_gx, auto). Bare flag picks auto, the most recently used browser with a live LinkedIn session.

  • --auto-import / --no-auto-import - Import a session from a signed-in local browser on the first tool call that needs one, before falling back to manual login (default: on). Skipped in Docker, behind a proxy, and on a non-loopback HTTP bind. On macOS the keychain may prompt once.

  • --status - Check whether the stored session is valid, then exit

  • --logout - Clear the stored session

  • --user-data-dir PATH - Browser profile directory (default: ~/.linkedin-mcp/profile). Rotating or clearing a session deletes this directory and its parent, which holds the stored cookies and derived profiles.

  • --claim-profile-root - Take over a profile directory the server will not claim on its own, such as one whose parent already holds other files. Needed once per directory.

Transport:

  • --transport {stdio,streamable-http} - Force the transport mode (default: stdio)

  • --host HOST / --port PORT / --path PATH - HTTP server address (defaults: 127.0.0.1, 8000, /mcp)

Timeouts:

  • --timeout MS - Timeout for a single page operation (default: 5000)

  • --tool-timeout SECONDS - Timeout for a whole tool call (default: 180). Raise it for calls that read many pages, slow networks, or a cold-start browser.

  • --login-timeout SECONDS - How long the login browser waits for you to finish signing in (default: 1800; 0 = no limit). --login-viewer ends the session after 30 minutes either way.

  • --login-inline-wait SECONDS - How long a tool call waits for a login to finish before telling the model to retry (default: 25, max 45; 0 = return at once)

Shared browser:

  • --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 with several MCP clients running at once.

  • --browser-min-hold SECONDS - Shortest time this process keeps the shared browser before handing it over (default: 20). Clamped to 3 seconds below --browser-wait, so raise that one along with it. Higher means fewer browser restarts but longer waits for other clients.

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

Browser:

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

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

  • --viewport WxH - Viewport size (default: 1280x720). Applies to windowless mode only; a headed launch uses the real window size.

  • --chrome-path PATH - Path to a Chrome/Chromium executable

  • --installer-temp-dir PATH - Existing directory for browser installation temporary files (environment: INSTALLER_TEMP_DIR).

  • --proxy-server URL - Route browser traffic through a proxy, as scheme://host:port. Set it up before --login; see Using a proxy.

Other:

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

  • --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": {
    "linkbridge-mcp": {
      "command": "uv",
      "args": ["--directory", "/path/to/linkedin-mcp-server", "run", "-m", "linkedin_mcp_server"]
    }
  }
}

stdio is used by default for this config.

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

  • Use --no-headless to watch the browser when a tool returns wrong or missing data

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

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

  • Managed browser downloads are cached at ~/.linkedin-mcp/patchright-browsers/, shared with the uvx and MCP Bundle installations

  • The browser cache keeps growing: Patchright keeps an old Chromium revision for as long as any installed version still references it, and a uv archive or a second worktree is such a reference. The server logs a warning naming what it holds. To reclaim the space, stop every LinkedIn MCP Server instance, delete ~/.linkedin-mcp/patchright-browsers/, and let the next launch download the current browser.

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

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

  • Reinstall Patchright: uv run patchright install chromium

  • Reinstall dependencies: uv sync --reinstall

  • 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, or use the explicit Docker --login --login-viewer command.

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

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

  • 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

  • On macOS and Linux the browser must be at least as new as the one that last opened your profile, and the server refuses the launch otherwise. (Not on Windows: a browser there cannot be asked its version without starting one, so the check is off.) An older browser can silently drop stores a newer one wrote, the saved session among them, and the failure then looks exactly like an expired login. The message names both versions. Going back to the bundled Chromium after running a newer Chrome once is the usual way to meet this; either run the newer browser again, whichever one that was, or run --login, which moves the stored session aside and signs in fresh with the browser you have. --logout also clears it but discards the old session instead of keeping it recoverable, and it asks for confirmation on the terminal, so it is not usable from a server an MCP client started.

  • Only Chrome, Chromium and Chrome for Testing are compared this way. Forks number themselves differently (Vivaldi is on 7.x, Edge's build number sits far below Chrome's under the same major), so pointing CHROME_PATH at one turns the check off rather than producing a refusal nothing could satisfy.

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.

Contributors

Thanks to everyone who has contributed code, bug reports and fixes.

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.

Building on this project is welcome! See the license for terms and the NOTICE for attribution.

Available Tools

25 tools
archive_conversationArchive ConversationA
Idempotent

Archive one LinkedIn messaging thread, InMail included, by thread ID.

Opens the thread, which marks it read, and chooses Archive from its options menu. A thread LinkedIn already files as archived is left alone and reported already_archived, so a repeated call clicks nothing. The change is confirmed by loading the thread again. Reversible on LinkedIn; a new message moves the thread back to the inbox.

NameRequiredDescriptionDefault
thread_idYesLinkedIn messaging thread ID, as get_inbox, search_conversations or get_conversation return it

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior5/5

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

Beyond the annotations (which only declare non-readonly, idempotent, non-destructive, open-world), the description discloses a non-obvious side effect — opening the thread marks it read — plus the idempotency mechanism, post-action verification by reloading the thread, reversibility, and the fact that a new message returns the thread to the inbox. This is exactly the behavioral context an agent needs before mutating state.

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 action and target are front-loaded in the first sentence, followed by mechanics, idempotency, verification, and reversibility in that order. There is no filler; every sentence contributes operational 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?

For a one-parameter mutation tool with annotations and an output schema, the description covers the preconditions (thread ID), the side effect (marked read), the outcome (already_archived), and reversibility. Return-value details are unnecessary because an output schema exists.

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 single thread_id parameter is already documented with its source tools (get_inbox, search_conversations, get_conversation). The description adds only 'by thread ID', which restates the schema rather than extending it — baseline 3 for a fully documented single parameter.

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 opening sentence names a specific verb and resource — 'Archive one LinkedIn messaging thread, InMail included, by thread ID' — and scopes it to a single thread. An agent can distinguish it from get_inbox, get_conversation, and search_conversations without consulting the schema.

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 gives clear operational context: repeated calls on already-archived threads click nothing and return already_archived. It does not explicitly name which sibling to use instead when the goal is reading (get_conversation) or replying (reply_to_conversation), so routing is implied rather than spelled out.

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

close_sessionClose SessionA
Destructive

Close the current browser session and clean up resources.

NameRequiredDescriptionDefault

No parameters

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior3/5

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

The destructiveHint annotation already signals this is a destructive action, and the description confirms it by saying 'Close' and 'clean up resources'. It adds some scope detail ('current browser session') but does not describe side effects such as invalidating cookies, logging out the user, or making the session unusable. Since the annotations carry much of the safety signal, a mid-range 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 entire description is a single, front-loaded sentence with no redundant words. It states the action and consequence efficiently, earning a top score 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?

For a zero-parameter, destructive tool with an output schema and annotation coverage, the description is complete enough for an agent to know what will happen. The absence of an alternative, zero parameters, and existing destructiveHint mean no additional operational context is essential.

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 and the schema is empty with 100% coverage, so there are no parameter semantics for the description to clarify. With no params, the baseline is 4, and the description does not need to add parameter-level explanation.

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 ('Close') and names the resource ('current browser session') plus a clear secondary purpose ('clean up resources'). It is well-distinguished from all sibling tools, which focus on profiles, searches, messaging, and feed actions, not session lifecycle.

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 that this tool ends the current browser session, implying it should be used when the session is no longer needed. There are no sibling tools providing an alternative session-close action, so explicit exclusions are unnecessary. A fully explicit 'use this when you are done' statement would improve clarity, but the context is already strong.

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.

NameRequiredDescriptionDefault
noteNoOptional note to include with the invitation
linkedin_usernameYesLinkedIn username (e.g., "stickerdaniel", "williamhgates"). A full profile URL is accepted too and is reduced to the username.

Output Schema

NameRequiredDescription

No output parameters

TDQS

A3.7/5.0
Behavior2/5

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

The description mostly restates the destructiveHint annotation by saying MCP clients will prompt for confirmation. It does not add meaningful behavioral context beyond that, such as irreversibility, notification to the recipient, authentication requirements, or rate-limit implications.

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 short and front-loaded with the primary action. The second sentence about destructiveHint is slightly redundant with the annotations, but it communicates the user-confirmation behavior clearly and does not add much bulk.

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?

With two well-documented parameters and an output schema present, the description is mostly sufficient for invoking the tool correctly. It lacks explicit guidance on when to accept versus send, or on side effects, but these are not critical given the schema and annotations.

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 parameter docs already explain linkedin_username and note in detail. The description adds no additional parameter-level meaning beyond what the schema provides.

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 specific action: send or accept a LinkedIn connection request. It names the exact resource and distinguishes it from sibling tools like send_message 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?

The description makes it clear this tool handles connection requests and acceptances, which provides usable context for when to choose it. It does not explicitly name alternatives or exclusions, but the action is specific enough to avoid major ambiguity.

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

dismiss_jobDismiss JobA
DestructiveIdempotent

Dismiss a job from LinkedIn job search so later searches never show it.

For jobs already applied to or rejected. Reads the job's title and company from its posting, clicks the dismiss button on its card in a worldwide search for them, then reloads that search to confirm the job is gone. Irreversible: LinkedIn offers no undo after a reload. A job that search does not list on its first page is an error, since an already dismissed job and a search that missed it look the same.

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

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior5/5

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

Annotations already flag destructiveHint and openWorldHint, but the description adds substantial context beyond them: the mechanism (read title/company, click dismiss on the card, reload to confirm), the irreversibility ('LinkedIn offers no undo after a reload'), and the ambiguous-error case. This is exactly the operational detail an agent needs before a destructive call.

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?

Front-loads the purpose, then mechanism, then irreversibility, then error semantics — a sensible ordering with no filler. The middle sentence describing the click sequence is slightly verbose but carries real behavioral value.

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?

An output schema exists, so return values need no explanation, and the description still covers preconditions, irreversibility, and failure modes for a one-parameter destructive tool. Nothing an agent needs to call it safely is missing.

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% and the single job_id parameter is documented with format examples there, so the description does not need to explain it. The description adds no meaning about the parameter itself, which is the expected baseline when the schema does the work.

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?

Names a specific verb and resource (dismiss a job) plus the exact effect ('so later searches never show it'), which separates it cleanly from siblings like search_jobs, get_saved_jobs, and get_job_details. An agent can route to it without opening the schema.

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

Usage Guidelines4/5

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

Explicitly scopes the tool to 'jobs already applied to or rejected', which is real when-to-use guidance, and adds an error condition for jobs not found on the first page. It stops short of naming sibling alternatives, so it is strong context rather than a full routing rule.

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.

NameRequiredDescriptionDefault
keywordsNoOptional filter by name, job title, or skill (e.g., "engineer", "sales")
company_nameYesLinkedIn company URL slug (e.g., "docker", "anthropicresearch", "microsoft"). A full company URL is accepted too and is reduced to the slug.

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior4/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. It adds meaningful behavioral context: the data comes from the /people/ page, demographics are unique to this view, and the company_name must be the exact URL slug, not the display name, with a concrete example. This goes beyond annotations without contradicting 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 moderately long but every sentence earns its place: core purpose first, then usage routing, then keyword semantics, then the critical slug caveat. The Anthropic example is concrete and high-value, not filler. Structure is logical and 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 output schema exists, annotations cover safety, and the description covers purpose, routing, param semantics, and a caveat with an example, the definition is complete for an agent to select and invoke the tool correctly. No critical gap is evident.

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?

Schema coverage is 100%, but the description adds substantial semantic value beyond the schema. It clarifies that company_name must be the exact LinkedIn URL slug, warns that display names often differ, gives the Anthropic example, and tells the agent to resolve ambiguity via search_companies. This is exactly the kind of parameter nuance that prevents incorrect calls.

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 'List employees at a company from the LinkedIn /people/ page' and uniquely identifies its value-add: the demographics aggregate (location, education, function breakdown). It distinguishes itself from siblings by noting these demographics are unique to this tool, so an agent can immediately tell it apart from search_people or get_company_profile.

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

Usage Guidelines5/5

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

Explicit guidance is provided for when to use this tool vs alternatives: for filtered search by network degree or location, prefer search_people with current_company set. It even notes search_people returns more result pages, and instructs the agent to call search_companies first if the slug is uncertain. This is strong, actionable routing guidance.

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 PostsC
Read-only

Get recent posts from a company's LinkedIn feed.

NameRequiredDescriptionDefault
max_scrollsNoMaximum scroll-to-bottom iterations to load more posts. Default (None) uses 10. Increase to read further back in the feed.
company_nameYesLinkedIn company name (e.g., "docker", "anthropic", "microsoft"). A full company URL is accepted too and is reduced to the slug.

Output 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 covered. The description adds only the vague word 'recent' and says nothing about needing an active session (implied by the close_session sibling), how far back the feed is read, or how results are ordered — despite a scroll-budget parameter existing.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

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

A single tight sentence with no wasted words and the resource front-loaded. It is efficient, though its brevity is closer to under-specification than to optimal information density.

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?

An output schema exists, so return values need not be explained. However, for a session-based scraping tool the description omits the prerequisites (active session) and the sibling-routing context an agent needs, leaving it only minimally viable.

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%: company_name and max_scrolls are both fully documented in the schema, including the default of 10 scrolls and URL-to-slug reduction. The description adds no parameter meaning beyond that, so the baseline of 3 applies.

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?

States a specific verb and resource ('Get recent posts') and scopes it to 'a company's LinkedIn feed', which implicitly separates it from the personal-feed and search siblings. It does not, however, name get_feed or search_posts explicitly, so the differentiation must be inferred.

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 gives no when-to-use guidance at all. With siblings get_feed and search_posts present, an agent is left to guess whether this is the right tool for reading a company's activity versus searching or reading its own feed.

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.

NameRequiredDescriptionDefault
sectionsNoComma-separated list of extra sections to read. The about page is always included. Available sections: posts, jobs Examples: "posts", "posts,jobs" Default (None) reads only the about page.
company_nameYesLinkedIn company name (e.g., "docker", "anthropic", "microsoft"). A full company URL is accepted too and is reduced to the slug.

Output 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 covered. The description adds nothing beyond that: it doesn't note authentication/scope requirements, rate limits, or the fact that requesting `sections` changes cost/behavior. With annotations present the bar is lower, but this description contributes essentially no extra behavioral context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

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

A single front-loaded sentence with zero waste. It is appropriately sized, though its brevity comes at the cost of substance rather than being maximally informative.

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?

Annotations and an output schema carry the return-value and safety burden, so much is delegated. However, for a tool with multiple overlapping company siblings, the description is too thin to help an agent route correctly, leaving a real gap in sibling differentiation.

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 both parameters are already fully documented in the schema, including the `sections` enum-like values and default. The description adds no syntax or format detail beyond the schema, so the baseline of 3 applies.

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 states a specific verb (get) and resource (a company's LinkedIn profile), making the core action unambiguous. It distinguishes the target as a company rather than a person, but does not differentiate from close siblings like get_company_posts, get_company_employees, or search_companies.

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?

There is no guidance on when to use this tool versus alternatives such as search_companies or get_company_employees. No prerequisites, no exclusions, and no mention of when the extra `sections` should be requested are provided.

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.

Username resolution scans matching rows from a requested compose page first. Its indexable sequence ends before the first unresolved click, missing matching click target, or admitted row that fails the existing exact display-name check. An index outside that verified prefix is refused with its reason. Search is a fallback only when the inbox scan has no observed matching result and no such barrier; it never substitutes a result after a stopped or gapped inbox scan. Pass a known thread_id to bypass username/index resolution.

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; a full profile URL is accepted too

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.2/5.0
Behavior5/5

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

With only openWorldHint in annotations, the description carries the behavioral burden and does so well: it discloses that username resolution click-visits each row and 'may mark it as read' (a real side effect), describes the indexable-prefix limits, the refusal behavior for out-of-prefix indexes, and that search is only a fallback. This is exactly the kind of non-obvious operational context structured fields cannot convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

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

Purpose and the two lookup paths are front-loaded, which is good, but the middle paragraphs are dense and hard to parse (e.g. 'indexable sequence ends before the first unresolved click, missing matching click target, or admitted row'), and the LinkedIn-sidebar implementation rationale is arguably more internal detail than an agent needs. It is informative but not tight.

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?

An output schema exists so return values need not be described, and the description still covers resolution paths, side effects, failure/refusal conditions, and fallback ordering. For a 3-param read tool with light annotations, nothing material an agent needs to call it correctly is missing.

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

Parameters4/5

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

Schema coverage is 100%, so the baseline is 3, but the description adds genuine meaning: it explains the index resolution semantics, the prefix barrier that causes an index to be refused, and that a known thread_id bypasses resolution entirely. This goes beyond the schema's terse per-field notes.

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?

States a specific verb and resource ('Read a specific messaging conversation') and immediately specifies the two identification paths, which cleanly separates it from get_inbox (list) and search_conversations (search). It does not name those siblings explicitly, so the differentiation is implied rather than stated.

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?

Gives concrete guidance on when to use linkedin_username vs thread_id ('Pass thread_id directly to skip this enumeration') and points to search_conversations for enumerating thread IDs. It stops short of an explicit when-not-to-use or a direct contrast with get_inbox, so it is clear context without full routing.

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

get_easy_apply_formGet Easy Apply FormA
Idempotent

Read the questions of a job posting's Easy Apply form, without answering them.

Opens Easy Apply and reads each step: every field's label, type, whether it is required, its options, character limit and prefilled value. Next is clicked only while LinkedIn accepts a step on its prefilled values, so the first step that needs input ends the read. Nothing is typed, Review and Submit are never clicked, and the dialog is closed with its draft discarded.

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

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior5/5

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

The description explains the otherwise puzzling readOnlyHint=false annotation: it opens the Easy Apply dialog and clicks Next while prefilled values are accepted, which is why it is not read-only. It further discloses that nothing is typed, Review and Submit are never clicked, and the dialog is closed with the draft discarded, plus the truncation rule (first step needing input ends the read) — all behavior not derivable from 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?

Front-loaded with the core action and scope in the first sentence, then a structured walkthrough of what is read and what is never done. It is slightly long for a single-parameter read tool and the 'Next is clicked only while…' sentence is dense, but nearly every clause carries behavioral information.

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

Completeness4/5

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

With an output schema present, the description need not describe return values, and it covers the process, its stopping condition, and its side effects well. It is only marginally incomplete in not saying what happens when the posting has no Easy Apply form or how failures surface.

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% and the single job_id parameter is documented in the schema with examples, so the description adds no parameter-level meaning. Baseline 3 applies; nothing here compensates for or extends 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?

States a specific verb and resource ('Read the questions of a job posting's Easy Apply form') and immediately delimits scope with 'without answering them'. This clearly separates it from siblings like get_job_details and get_job_apply_url, which an agent could otherwise confuse with a form-reading tool.

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 'without answering them' clause and the note that the read stops at the first step needing input tell the agent exactly when this tool is applicable (inspection-only). It does not, however, explicitly name an alternative for the case where the agent actually needs to submit an application, so the routing is implied rather than spelled out.

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.

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

NameRequiredDescription

No output parameters

TDQS

A3.7/5.0
Behavior2/5

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

The description does not disclose behavioral traits beyond the annotations: it only says 'Get posts', which is consistent with readOnlyHint=true but adds no new behavioral context. Notable behavior like batched loading and count overshooting appears only in the schema property description, not in the tool description.

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 short sentence with no filler, front-loading the action and resource. It is concise without sacrificing clarity.

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 feed fetch with one optional parameter and an output schema, the description plus schema provide all necessary information. The feed scope is clear, and nothing critical is missing.

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 the num_posts parameter fully documented including default, range, and batch behavior. The tool description itself adds no parameter detail, but the schema already carries the full semantic burden, 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?

States a specific verb 'Get' and a specific resource 'posts from the authenticated user's LinkedIn feed', which clearly distinguishes it from sibling tools like get_company_posts and search_posts. The phrase 'authenticated user' pins the scope unambiguously.

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 intended use — fetching the current user's LinkedIn feed — is reasonably implied by the description, but there is no explicit guidance about when to choose this over alternative tools such as search_posts or get_company_posts. No exclusions or routing hints are provided.

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

get_inboxGet InboxC
Read-only

List recent conversations from the LinkedIn messaging inbox.

The returned inbox text and result URL come from the ordinary messaging inbox. Click-derived conversation references are collected separately after requesting the compose page, which avoided inbox auto-opening on the measured variant. A row contributes a click-derived reference only after its click is followed by an observed different thread path. The scan stops at its first unverifiable click. section_errors.inbox reports that stop or unavailable scan rows; captured inbox text and independently extracted anchors retain their normal handling. A known thread_id can bypass row attribution when calling get_conversation.

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

Output Schema

NameRequiredDescription

No output parameters

TDQS

C2.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 safety profile is covered. The description does add behavioral context (scan can stop, section_errors.inbox reports that stop, captured text is retained), but it is buried in scraped-page implementation jargon rather than stated as caller-relevant behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

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

The first sentence is well front-loaded, but the remaining three-to-four sentences dwell on internal scraping mechanics (compose page, measured variant, click-derived references, scan stopping) that a caller does not need. Significant bloat for a one-parameter read tool.

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?

An output schema exists, so return values need not be spelled out, and for a single-parameter read tool the definition is more than long enough. However, it spends its length on implementation detail while omitting the one thing an agent needs: how this tool relates to search_conversations and get_conversation.

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?

Only one parameter (limit) exists and schema coverage is 100%, including range and default, so the schema carries the full burden. The description adds nothing about the limit semantics, matching the baseline for a fully documented schema.

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 opening sentence gives a clear verb+resource ('List recent conversations from the LinkedIn messaging inbox'), so the agent immediately knows what the tool returns. It does not distinguish itself from the siblings search_conversations or get_conversation, which list/fetch similar data, so it stops short of a 5.

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?

There is no statement of when to use this tool versus search_conversations or get_conversation. The only routing hint is an oblique trailing remark that 'a known thread_id can bypass row attribution when calling get_conversation,' which is not framed as guidance a caller can act on.

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

get_job_apply_urlGet Job Apply URLA
Read-only

Get how a job posting takes applications, and the employer's application link.

Reads the posting without clicking anything.

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

Output Schema

NameRequiredDescription

No output parameters

TDQS

A3.7/5.0
Behavior4/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 genuinely useful context beyond that: it clarifies the call inspects the posting without triggering any click/navigation or application flow, which tells the agent there are no side effects on the employer's page.

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?

Two short sentences, front-loaded with the core purpose and followed by the behavioral qualifier. No filler or redundancy, though the second sentence is a minor stylistic flourish rather than essential information.

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

Completeness4/5

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

An output schema exists, so return values need no explanation, and the single required parameter is fully documented in the schema. For a one-param read tool this is largely complete; only cross-tool routing guidance is missing.

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 a single job_id parameter, so the schema already carries the semantics. The description adds nothing about the identifier format or expected values, so baseline 3 applies.

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 names a specific verb (Get) and resource (how a job posting takes applications / the employer's application link), which is more precise than the bare title. It implicitly distinguishes itself from the sibling apply_to_job by describing retrieval of the application method rather than performing the application, though it never names that sibling explicitly.

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

Usage Guidelines3/5

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

Usage is only implied: an agent can infer this is a preview step before applying, but there is no explicit when-to-use, when-not-to-use, or comparison against get_job_details or apply_to_job. 'Reads the posting without clicking anything' hints at the read-only context but does not route the agent between tools.

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.

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

Output 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=true and openWorldHint=true, so the description does not need to restate basic safety. The description adds no meaningful behavioral context beyond the annotations, such as what kind of details are returned or whether the job must be publicly accessible. It is consistent with the annotations, so 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?

The description is one short sentence with no filler. It front-loads the action and resource, and 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 simplicity—one parameter, full schema coverage, output schema present, and read-only annotations—the description is nearly complete. The only minor gap is lack of explicit guidance on when to choose this over search_jobs, but the 'specific job posting' wording covers the core usage context.

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% coverage for the single parameter, including an example format for job_id. The description does not add additional parameter meaning beyond what the schema already provides, but with full schema coverage the 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 the action ('Get'), the resource ('job details'), and the scope ('for a specific job posting on LinkedIn'). It distinguishes itself from sibling tools like search_jobs and get_saved_jobs by emphasizing a specific job ID rather than searching or listing.

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 phrase 'for a specific job posting' implies this tool should be used when you already have a job_id and need details, as opposed to searching for jobs. However, it does not explicitly state when not to use it or name alternative tools.

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 reading the profile, so the url field in the result is the actual profile URL (e.g. linkedin.com/in/johndoe/) rather than /in/me/.

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

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4/5.0
Behavior4/5

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

Beyond the readOnlyHint/openWorldHint annotations, the description discloses a non-obvious implementation trait: it navigates to /in/me/ and resolves a redirect so the returned url is the real profile URL. That is genuinely useful context an agent could not infer from schema or annotations. It stops short of mentioning rate limits, login/session prerequisites, or cost of the extra navigation.

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 short sentences, front-loaded with the purpose and followed by the one behavioral nuance that matters. No filler or repetition of schema content.

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?

With an output schema present, return values need not be explained, and annotations cover the safety profile. The redirect-resolution note fills the main gap; only the relationship to get_person_profile (and any session precondition) is left implicit.

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%, with sections and max_scrolls fully documented in the schema, including enum-like section names and a reference to get_person_profile semantics. The description adds no parameter information, so the baseline 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?

States a specific verb and resource ('Get the authenticated user's own LinkedIn profile') and scopes it to the authenticated user, which cleanly separates it from the sibling get_person_profile that targets arbitrary people. An agent can select this without opening the schema.

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

Usage Guidelines3/5

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

Usage is implied by 'the authenticated user's own profile', which suggests when to prefer this over get_person_profile, but the description never names that sibling or states an explicit when-to-use/when-not-to-use rule. Nothing tells the agent whether to use this first as a session/anchor step.

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 ProfileC
Read-only

Get a specific person's LinkedIn profile.

NameRequiredDescriptionDefault
sectionsNoComma-separated list of extra sections to read. The main profile page is always included. Available sections: experience, education, interests, honors, volunteering, languages, certifications, skills, projects, contact_info, posts Examples: "experience,education", "contact_info", "skills,projects", "honors,languages", "posts" Default (None) reads 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"). A full profile URL is accepted too and is reduced to the username.

Output 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 covered. Beyond that, the description adds nothing: no mention of authentication requirements, rate limiting or scraping throttling, behavior for nonexistent or private profiles, or cost of requesting heavy sections. The pagination guidance lives in the schema, not the description.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

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

A single front-loaded sentence with zero filler. It is efficient, though its brevity borders on under-specification given the tool's scraping behavior.

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?

An output schema exists and parameters are fully documented, so return values needn't be explained. However, for an open-world scraping tool the description omits failure modes (invalid username, private profile, rate limits) that an agent would need to plan around.

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 detailed documentation of sections, max_scrolls, and linkedin_username, so the baseline is 3. The description contributes no additional parameter meaning, such as when to prefer a separate call for heavy sections, though the schema itself already states that.

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?

States a specific verb and resource ("Get a specific person's LinkedIn profile"), which distinguishes it implicitly from siblings like get_my_profile, search_people, and get_company_profile. It does not explicitly name or contrast with those siblings, so it stops short of a 5.

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 gives no when-to-use guidance, no prerequisites, and no alternatives. An agent must infer from sibling names that search_people finds usernames first and get_my_profile covers the authenticated user's own profile.

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 the authenticated user's jobs at one stage of LinkedIn's job tracker.

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

NameRequiredDescriptionDefault
stageNoTracker tab: saved (default), in_progress, applied or archived. applied lists Easy Apply submissions and external applications the user confirmed to LinkedIn.saved
max_pagesNoMaximum number of tracker pages to load (1-10, default 3)

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4/5.0
Behavior3/5

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

The readOnlyHint and openWorldHint annotations already establish that this is a safe read against external LinkedIn data. The description adds useful relational behavior (the returned job_ids are meant to feed get_job_details), but says nothing about ordering, page budget effects, or what an empty result means for a user with no jobs in that stage.

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 short sentences, front-loaded with what it returns and followed by the actionable next step. Nothing is redundant or padded.

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 two-parameter read-only lister with a full schema and an output schema, this covers purpose, scope and follow-up. The only gap is not hinting at pagination/truncation behavior implied by max_pages, which matters if the agent must page through a large tracker.

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%, and the stage enum is documented in detail there, including the meaning of 'applied'. The description only echoes the stage concept ('at one stage') and adds no format, default, or interaction detail beyond the schema, so it sits at the baseline.

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 pairs a specific verb (List) with a specific resource (the authenticated user's jobs in LinkedIn's job tracker) and adds a scope qualifier (one stage). This clearly separates it from search_jobs (which searches the wider job corpus) and from get_job_details (which expands a single job).

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 states the intended workflow: list to obtain job_ids, then pass those ids to get_job_details for full info. That is genuine when-to-use guidance for the follow-up call, but there is no explicit exclusion such as 'use search_jobs instead when you don't know the employer/user's saved state'.

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

get_session_statusGet Session StatusA
Read-only

Report local saved-session and serving-process state for requested diagnostics.

Reads local observations without opening a browser, starting setup or login, or contacting LinkedIn. Stored files do not prove current authentication. In shared-browser mode these observations belong to the owner, not to a frontend running a login. It answers during browser work without refreshing the browser idle timer. Use ordinary LinkedIn tools directly for their requested work rather than adding a status preflight.

NameRequiredDescriptionDefault

No parameters

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

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

Goes well beyond readOnlyHint/openWorldHint by disclosing that no browser is opened, no setup or login occurs, no LinkedIn contact is made, and the browser idle timer is not refreshed. It also flags the important semantic caveat that stored files do not prove current authentication and that in shared-browser mode observations belong to the owner rather than a frontend running a login.

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?

Front-loaded with the purpose, then layered caveats and the sibling-routing sentence. Every sentence carries information, though the idle-timer sentence is slightly awkwardly worded and the density of caveats makes it longer than strictly minimal.

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, return values need no explanation, and with no parameters there is nothing else to document. The description covers safety-adjacent semantics (auth proof, shared-browser ownership) plus the selection rule, leaving nothing an agent needs before calling it.

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

Parameters4/5

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

The tool takes zero parameters, so the baseline is 4 and there is no parameter meaning the description could add. It does not waste space restating an empty 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?

States a specific verb and object: report local saved-session and serving-process state for diagnostics. It is immediately distinguishable from every sibling, which are all LinkedIn actions, and it explicitly disclaims LinkedIn interaction so the agent will not confuse it with a connectivity or auth check.

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?

Gives explicit when-to-use (requested diagnostics) and an explicit when-not-to-use: 'Use ordinary LinkedIn tools directly for their requested work rather than adding a status preflight.' That names the alternative behavior, which is the main mis-selection risk for a status tool in a browser-automation suite.

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.

NameRequiredDescriptionDefault
linkedin_usernameYesLinkedIn username of the profile page to read; a full profile URL is accepted too (e.g., "stickerdaniel", "williamhgates")

Output 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 declare readOnlyHint and openWorldHint, so safety is covered. The description adds genuinely useful behavioral detail beyond that: it follows 'Show all' links to return the full list rather than a truncated preview, and it silently skips sections that redirect to linkedin.com/premium. That extra fan-out behavior is exactly the kind of context an agent needs, though it doesn't mention rate limits or failure modes.

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 short sentences, front-loaded with what it returns and where it reads from, then the fan-out behavior, then the skip rule. No filler, no repetition of the title or schema.

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?

An output schema exists, so return payload shape need not be explained, and annotations carry the safety profile. The description covers source sections, expansion behavior, and skip logic, leaving only edge cases (e.g., empty sections, section ordering) unspecified — a minor gap.

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% and there is only one parameter, so the schema already documents linkedin_username (including the URL-or-handle form and examples). The description adds nothing about the parameter, which is the expected baseline 3 when the schema does the work.

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 names a specific verb+resource (get profile links) and narrows the scope precisely to sidebar recommendation sections on a profile page, enumerating the exact sections: 'More profiles for you', 'Explore premium profiles', 'People you may know'. This is enough for an agent to distinguish it from siblings like search_people or get_person_profile without inspecting their schemas.

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

Usage Guidelines3/5

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

Usage is implied by the tightly scoped resource (sidebar recommendations only), but the description never states when to prefer this over get_person_profile, search_people, or get_feed, and gives no prerequisites or exclusions beyond the premium-redirect skip. Adequate but leaves routing to inference.

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

reply_to_conversationReply to ConversationA
Destructive

Reply inside an existing LinkedIn messaging thread, InMail included.

Opens /messaging/thread/<thread_id>/ and types into that thread's own reply composer, so the message lands in the same conversation. This is the path for answering a recruiter InMail, whose sender may have no Message action on their profile. Get the thread_id from get_inbox, search_conversations or get_conversation.

The thread is verified before anything is typed: the page must land on exactly the requested thread and stay there, and the composer must be the page's one visible editor, inside the thread's main region, with one submit button in its own form. Any doubt fails closed. Quick-reply buttons an InMail shows ("Yes, interested...", "No thanks...") are never clicked; a thread that offers only those has no composer and returns composer_unavailable. A draft already in the composer is left untouched and returns composer_occupied. A status of enter_to_send_enabled means LinkedIn's "Press Enter to Send" preference hides the Send button; relay the returned instructions as for send_message. The dry run reports it too. No Voyager or other private API is used. This is a write operation when confirm_send is True.

NameRequiredDescriptionDefault
messageYesMessage text, read as send_message reads it: LF, CRLF and CR all end a line, empty lines are kept, and the whole message is trimmed. Tab, other control characters, DEL, U+0085, U+2028 and U+2029 are refused.
thread_idYesLinkedIn messaging thread ID, or a /messaging/thread/<id>/ reference as another tool returned it
confirm_sendYesMust be True to send. False is a dry run that verifies the thread and composer, types nothing, and says who the reply would go to.

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

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

Beyond the destructiveHint/openWorldHint annotations, the description discloses the verification gate (page must land on exactly the requested thread, composer must be the single visible editor in the main region with one submit button in its own form), the fail-closed policy, named failure statuses, and the fact that an existing draft is left untouched. It also scopes destructiveness precisely: it is a write operation only when confirm_send is True, which refines rather than repeats the destructiveHint annotation.

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?

Content is front-loaded with purpose first, then the verification and failure behavior, and nearly every sentence carries operational information. It is dense and long for a single tool, with some artifacts (double spaces, backticked status values) that slightly impede scanning, but there is no filler or repetition of the schema.

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 destructive, browser-driven write tool this covers what an agent needs: prerequisites (thread_id sources), safety gating, dry-run semantics, and enumerated failure outcomes. An output schema exists, so return-shape detail is correctly omitted while status meanings that affect the agent's next action are still explained.

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

Parameters4/5

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

Schema coverage is 100%, so the baseline is 3; the description earns a step above by adding acquisition guidance for thread_id (where to get it) and by clarifying that confirm_send=False is a dry run that still verifies the thread and composer, types nothing, and reports the recipient. Message formatting rules are left entirely to the schema, which 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 opening sentence states a specific verb and resource (reply inside an existing LinkedIn messaging thread) and immediately extends scope (InMail included). It also distinguishes itself from the profile-based path by explaining that the InMail sender may have no Message action, which is the concrete reason this tool exists separately from send_message.

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?

It tells the agent where the required thread_id comes from (get_inbox, search_conversations, get_conversation) and gives explicit when-not conditions: quick-reply-only threads return composer_unavailable, threads with an existing draft return composer_occupied, and quick-reply buttons are never clicked. It also points to send_message for the enter_to_send_enabled case, so the alternative path is named rather than left to inference.

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

search_companiesSearch CompaniesB
Read-only

Search for companies on LinkedIn.

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

Output 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?

The description discloses no behavioral traits beyond what 'search' and 'LinkedIn' naturally imply. Annotations already declare readOnlyHint and openWorldHint, but the description adds no further context about result limits, matching behavior, or ordering. It is not contradictory, but it is also not informative beyond the basic action.

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 compact sentence that wastes no words and immediately states the core action and target resource. It is appropriately sized for a simple tool.

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 one-parameter tool with an output schema and safety annotations, the description is minimally adequate. However, it does not clarify edge behavior, result scope, or how it differs from nearby company-related tools, so an agent may still need to infer intent.

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

Parameters3/5

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

The input schema already fully documents the only parameter, keywords, with a useful example. The description adds no additional semantic detail beyond the schema, so a baseline score 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 identifies the verb ('Search') and resource ('companies on LinkedIn'), so an agent can understand the basic function. However, it does not differentiate itself from sibling tools like get_company_profile or search_people, leaving some ambiguity about scope or result type.

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?

There is no guidance on when to use this tool instead of search_people, get_company_profile, or get_company_employees. The description implies keyword-based discovery but provides no explicit context, prerequisites, or exclusions.

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

search_conversationsSearch ConversationsC

Search messages by keyword.

Click-derived references require an observed different thread path after each row click. The first unverifiable click stops further row clicks and is reported in section_errors.search_results. Already-read text and independently extracted anchors retain their normal handling. A result without that diagnostic does not guarantee that every conversation was enumerated.

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

NameRequiredDescription

No output parameters

TDQS

C2.7/5.0
Behavior3/5

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

Annotations supply only openWorldHint=true, so the description must carry the behavioral load, and it does disclose two real traits: row clicks may mark conversations read, and an unverifiable click halts further enumeration with diagnostics in section_errors.search_results. However, this is expressed in opaque internal jargon ('click-derived references', 'observed different thread path') that an agent cannot readily act on, and it omits permissions or rate-limit context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

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

The first sentence is properly front-loaded, but the second paragraph is long, jargon-heavy, and largely about the scraper's internals rather than what the caller needs. Those sentences do not earn their place for an agent selecting or invoking the tool.

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?

An output schema exists, so return values need not be explained, and the description correctly gestures at where errors surface. Still, it leaves the agent without a clear picture of result shape, ordering, or how this tool relates to get_inbox/get_conversation, which is a meaningful gap for a search tool with a truncation caveat.

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%, and both parameters are already well documented in the schema, including the read-marking side effect of the limit parameter. The description adds no additional syntax, format, or matching semantics (e.g., how keywords are combined) beyond what the schema provides, so the baseline 3 applies.

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

Purpose3/5

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

The opening sentence gives a verb and resource ('Search messages by keyword'), but it names 'messages' while the tool is 'search_conversations', creating a small mismatch. It never distinguishes this tool from the closely related get_inbox and get_conversation siblings, and the rest of the description drifts into internal scraping mechanics rather than clarifying purpose.

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?

There is no explicit when-to-use guidance and no named alternative, despite three plausible siblings (get_inbox, get_conversation, search_posts). The only quasi-guidance is the schema note about preferring a low cap for noisy queries, which lives in the schema, not the description.

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.

LinkedIn is moving accounts to a redesigned job search, which keeps only the keywords, date_posted and paging. It drops the filters marked "Classic search only" and reports them in section_errors as filters_dropped. When it drops the location or work type, search again with them in the keywords ("remote python developer in Lyon") and keep doing so; words such as "senior" or "internship" there narrow the results too. Quotes do not make a phrase exact on that search.

NameRequiredDescriptionDefault
sort_byNoSort results (date, relevance). Classic search only.
job_typeNoFilter by job type, comma-separated (full_time, part_time, contract, temporary, volunteer, internship, other). Classic search only.
keywordsYesSearch keywords (e.g., "software engineer", "data scientist")
locationNoOptional location filter (e.g., "San Francisco", "Remote"). Classic search only.
max_pagesNoMaximum number of result pages to load (1-10, default 3)
work_typeNoFilter by work type, comma-separated (on_site, remote, hybrid). Classic search only.
easy_applyNoOnly show Easy Apply jobs (default false). Classic search only.
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). Classic search only.

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

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

Annotations only declare readOnly and openWorld; the description adds substantial behavioral context beyond them — the LinkedIn redesign, which filters are dropped, that drops are surfaced in section_errors as filters_dropped, and that quotes do not force exact phrases. This is exactly the kind of degradation and error-reporting behavior an agent cannot infer from structured fields.

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?

Front-loads purpose and the job_id handoff in two short sentences, then a single focused paragraph on the redesign caveat. Slightly wordy in places ('keep doing so'), but every sentence carries actionable 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?

An output schema exists, yet the description still adds the useful job_ids-to-get_job_details linkage. For a nine-parameter search tool with a nontrivial fallback path, the description covers the failure mode, the workaround, and the error field an agent should inspect.

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

Parameters4/5

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

Schema coverage is 100%, so the schema already documents all nine parameters and their values. The description still adds meaning by explaining that several filters are 'Classic search only' and will be dropped on redesigned search, plus keyword syntax caveats (words narrow results, quotes are not exact).

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?

States a specific verb and resource ('Search for jobs on LinkedIn') and immediately clarifies the output relationship: returns job_ids that feed get_job_details. This distinguishes it from the sibling detail-fetch tool without the agent needing to open either schema.

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?

Gives concrete guidance for the redesigned-search case: when filters are dropped, re-run with location/work type folded into keywords, and notes that words like 'senior' narrow results. It does not discuss when to prefer this over neighboring tools such as search_people, but the domain is clear enough that this is a minor gap.

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

search_peopleSearch PeopleC
Read-only

Search for people on LinkedIn.

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. A single token ("F") or a comma-separated string ("F,S") is also accepted, for clients that cannot transmit an array.
keywordsYesSearch keywords (e.g., "software engineer", "recruiter at Google")
locationNoOptional location filter, as LinkedIn's numeric geo URN id (e.g., "103644278" for the United States). Plain-text place names are silently ignored by LinkedIn and return unfiltered results, so they are refused here. The id is the geoUrn value in the URL of a LinkedIn people search filtered to that place; without one, put the place in keywords instead.
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

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 agent knows this is a safe, open-world read. The description adds nothing beyond that: no mention of result caps, pagination behavior, throttling risk, or that LinkedIn silently ignores plain-text location and company filters. That filter-failure behavior is detailed in the schema, but the description itself contributes no behavioral context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

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

A single sentence with no wasted words, front-loaded with the verb and resource. It is efficient but under-specified; concision here comes at the cost of useful detail rather than from careful editing.

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?

The tool has four parameters, full schema coverage, an output schema, and read-only annotations, so much of the burden is already carried by structured fields. Still, a search tool with filters and an output schema deserves at least a note on result shape or filtering caveats. The description supplies none of that, leaving it minimally adequate for its complexity.

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 baseline is 3. The schema already explains the network tokens (F/S/O), the numeric geo URN for location, and the company URN lookup path in detail. The description repeats none of this and adds no meaning beyond the schema.

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 states a specific verb and resource: 'Search for people on LinkedIn.' This distinguishes it from search_companies, search_jobs, and search_posts by resource even though those siblings are never named. It stops short of the sibling-differentiation required for a 5.

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?

There is no guidance on when to use this tool rather than alternatives such as get_person_profile, get_company_employees, or get_sidebar_profiles. No prerequisites, no mention of connection limitations, and no note on when a keyword search is the right approach instead of a direct profile lookup.

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

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.
content_typeNoOptional "Content type" filter. One of "documents" (PDFs and slide decks people upload), "images", "videos", "live_videos", "job_posts". Omit for all posts.

Output 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 safety and reach profile is covered. The description adds that results are an open global content search, but says nothing about result volume, pagination behavior, or rate limits beyond what the schema's max_pages note already provides.

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?

Front-loads the verb, resource, and scope in the first clause, then justifies the use case and the sibling distinctions. Every sentence earns its place; only minor tightening is possible.

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?

With an output schema, full schema coverage, and read-only/open-world annotations, the description covers what an agent needs to select the tool. It could be richer about expected result volume for a scroll-based search, but nothing essential to correct invocation is missing.

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%, including enum-like values for date_posted and content_type and the infinite-scroll semantics of max_pages, so the schema carries the parameter burden. The description adds no keyword syntax, quoting, or filtering guidance beyond the schema.

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

Purpose5/5

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

States a specific verb and resource ("Search LinkedIn posts/content") plus the scope "globally by keyword" and identifies the UI counterpart (the "Posts" tab). An agent can distinguish this from get_feed and get_company_posts purely from the description.

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?

Gives an explicit use case (catching informal hiring posts before a formal listing exists) and names two alternatives with the condition that selects against them: get_feed for your own home feed and get_company_posts for a single company's page. Nothing about routing is left to inference.

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

Compose and send a new message to a LinkedIn user.

Profile-based targeting opens LinkedIn's compose flow. It is not a safe reply path for an existing recruiter/InMail or messaging thread: it may create a separate DM even after you inspect that thread with get_conversation or search_conversations. To answer an existing thread, including an InMail from someone who is not a connection, use reply_to_conversation with the thread's id instead.

The recipient must be directly messageable from the profile page. If LinkedIn does not expose a normal Message action, use connect_with_person first, then retry send_message only after the connection request is accepted. A status of enter_to_send_enabled means the account has LinkedIn's "Press Enter to Send" preference on, which hides the Send button; relay the returned instructions to the user, who switches it to "Click Send to send" before retrying. The dry run (confirm_send False) reports it too. Recipient authorization comes from validating one recipient-specific Message action carrying the target URN, then following its browser navigation and pinning the exact final route. Visible profile links or recipient URNs in the composer are optional corroboration; any contradiction fails closed. No Voyager or other private API is used. This is a write operation when confirm_send is True.

thread_id is present only on sent: the conversation the confirmed message was observed in, or null when the page stayed on the compose route. retry_safe stays the authority for whether a retry is safe.

NameRequiredDescriptionDefault
messageYesMessage text. LF, CRLF and CR all end a line; an empty line separates paragraphs and is kept. Whitespace-only lines count as empty, and leading and trailing whitespace of the whole message is removed, as LinkedIn does when sending. Tab, other control characters, DEL, U+0085, U+2028 and U+2029 are refused.
profile_urnNoOptional profile URN (e.g. ACoAAB...) to verify against the URN exposed by the loaded profile before opening its Message action. It never bypasses recipient verification. 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; a full profile URL is accepted too

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

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

Annotations declare destructiveHint=true and openWorldHint=true, and the description is fully consistent, explicitly scoping the write behavior to confirm_send=True. Beyond the annotations it discloses failure modes not visible in structured fields: the enter_to_send_enabled status and what to tell the user, the fail-closed recipient authorization rule, the absence of any private/Voyager API, and retry_safe as the authority for retrying.

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?

Front-loaded with purpose and the reply-alternative routing, then the connection-prerequisite, then status/failure handling — a sensible priority order. It loses a point for the dense implementation aside about validating a Message action, following browser navigation and pinning the final route, and for a return-value paragraph (thread_id, retry_safe) that partly duplicates the output schema.

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 destructive, open-world write tool with four parameters, this covers purpose, alternatives, prerequisites, authorization behavior, dry-run behavior and the one non-obvious account setting that blocks sending. Nothing an agent needs in order to decide or retry is missing.

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

Parameters4/5

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

Schema coverage is 100%, so the baseline is 3, but the description adds real meaning the schema lacks: confirm_send=False is framed as a dry run that still reports the Enter-to-Send status, and profile_urn is characterized as corroboration only that never bypasses recipient verification. The message-formatting details are left entirely to the schema, which is fine given the coverage.

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?

Opens with a specific verb+resource+scope ("Compose and send a new message to a LinkedIn user") and immediately distinguishes itself from reply_to_conversation by naming the sibling and the exact situation each covers. An agent can route between send_message and reply_to_conversation without opening either schema.

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?

Gives explicit when-to-use and when-not-to-use rules: existing recruiter/InMail threads go to reply_to_conversation with the thread id, and non-messageable recipients require connect_with_person first with a retry only after acceptance. It also documents the dry-run path (confirm_send False) as the pre-flight check, which is exactly the decision support an agent needs.

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

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 25 tool updatesv4.29.0
    • First observedarchive_conversation
    • First observedclose_session
    • First observedconnect_with_person
    • First observeddismiss_job
    • First observedget_company_employees
    • First observedget_company_posts
    • First observedget_company_profile
    • First observedget_conversation
    • First observedget_easy_apply_form
    • First observedget_feed
    • First observedget_inbox
    • First observedget_job_apply_url
    • First observedget_job_details
    • First observedget_my_profile
    • First observedget_person_profile
    • First observedget_saved_jobs
    • First observedget_session_status
    • First observedget_sidebar_profiles
    • First observedreply_to_conversation
    • First observedsearch_companies
    • First observedsearch_conversations
    • First observedsearch_jobs
    • First observedsearch_people
    • First observedsearch_posts
    • First observedsend_message

TDQS

A3.7/5.0

Scored across 25 tools

Disambiguation4/5

Most tools target a clear resource+action, and the descriptions go out of their way to separate near-neighbors (send_message vs reply_to_conversation, get_feed vs search_posts vs get_company_posts, get_company_employees vs search_people). A few pairs still require reading long prose to distinguish, notably send_message/reply_to_conversation and get_job_apply_url/get_easy_apply_form/get_job_details, and get_sidebar_profiles overlaps conceptually with search_people.

Naming Consistency5/5

Every tool is snake_case with a verb-first pattern (get_*, search_*, send_*, reply_to_*, archive_*, close_*, dismiss_*, connect_with_*). No mixed casing or stylistic drift, and names are readable and predictable.

Tool Count4/5

25 tools is at the upper bound, but the LinkedIn domain is genuinely broad (people, companies, jobs, messaging, feed, session) and each tool maps to a distinct operation rather than being a variant of another. Slightly heavy, but the surface is defensible rather than padded.

Completeness4/5

Strong lifecycle coverage: profile reads, people/company/job/post search, connection requests, full messaging flow (inbox, read, search, reply, send, archive), job details/saved/dismiss, and session management. Gaps exist around writing actions — no save_job (only get_saved_jobs), no post creation/like/comment, no withdraw/remove connection, and Easy Apply is read-only with no submit path.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers