Skip to main content

linkedin-toolkit (Python)

The Python client for LinkedIn Toolkit, with ready-made tool wrappers for LangChain, LlamaIndex, CrewAI, AutoGen, Google ADK, Pydantic AI and smolagents.

It talks to the local HTTP API that lit serve --http exposes on 127.0.0.1:47830. Nothing leaves your machine except the LinkedIn calls your own Chrome makes.

pip install linkedin-toolkit

Prerequisites

npx linkedin-toolkit-mcp     # pair the extension once
lit serve --http             # 127.0.0.1:47830

Add --fake to lit serve to run without a LinkedIn account: real envelopes, real error codes, invented data.

Use it

from linkedin_toolkit import LinkedInToolkit

client = LinkedInToolkit()                    # finds the URL and token for you

status = client.status_get()
data = client.search_people(keywords="CTO fintech London", count=25)
invite = client.outreach_invite(publicId=data["profiles"][0]["publicId"], note="Hello.")

invite["status"]   # 'queued' — a human approves it in the extension popup. That is success.

One keyword-only method per action, named by snake-casing it: search.peoplesearch_people, network.unfollowCountnetwork_unfollow_count. Parameter names are the contract's own — publicId, not public_id — so one vocabulary covers MCP, HTTP, the docs and every wrapper.

Async is the same surface, awaited:

from linkedin_toolkit import AsyncLinkedInToolkit

async with AsyncLinkedInToolkit() as client:
    data = await client.search_people(keywords="CTO fintech London")

call(action, params) is the untyped escape hatch; call_tool(name, args) reaches the three tools that are not a bare action (linkedin_query_sql, linkedin_sync, linkedin_research_pack).

Requests time out after 120 s by default (timeout=). linkedin_research_pack is the exception: the server waits for that job to finish, so the client gives it 11 minutes — wider than the server's own 10-minute budget. research_pack(...), the action rather than the tool, returns a job id immediately and is unaffected.

Configuration

Nothing is required. In order:

  1. LinkedInToolkit(base_url=..., token=...)
  2. LINKEDIN_TOOLKIT_URL / LINKEDIN_TOOLKIT_TOKEN
  3. ~/.linkedin-toolkit/server.json — the port a running lit serve actually bound
  4. ~/.linkedin-toolkit/config.json — the pairing token, and the configured port
  5. http://127.0.0.1:47830

LINKEDIN_TOOLKIT_HOME moves the directory, as it does for the server. client.config says which source each value came from.

Errors

from linkedin_toolkit import LinkedInToolkitError

try:
    client.outreach_invite(publicId="someone")
except LinkedInToolkitError as err:
    err.code          # 'RATE_LIMITED' | 'CHALLENGE_DETECTED' | …
    err.how_to_fix    # pass this to the user verbatim
    err.retry_after   # milliseconds, when the server said
    err.terminal      # True for RATE_LIMITED, QUOTA_EXCEEDED, CHALLENGE_DETECTED, NOT_LOGGED_IN

This client never retries. Half of these codes are terminal, and retrying after a challenge is the specific behaviour that turns a LinkedIn warning into a restriction.

Models

linkedin_toolkit.models has pydantic models for every shared type — Profile, Company, Thread, Message, List, Campaign, QueueItem, WriteResult, RateLimit, Status, Pack and the rest. They allow extra fields on purpose: the extension is authoritative about what a profile contains and ships on its own cadence.

from linkedin_toolkit import models

people = [models.Profile.model_validate(p) for p in data["profiles"]]

Tools and framework wrappers

client.tools() returns the same 39 definitions the MCP server advertises — {name, description, parameters} — read from a committed copy of mcp-server/tools.json, so it works with the server stopped.

