linkedin-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@linkedin-mcpshow my recent LinkedIn conversations"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
linkedin-mcp
A personal MCP server that gives an AI assistant read-only access to your own LinkedIn data through LinkedIn's Member Data Portability (Member) API. LinkedIn provides this API for members in the EEA and Switzerland under the EU Digital Markets Act (DMA).
Terms and disclaimer
This project is for personal use: each user accesses only their own LinkedIn data, with their own credentials.
There is no warranty or support. The software is provided "as is" under the MIT License. The API can change or stop working at any time.
This project is not affiliated with, endorsed by, or supported by LinkedIn or Microsoft.
You must accept LinkedIn's API Terms of Use and the terms of the Member Data Portability API (Member) product. You are responsible for complying with them.
You must create your own personal LinkedIn developer application with the Member Data Portability API (Member) product (scope
r_dma_portability_self_serve). This repository contains no credentials.You must be eligible for that product: LinkedIn only lets members located in the European Economic Area (EEA) and Switzerland consent and generate a token.
The AI assistant you connect this server to receives the data it reads, including messages from other people. Check the data handling terms of your AI provider.
Related MCP server: LinkedIn Agent MCP
What you can and cannot do
The API is read-only. You cannot send messages, publish posts or change anything.
Data | Source | Notes |
Messages |
| Full history. The newest messages may stop at the time you gave consent; see below. |
Connections |
| Name, profile URL, company, position, connection date. Email only if the connection allows exporting it. |
Posts |
| Can be empty for a while after consent: LinkedIn processes some domains later than others. |
Profile, positions, skills, invitations, endorsements, ... | Other snapshot domains (about 67 in total) | Available through the generic domain tools. |
Activity after consent (new messages, posts, comments, reactions) | Member Changelog API | Only events from the last 28 days and only after consent. |
LinkedIn does not document whether the snapshot is rebuilt on every request or only once, at consent time. If it is built once, activity after consent appears only in the changelog.
Setup
Create a LinkedIn developer app on the LinkedIn Developer Portal. Use the Member Data Portability (Member) Default Company page as the app's company. Do not create a new company page. Then, on the Products tab, request the Member Data Portability API (Member) product and accept its terms. See LinkedIn's instructions.
Generate an access token with the OAuth Token Generator: select your app and the
r_dma_portability_self_servescope.Install dependencies and configure the token:
uv sync cp .env.example .env # then set LINKEDIN_ACCESS_TOKEN uv run linkedin-mcp status
Tokens expire after 60 days and have no refresh token. When a token expires, every
call fails with an error that links to the token generator. Generate a new token and
update .env.
Configuration
The CLI reads settings from environment variables first, then from the .env file
(./.env, or the path given with --env-file).
Variable | Default | Description |
| (required) | OAuth access token. |
|
| Seconds to keep snapshot data in memory. |
|
| HTTP request timeout in seconds. |
Using it from an MCP host
The server uses the stdio transport. MCP hosts start it in an arbitrary working
directory, so give the .env path explicitly.
Claude Code:
claude mcp add linkedin -- uv --directory /path/to/linkedin-mcp run linkedin-mcp --env-file /path/to/linkedin-mcp/.env serveGeneric JSON configuration (Claude Desktop and others):
{
"mcpServers": {
"linkedin": {
"command": "uv",
"args": [
"--directory", "/path/to/linkedin-mcp",
"run", "linkedin-mcp", "--env-file", "/path/to/linkedin-mcp/.env", "serve"
]
}
}
}Tools
Tool | Description |
| Basic profile: name, headline, summary, location. |
| Conversations, most recently active first. Filters: folder, participant, since. |
| One conversation with its messages in chronological order. |
| Search messages by text, sender, folder and time range. |
| Search connections by name, company, position, email and connection date. |
| Your posts, newest first. |
| Changelog events after consent (last 28 days). |
| All snapshot domains that have data, with row counts. |
| Raw rows from any snapshot domain. |
All list tools support offset and limit and return the total number of matches.
Text matching ignores case and diacritics, so saric matches Šarić.
Agent guidance
The server sends a short usage guide to every MCP client in its instructions: data
sources, search behaviour and the main caveats.
skills/linkedin-mcp/SKILL.md is a longer guide with
steps for messages, contacts, posts, events and changelog data. To use it in Claude Code,
copy it to your skills directory:
cp -r skills/linkedin-mcp ~/.claude/skills/For other agents, add the file's content to the agent's instructions.
Command-line debugging
The CLI can call the API directly and print JSON. No MCP host is needed:
uv run linkedin-mcp status # changelog archiving status
uv run linkedin-mcp enable-changelog # enable archiving (normally automatic)
uv run linkedin-mcp domains # domains with data and row counts
uv run linkedin-mcp snapshot SKILLS # raw data of one domain (omit for all)
uv run linkedin-mcp changelog --since 2026-10-01 --resource messagesArchitecture
src/linkedin_mcp/
client.py LinkedInClient: async HTTP client for the 4 API endpoints, pagination, retries
models.py Pydantic models of the raw API responses
errors.py Exception hierarchy (AuthenticationError, RateLimitError, ...)
records.py Typed records parsed from snapshot rows (Message, Connection, Profile, Post)
service.py LinkedInService: in-memory cache, filtering, sorting, pagination
cache.py TTL cache
domains.py Snapshot domain names and descriptions
config.py Settings from the environment and .env
server.py MCP server (official `mcp` SDK, MCPServer)
cli.py Command-line entry pointThe API has no server-side filtering, so the service fetches each snapshot domain once
and keeps it in memory for LINKEDIN_CACHE_TTL seconds. Changelog data is not cached.
API quirks the client handles:
Snapshot pagination ends with HTTP 404 "No data found", not with an empty page.
paging.totalcan undercount, so the client keeps requesting pages until it gets the 404.The Snapshot API only accepts
Linkedin-Version: 202312.Domain names are case-sensitive, and some differ from the documentation: events are
Events, and the API also returns the undocumentedWHATSAPP_NUMBERS.The changelog
startTimeis inclusive. The client continues from the latestprocessedAtand removes duplicate events byid.The client retries 5xx responses and connection errors with exponential backoff. It does not retry 429, because the rate limits are daily.
Development
uv run ruff format . # format
uv run ruff check . # lint (includes docstring and annotation rules)
uv run ty check # type check
uv run pytest # tests with coverageThe unit tests cover the client and service layers and use mocked HTTP (respx) and
synthetic data. server.py and cli.py are thin wrappers and are not included in
coverage.
License
Available Tools
9 toolsget_conversationARead-onlyIdempotent
Get one LinkedIn conversation with its messages in chronological order.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Return only the most recent messages. | |
| conversation_id | Yes | From list_conversations or search_messages. |
Output Schema
| Name | Required | Description |
|---|---|---|
| title | Yes | |
| folder | Yes | |
| messages | Yes | |
| participants | Yes | |
| message_count | Yes | |
| conversation_id | Yes | |
| last_message_at | Yes | |
| first_message_at | Yes | |
| last_message_sender | Yes | |
| last_message_preview | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and openWorldHint=false, so the safety profile is covered. The description adds ordering semantics (chronological), which is genuinely useful, but says nothing about how the limit interacts with that ordering, truncation behavior, or pagination.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single, front-loaded sentence with no filler; every element (scope, return content, ordering) carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
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 annotations cover mutability. For a two-parameter read tool this is close to complete, with only the limit/ordering interaction left implicit.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both parameters are documented, including that limit selects the most recent messages. The description's 'chronological order' clarifies the output ordering but does not resolve how 'most recent' filtering composes with chronological presentation. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (get) and resource (one LinkedIn conversation) plus the payload (its messages in chronological order). It is clearly distinct from list_conversations and search_messages, though it does not name them explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The single-conversation scope implies this is the drill-down after a list/search, but the description itself gives no explicit when-to-use or when-not-to-use guidance. The routing hint lives only in the conversation_id schema field ('From list_conversations or search_messages').
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_data_domainARead-onlyIdempotent
Get raw data rows from any LinkedIn data domain, for example POSITIONS or SKILLS.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of results. | |
| domain | Yes | Case-sensitive name from list_data_domains, e.g. "Events". | |
| offset | No | Number of results to skip. |
Output Schema
| Name | Required | Description |
|---|---|---|
| items | Yes | |
| total | Yes | |
| offset | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare this as a read-only, idempotent, non-open-world operation, so the safety profile is covered. The description adds some context by saying it returns raw data rows from any LinkedIn domain, but it does not discuss pagination, data scope, or other behavioral limits beyond what the schema and annotations already provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single front-loaded sentence with no filler. It communicates the core action and example resources efficiently.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the simple three-parameter read-only operation, full schema coverage, output schema, and clear annotations, the description is largely complete. It could be improved by explicitly mentioning the dependency on list_data_domains, but that gap is minor and partially covered by the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every parameter is already documented in the input schema, which sets the baseline at 3. The description reinforces valid domain examples like POSITIONS and SKILLS but does not add syntax or meaning beyond the schema for domain, limit, or offset.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: retrieving raw data rows from a LinkedIn data domain, with concrete examples like POSITIONS and SKILLS. It does not explicitly differentiate this from the sibling list_data_domains, but the contrast between raw data rows and domain listing is reasonably clear.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the statement that this gets raw rows from any data domain, and the examples suggest valid domain values. However, it does not explicitly say when to use this versus list_data_domains or other sibling tools, nor does it state that the domain must first be discovered via list_data_domains.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_profileARead-onlyIdempotent
Get the user's basic LinkedIn profile: name, headline, summary, location.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| address | Yes | |
| summary | Yes | |
| headline | Yes | |
| industry | Yes | |
| location | Yes | |
| websites | Yes | |
| zip_code | Yes | |
| last_name | Yes | |
| birth_date | Yes | |
| first_name | Yes | |
| maiden_name | Yes | |
| twitter_handles | Yes | |
| instant_messengers | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and openWorldHint=false, so the safety and side-effect profile is fully covered. The description adds only the field inventory, which is arguably duplicated by the output schema. It does not clarify whose profile (authenticated user vs. arbitrary member) beyond the vague "the user's".
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single sentence with zero filler, and the resource identification is front-loaded before the field list. Every word earns its place; nothing is repeated or padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With a rich annotation set, a full output schema, and no parameters, the description covers what an agent needs to select this tool. The remaining gap is the ambiguity of "the user's" — nothing tells the agent this is the authenticated user's profile as opposed to a lookup keyed by an identifier.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there are no parameter semantics to explain; baseline for zero-param tools is 4. The description's field list is a reasonable substitute for explaining what comes back, though it is largely redundant with the existing output schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description pairs a specific verb ("Get") with a specific resource ("the user's basic LinkedIn profile") and enumerates the fields returned (name, headline, summary, location). It is unambiguous about what the tool retrieves; the small deduction is because it does not explicitly distinguish scope from siblings, though no sibling overlaps as a profile getter.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No explicit when-to-use or when-not-to-use guidance, and no alternatives are named. Usage is only implied by the resource name, which happens to be sufficient here because no sibling tool returns profile data. An agent must still infer that this returns the authenticated user's own profile rather than a given member's.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_recent_activityARead-onlyIdempotent
Get the user's LinkedIn activity since consent (last 28 days), newest first.
Covers new messages, posts, comments and reactions. Times are epoch milliseconds.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of results. | |
| since | No | Only events at or after this time. | |
| offset | No | Number of results to skip. | |
| resource_name | No | Only events for this resource type. The values are not documented: call without this filter first to see which values occur. |
Output Schema
| Name | Required | Description |
|---|---|---|
| items | Yes | |
| total | Yes | |
| offset | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover safety (readOnly, idempotent, closed-world), so the description earns credit for adding the non-obvious constraints: results are capped to the consent window of the last 28 days and returned newest-first. The epoch-millisecond time format also preempts a common misinterpretation. It stops short of explaining pagination behaviour or whether the 28-day cap truncates offset paging.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, zero filler, with the scope and ordering constraint front-loaded before the event-type enumeration. Every clause carries information the agent needs to call it correctly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Output schema and annotations are present and the parameter schema is fully documented, so the description only needs to supply the temporal scope and ordering, which it does. The one residual gap is how the 28-day cap interacts with limit/offset paging for an agent trying to page back further.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, including an explicit warning that resource_name values are undocumented — so the schema does the heavy lifting and the baseline of 3 is met. The description's 'newest first' framing does add ordering semantics that bear directly on how limit/offset behave, slightly above baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get the user's LinkedIn activity') and enumerates the four event types covered plus the 28-day scope and newest-first ordering. It does not name the siblings it differs from (list_posts, search_messages), so an agent must infer how this aggregated feed relates to those narrower tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The 'since consent (last 28 days)' framing implies this is the cross-cutting recent-feed view, but no explicit when-to-use/when-not or alternative routing is given despite obvious siblings like list_posts and search_messages. Usage is inferable rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_conversationsBRead-onlyIdempotent
List LinkedIn message conversations, most recently active first.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of results. | |
| since | No | Only conversations active at or after this time. | |
| folder | No | Folder of the latest message: "INBOX", "ARCHIVE", "SPAM". | |
| offset | No | Number of results to skip. | |
| participant | No | Text to find in a participant's name. |
Output Schema
| Name | Required | Description |
|---|---|---|
| items | Yes | |
| total | Yes | |
| offset | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and a closed world, so the safety profile is covered. The description adds real behavioral value in stating the result ordering (most recently active first), which is not derivable from the schema. It says nothing about pagination semantics or total counts beyond what limit/offset already imply.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence that conveys resource, identity and ordering with no filler. It is appropriately short for a simple list tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present and full parameter documentation in the schema, plus annotations covering safety, the description covers what is needed to call the tool correctly. Minor gap: no hint about paging through results or what a default listing contains.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every parameter (limit, since, folder, participant, offset) is already documented in the schema and the baseline is 3. The description adds no syntax, format, or matching-behavior detail (e.g. how 'participant' text matching works) beyond what the schema already says.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List LinkedIn message conversations') plus the sort order ('most recently active first'), which an agent can use immediately. It does not explicitly distinguish itself from get_conversation or search_messages, but the plural/list framing makes the distinction inferable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use or when-not-to-use guidance, and no mention of the siblings (search_messages, get_conversation) that an agent would otherwise have to disambiguate against. The only directional hint is the default recency ordering, which is implicit rather than stated as a selection criterion.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_data_domainsARead-onlyIdempotent
List all LinkedIn data domains that have data for the user, with row counts.
The first call fetches all data and takes several seconds.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses a real behavioral trait beyond the annotations: the first call is a full fetch and takes several seconds, warning the agent about latency and a cold-cache penalty. Annotations already cover read-only/idempotent/non-open-world semantics, and the output schema covers return shape, so this performance note is the additive value.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with the purpose and finish with the latency caveat; nothing is wasted or buried.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no params, an output schema, and read-only annotations, the description only needs purpose, scope, and any call-shape caveats, all of which it delivers. It could be slightly more complete by pointing to get_data_domain as the drill-down step, but nothing required for a correct call is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to disambiguate; the baseline for a no-param tool applies. No schema semantics are repeated or contradicted.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb (List) and resource (LinkedIn data domains) and adds scope ('that have data for the user') plus what the result carries ('with row counts'). The plural/aggregate framing implicitly separates it from the singular sibling get_data_domain, 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The line 'The first call fetches all data' hints that this is the discovery entry point and should be called before drilling into a domain, but it never explicitly says when to use this versus get_data_domain or what the follow-up is. Usage is implied rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_postsARead-onlyIdempotent
List the user's LinkedIn posts, newest first.
Posts made after the user's consent may only appear in get_recent_activity.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of results. | |
| query | No | Text to find in the post text. | |
| since | No | Only posts made at or after this time. | |
| offset | No | Number of results to skip. |
Output Schema
| Name | Required | Description |
|---|---|---|
| items | Yes | |
| total | Yes | |
| offset | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and openWorldHint=false, so safety is covered. The description adds two things not in the annotations: the default ordering (newest first) and a data-visibility constraint tied to consent that determines which posts this tool can even return.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with the core purpose and followed by the caveat. The consent sentence is slightly awkwardly worded ('after the user's consent'), but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present and full parameter documentation in the schema, the description needn't explain return values. It covers purpose, ordering, and the visibility caveat; only a note on pagination behavior or whether results are scoped strictly to the authenticated user is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with limit, query, since, and offset all documented in the schema, so the baseline is 3. The description's 'newest first' implies the sort order the offset/limit operate over but adds no syntax or format detail beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List the user's LinkedIn posts') plus a result ordering ('newest first'), and explicitly names the sibling that owns a subset of the data (get_recent_activity). An agent can distinguish this from the other list/search siblings without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides an explicit when-not rule: posts made after the user's consent may only appear in get_recent_activity, which routes the agent to the right alternative. It stops short of covering the broader choice against search_messages/search_connections, but the key exclusion is stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_connectionsARead-onlyIdempotent
Search the user's first-degree LinkedIn connections, most recent first.
Email addresses are only present for connections who allow exporting them.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of results. | |
| query | No | Text to find in the name, company, position or email. | |
| offset | No | Number of results to skip. | |
| company | No | Text to find in the company name. | |
| connected_since | No | Only connections made on or after this date. |
Output Schema
| Name | Required | Description |
|---|---|---|
| items | Yes | |
| total | Yes | |
| offset | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, and non-open-world behavior, so the description doesn't need to cover safety. It adds genuine value beyond that with the result ordering and the caveat that email addresses are only returned for connections who permit exporting — a data-availability trait an agent cannot learn from the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with the verb and scope, followed by the one non-obvious caveat. Nothing is redundant or padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema, full parameter coverage, and read-only annotations, most of the burden is lifted. The description covers scope, ordering, and the email-permission caveat; a note on pagination expectations or an explicit 'use X instead for profiles' pointer would complete it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the description adds no parameter detail beyond what is in the schema (limit, query, company, connected_since are all self-documented). Baseline 3 applies since the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (search) and resource (the user's first-degree LinkedIn connections), plus the ordering ('most recent first') and a scope qualifier (first-degree only). No sibling tool touches connections, so there is no ambiguity to resolve.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the tool name and the 'first-degree connections' scope, but the description never says when to reach for this versus alternatives like get_profile or search_messages, nor any prerequisites. An agent must infer that it should use this only when looking for a connection list.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_messagesBRead-onlyIdempotent
Search LinkedIn messages, newest first. Matching ignores case and accents.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of results. | |
| query | No | Text to find in the message body or subject. | |
| since | No | Only messages sent at or after this time. | |
| until | No | Only messages sent before this time. | |
| folder | No | Message folder: "INBOX", "ARCHIVE", "SPAM". | |
| offset | No | Number of results to skip. | |
| sender | No | Text to find in the sender's name. |
Output Schema
| Name | Required | Description |
|---|---|---|
| items | Yes | |
| total | Yes | |
| offset | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, and closed-world, so safety is covered. The description usefully adds result ordering (newest first) and matching semantics (case- and accent-insensitive), but says nothing about pagination behavior or what happens with no filters applied.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, zero filler, with the identifying verb and resource front-loaded and the ordering caveat second. Everything present earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
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 needn't be explained, but for a search tool with seven optional filters an agent would benefit from knowing default behavior with no query and how it relates to the listing siblings. Adequate but with a clear routing gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all seven parameters are already documented with defaults and bounds. The description's note about case/accent-insensitive matching slightly enriches the query/sender params, but adds little beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Search LinkedIn messages") plus an ordering guarantee. It does not differentiate itself from the sibling list_conversations/get_conversation, so an agent must infer the boundary between 'search' and 'list'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance on when to use this versus list_conversations or get_conversation, and no mention of behavior when query is null (does it return everything?). Usage must be inferred from the name alone.
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.
9 tool updates
v0.1.0- First observed
get_conversation - First observed
get_data_domain - First observed
get_profile - First observed
get_recent_activity - First observed
list_conversations - First observed
list_data_domains - First observed
list_posts - First observed
search_connections - First observed
search_messages
TDQS
Scored across 9 tools
Most tools target distinct resources and actions: profile, conversations, messages, connections, posts, recent activity, and raw data domains. The only mild overlap is between get_recent_activity and list_posts/list_conversations, but the description clarifies its aggregate, consent-window scope.
All names use consistent snake_case with clear verb_noun patterns: get_profile, list_conversations, get_conversation, search_messages, search_connections, list_posts, get_recent_activity, list_data_domains, get_data_domain. The verbs are appropriate and predictable.
Nine tools is well-scoped for a LinkedIn data-access MCP server. Each tool covers a meaningful area without excessive fragmentation.
The surface covers core read access: profile, conversations, messages, connections, posts, recent activity, and generic raw domain retrieval. Minor gaps exist, such as no dedicated search_posts or get_post, but the generic data-domain tools provide a workaround.
Maintenance
Related MCP Connectors
LinkedIn for AI agents: search people, read profiles, posts and connections via a connected account
- linkedinOAuthio.reachium
LinkedIn campaigns, content, leads and inbox from your AI client. Scoped, revocable keys.
Full LinkedIn access for AI agents: leads, messaging, and campaigns with activity limits built in.
LinkedIn jobs, companies and people for AI agents, plus messages and invites via your own account.
Related MCP Servers
- AlicenseBqualityCmaintenanceEnables AI agents with read/write access to LinkedIn API, including profile, posts, media, organizations, comments, reactions, and analytics.2020 npmMIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to connect to LinkedIn, accessing profiles and companies, searching for jobs and people, managing saved jobs, updating job-search profile settings, and inspecting analytics.1Apache 2.0
- AlicenseAqualityDmaintenanceEnables AI assistants to read and edit LinkedIn profiles including headline, about section, work experience, education, and skills through OAuth 2.0 authentication.16MIT
- AlicenseAqualityBmaintenanceConnects your LinkedIn professional profile to AI assistants (Claude, GitHub Copilot) via LinkedIn's official Member Data Portability API, enabling read-only access to résumé data, activity, and recent changes.529 npm4MIT