Framework Import Extra
LangChain linkedin_toolkit.integrations.langchain linkedin-toolkit[langchain]
LlamaIndex linkedin_toolkit.integrations.llama_index linkedin-toolkit[llamaindex]
CrewAI linkedin_toolkit.integrations.crewai linkedin-toolkit[crewai]
AutoGen linkedin_toolkit.integrations.autogen linkedin-toolkit[autogen]
Google ADK linkedin_toolkit.integrations.google_adk linkedin-toolkit[google-adk]
Pydantic AI linkedin_toolkit.integrations.pydantic_ai linkedin-toolkit[pydantic-ai]
smolagents linkedin_toolkit.integrations.smolagents linkedin-toolkit[smolagents]

Every one exposes the same get_tools(client, include=…, exclude=…, read_only=…):

from linkedin_toolkit import LinkedInToolkit
from linkedin_toolkit.integrations.langchain import get_tools
from langgraph.prebuilt import create_react_agent

client = LinkedInToolkit()
agent = create_react_agent(model, get_tools(client))

read_only=True drops every tool that writes to LinkedIn — the cheapest way to build a sourcing agent that structurally cannot send anything. It is worth passing for smolagents in particular, where a CodeAgent writes loops that call your tools.

The argument schemas are built from the contract recursively: steps on campaign.create is an array of objects whose type is one of nine values and whose branch nests further, and that is what the model sees — not list[dict]. Enums stay enums, records stay records, and the signature-reading frameworks (AutoGen, ADK, LlamaIndex, Pydantic AI) get the same shape as the args_schema ones. smolagents is the exception: its input vocabulary is a fixed set of flat types, so the nesting is described in the field's prose instead.

An integration whose framework is not installed raises an ImportError naming the extra, at import time, rather than failing somewhere deeper.

Failures inside a wrapper are returned to the model as data ({"error": "CHALLENGE_DETECTED", "message": …}) rather than raised, because an exception aborts most agent loops and the model needs to read the code to stop for the right reason. The client itself still raises.

What you cannot change from here

  • Hard caps live in the extension: 100 invites, 150 messages, 500 profile visits and 1,000 search results per day. No parameter in this package raises them.
  • Copilot mode is on by default. Writes return {"status": "queued", "queueId": …} and wait for a human. Report that as success.

Regenerating

linkedin_toolkit/tools.json and linkedin_toolkit/_actions.py are generated from mcp-server/tools.json and mcp-server/openapi.json by python scripts/gen.py. They are committed, and tests/test_gen.py fails if they are stale.

Licence

MIT.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

linkedin_toolkit-2.0.0.tar.gz (46.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

linkedin_toolkit-2.0.0-py3-none-any.whl (41.7 kB view details)

Uploaded Python 3

File details

Details for the file linkedin_toolkit-2.0.0.tar.gz.

File metadata

  • Download URL: linkedin_toolkit-2.0.0.tar.gz
  • Upload date:
  • Size: 46.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for linkedin_toolkit-2.0.0.tar.gz
Algorithm Hash digest
SHA256 43ee346d61d098b8be14d123efbad1a14e9754578089463e9f858b73e4e50e98
MD5 2a41d38310f2b10b79a42d4b47bdbe43
BLAKE2b-256 1989d7cf54abd87395f9d35c5fb1838348f5b3796d5398d2dd03bbb22e1e32e1

See more details on using hashes here.

Provenance

The following attestation bundles were made for linkedin_toolkit-2.0.0.tar.gz:

Publisher: release.yml on OpenRecruiterTools/linkedin-toolkit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file linkedin_toolkit-2.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for linkedin_toolkit-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ccf7e79788d1150faf0dda1cec1f0d5caf7b4db681291ec32c83f08373f3d1a8
MD5 34fa64e83bbf222456f8b835565c53b4
BLAKE2b-256 e3ac617a01e9d5879e121f60c1b2d48fc3ef6493e7b6014d89c350e4cbfb82e4

See more details on using hashes here.

Provenance

The following attestation bundles were made for linkedin_toolkit-2.0.0-py3-none-any.whl:

Publisher: release.yml on OpenRecruiterTools/linkedin-toolkit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

2.0.2

2 files

2.0.1

2 files

This release

2.0.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page