LinkedIn MCP Tools: Complete Reference (19 Tools, Full tools/list, inputSchema)
Complete reference for the LinkedIn MCP tool surface: 19 tools, full tools/list response, inputSchema, worked examples, and comparison vs the alternatives.
TL;DR
The Fintalio LinkedIn MCP server exposes 19 tools at https://fintalio.com/mcp. Nine read tools (list_contacts, get_contact, list_contact_groups, list_sequences, get_sequence, list_sequence_templates, get_sequence_template, list_variables, get_account_status), nine write tools (create_contact_group, update_contact, pause_sequence, resume_sequence, stop_sequence, parse_csv, commit_csv, create_sequence_template, create_contact), and one execute tool (launch_sequence). Transport is HTTP+SSE, wire format is JSON-RPC 2.0, auth is Sanctum bearer tokens, rate limit is 120 requests per minute per token. The server is published in the official MCP registry at registry.modelcontextprotocol.io as com.fintalio/linkedin-mcp.
This page reproduces the full tools/list payload with every name, description, and inputSchema verbatim from the production code (app/Mcp/Servers/FintalioServer.php, version 0.0.1). Each tool gets a worked tools/call example so an LLM can copy the invocation directly.
How to read this reference
This document is the canonical spec for the Fintalio MCP tool surface as of version 0.0.1. The endpoint lives at https://fintalio.com/mcp and is mounted by the laravel/mcp package via routes/ai.php. The transport is HTTP with Server-Sent Events for streaming, the wire format is JSON-RPC 2.0 (JSON-RPC 2.0 specification), and every tool follows the Model Context Protocol tools/list contract defined at modelcontextprotocol.io/specification/tools.
A few invariants apply to every tool below:
- Authentication. Every request must carry
Authorization: Bearer <sanctum-token>. Tokens are minted from/settings/tokensagainst a subscribed account (single plan, €69/mo, MCP access bundled perconfig/plans.php). - Rate limit. The route declares
throttle:120,1middleware, so each token gets 120 requests per minute. The 121st returns HTTP 429. - Pagination. The server overrides
laravel/mcp’s defaults todefaultPaginationLength=100andmaxPaginationLength=200, which keepstools/listsingle-page (nonextCursorfor 19 tools). Most MCP clients in 2026 do not follownextCursorreliably, so single-page delivery keeps discovery deterministic. - User scoping. Every tool reads
auth()->id()and filters byuser_id. There is no cross-tenant access path. - inputSchema dialect. All schemas are JSON Schema Draft 2020-12 inside
{ type: "object", properties: {...} }, as required by the MCP spec.
If you are building the server itself rather than calling it, see /blog/how-to-build-linkedin-mcp-server. For the install walkthrough into Claude Desktop, see /blog/claude-desktop-linkedin-agent. For the category overview, the pillar lives at /blog/linkedin-mcp.
What does the full tools/list response look like?
Below is the abridged response Fintalio returns to an authenticated tools/list call, showing three representative tools (list_contacts, create_contact, launch_sequence) in full. The remaining 16 tools follow the same shape and are documented individually further down. This is the payload an LLM host caches at session start and feeds into the model’s context when deciding which tool to call.
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "list_contacts",
"description": "List the user's contacts. Paginated (max 50 per page). Filter by status, group, or search.",
"inputSchema": {
"type": "object",
"properties": {
"status": { "type": "string" },
"group_id": { "type": "integer" },
"search": { "type": "string" },
"limit": { "type": "integer" },
"offset": { "type": "integer" }
}
}
},
{
"name": "create_contact",
"description": "Create a contact (single) from a LinkedIn URL plus identity. Upserts the underlying Prospect by linkedin_id (slug) so two callers with the same URL share one Prospect. Returns the existing contact unchanged if it already exists for the current user. For bulk imports, prefer parse_csv + commit_csv.",
"inputSchema": {
"type": "object",
"properties": {
"linkedin_url": { "type": "string" },
"first_name": { "type": "string" },
"last_name": { "type": "string" },
"full_name": { "type": "string" },
"title": { "type": "string" },
"company_name": { "type": "string" },
"custom_data": { "type": "object" }
}
}
},
{
"name": "launch_sequence",
"description": "Launch a sequence template against a list of contacts or a contact group. Without confirm=true, returns a dry-run preview (target count, first 5 names, template name). With confirm=true, requires the sequences:execute scope and triggers real LinkedIn sends. Each existing active sequence for the same (user, contact, template) is skipped.",
"inputSchema": {
"type": "object",
"properties": {
"template_id": { "type": "integer" },
"contact_ids": { "type": "array" },
"contact_group_id": { "type": "integer" },
"confirm": { "type": "boolean" }
}
}
}
// ... 16 more tools below
]
}
}
Three things matter in that payload. First, every tool name is snake_case verb-plus-object, which is the shape LLMs disambiguate fastest. Second, the description carries both happy-path semantics and constraints, because the model picks tools by reading descriptions. Third, launch_sequence exposes a confirm: boolean dry-run flag so the agent can preview the target list before triggering real LinkedIn sends. That preview-then-confirm pattern is repeated wherever a tool causes external side effects.
Read tools (9): what the agent fetches before acting
Read tools are the agent’s perception loop. They never mutate state, never call the LinkedIn data provider directly, and never count against any LinkedIn-side quota. Every one of the nine tools below requires the read ability scope, which is the default scope on any Fintalio Sanctum token. Together they answer the four questions an agent asks every loop: “who do I know, where are they grouped, what am I running, and is the account healthy?”
list_contacts
Lists the current user’s contacts with prospect identity and current outreach status. Paginated, max 50 per page. The filters allow an agent to scope to a status (connected, pending, replied, etc.), a group, or a free-text search across full name and title.
{
"name": "list_contacts",
"description": "List the user's contacts. Paginated (max 50 per page). Filter by status, group, or search.",
"inputSchema": {
"type": "object",
"properties": {
"status": { "type": "string" },
"group_id": { "type": "integer" },
"search": { "type": "string" },
"limit": { "type": "integer" },
"offset": { "type": "integer" }
}
}
}
Worked tools/call:
{ "jsonrpc": "2.0", "id": 2, "method": "tools/call",
"params": { "name": "list_contacts",
"arguments": { "status": "connected", "limit": 20 } } }
When an agent reaches for this tool: at the start of any workflow that needs a target list (re-engagement, follow-up triage, segmentation).
get_contact
Returns a single contact by id, with full prospect detail, current status flags, the last ten messages, notes, priority, tags, and the custom_data JSON. This is what the agent calls after list_contacts to read enrichment fields before deciding the next action.
{
"name": "get_contact",
"description": "Get a single contact by id with full prospect detail and last 10 messages.",
"inputSchema": {
"type": "object",
"properties": { "id": { "type": "integer" } }
}
}
Worked tools/call:
{ "jsonrpc": "2.0", "id": 3, "method": "tools/call",
"params": { "name": "get_contact", "arguments": { "id": 42 } } }
When an agent reaches for this tool: drilling down after a list_contacts result, or following a deep-link from a user message that pasted a contact id.
list_contact_groups
Lists the user’s segments with member counts. No parameters: the result is small enough to ship in full every call. Agents use this to find existing segments before creating duplicates with create_contact_group.
{
"name": "list_contact_groups",
"description": "List the user's contact groups with member counts.",
"inputSchema": { "type": "object", "properties": {} }
}
Worked tools/call:
{ "jsonrpc": "2.0", "id": 4, "method": "tools/call",
"params": { "name": "list_contact_groups", "arguments": {} } }
When an agent reaches for this tool: before any group write, to avoid creating duplicate segments. Migration 2026_05_02 enforces a unique (user_id, name) constraint, so duplicate-create silently returns the existing group, but knowing the id up front is cheaper.
list_sequences
Lists the user’s outreach sequences with template name, current step, total steps, status, and next_message_at. Paginated like list_contacts. Status filter accepts running, paused, stopped, completed, failed, replied.
{
"name": "list_sequences",
"description": "List the user's sequences with current step and template name. Paginated, max 50 per page.",
"inputSchema": {
"type": "object",
"properties": {
"status": { "type": "string" },
"limit": { "type": "integer" },
"offset": { "type": "integer" }
}
}
}
Worked tools/call:
{ "jsonrpc": "2.0", "id": 5, "method": "tools/call",
"params": { "name": "list_sequences",
"arguments": { "status": "running", "limit": 20 } } }
When an agent reaches for this tool: morning sweep (“what is currently in flight”), or scoping which sequences to pause before launching a new campaign.
get_sequence
Returns one sequence with full message history (step-by-step status, content, sent_at, error_message) and contact identity. This is the tool the agent calls in a loop to read response state mid-campaign.
{
"name": "get_sequence",
"description": "Get a sequence by id with its messages history.",
"inputSchema": {
"type": "object",
"properties": { "id": { "type": "integer" } }
}
}
Worked tools/call:
{ "jsonrpc": "2.0", "id": 6, "method": "tools/call",
"params": { "name": "get_sequence", "arguments": { "id": 17 } } }
When an agent reaches for this tool: investigating a single sequence’s progress, or correlating a reply alert with the underlying campaign.
list_sequence_templates
Lists reusable templates with description and step count. Includes both user-authored templates and templates marked is_library (the shared library). No parameters: the surface is small enough to return in full.
{
"name": "list_sequence_templates",
"description": "List the user's sequence templates with description and step count.",
"inputSchema": { "type": "object", "properties": {} }
}
Worked tools/call:
{ "jsonrpc": "2.0", "id": 7, "method": "tools/call",
"params": { "name": "list_sequence_templates", "arguments": {} } }
When an agent reaches for this tool: picking a template before launch_sequence, or deciding whether to author a new one with create_sequence_template.
get_sequence_template
Returns one template with its ordered message templates: step number, type (connect / dm / followup), subject, body, and delay_days (decimal per migration make_delay_days_decimal). The agent uses this to verify a template matches the use case before launching.
{
"name": "get_sequence_template",
"description": "Get a sequence template by id, including its message templates (step / type / body / delay).",
"inputSchema": {
"type": "object",
"properties": { "id": { "type": "integer" } }
}
}
Worked tools/call:
{ "jsonrpc": "2.0", "id": 8, "method": "tools/call",
"params": { "name": "get_sequence_template", "arguments": { "id": 3 } } }
When an agent reaches for this tool: dry-run reading the exact body text and delays before calling launch_sequence.
list_variables
Returns the merge variables available when composing a message: a fixed list of system keys (prenom, nom, nom_complet, entreprise, poste) plus all custom keys the user has put in any contact’s custom_data. Agents call this when drafting a template to know which {{placeholders}} will hydrate per recipient.
{
"name": "list_variables",
"description": "List the variables available when composing a sequence message: system keys (prenom, nom, etc.) and per-user custom keys.",
"inputSchema": { "type": "object", "properties": {} }
}
Worked tools/call:
{ "jsonrpc": "2.0", "id": 9, "method": "tools/call",
"params": { "name": "list_variables", "arguments": {} } }
When an agent reaches for this tool: drafting a new template, or validating that a proposed {{key}} is one the runtime will actually substitute.
get_account_status
Returns subscription state, LinkedIn connection state, and daily quota usage (50 messages/day on the current plan). This is the precondition check the agent should run before any launch_sequence. If linkedin_connected is false, the sequence will fail at the first send.
{
"name": "get_account_status",
"description": "Returns subscription, LinkedIn connection, and daily quota usage for the current user.",
"inputSchema": { "type": "object", "properties": {} }
}
Worked tools/call:
{ "jsonrpc": "2.0", "id": 10, "method": "tools/call",
"params": { "name": "get_account_status", "arguments": {} } }
When an agent reaches for this tool: at the start of any session, and again right before any execute call. The two-call pattern catches the case where the LinkedIn connection degraded mid-session.
Write tools (9): what the agent does to change state
Write tools mutate the Fintalio database. They do not, by themselves, send anything to LinkedIn. The single tool that crosses the boundary into the outside world is launch_sequence (the next section). Everything below is internal CRUD. Most write tools require the contacts:write or sequences:write ability scope, which a Sanctum token has by default unless the user constrained it at creation time.
create_contact_group
Creates a new segment, or returns the existing one if the name already exists for the current user. Migration 2026_05_02 enforces the (user_id, name) unique constraint at the database level, so this is firstOrCreate semantics: idempotent by design.
{
"name": "create_contact_group",
"description": "Create a new contact group for the current user (or return the existing one with the same name).",
"inputSchema": {
"type": "object",
"properties": { "name": { "type": "string" } }
}
}
Worked tools/call:
{ "jsonrpc": "2.0", "id": 11, "method": "tools/call",
"params": { "name": "create_contact_group",
"arguments": { "name": "Q3 re-engagement" } } }
When an agent reaches for this tool: materializing a segment the user described in natural language (“group everyone at fintech firms in Berlin”), before assigning contacts.
update_contact
Updates one contact’s status, notes, priority, or custom_data. The custom_data field is merged (existing keys preserved, new keys added), not replaced. Status must be one of not_contacted, pending, connected, replied, meeting_scheduled, rejected, ghosted. Priority is 0-5 inclusive.
{
"name": "update_contact",
"description": "Update a contact: status, notes, priority, or merge new custom_data keys (existing keys preserved).",
"inputSchema": {
"type": "object",
"properties": {
"id": { "type": "integer" },
"status": { "type": "string" },
"notes": { "type": "string" },
"priority": { "type": "integer" },
"custom_data": { "type": "object" }
}
}
}
Worked tools/call:
{ "jsonrpc": "2.0", "id": 12, "method": "tools/call",
"params": { "name": "update_contact",
"arguments": { "id": 42, "status": "replied",
"custom_data": { "stage": "qualified" } } } }
When an agent reaches for this tool: writing enrichment back after researching a prospect, marking a stage change, or correcting bad data the user flagged.
pause_sequence
Pauses a running sequence without losing step state. Only valid against status == "running". The paused sequence stops scheduling future messages but keeps its current_step so resume_sequence can pick up where it left off.
{
"name": "pause_sequence",
"description": "Pause a running sequence.",
"inputSchema": {
"type": "object",
"properties": { "id": { "type": "integer" } }
}
}
Worked tools/call:
{ "jsonrpc": "2.0", "id": 13, "method": "tools/call",
"params": { "name": "pause_sequence", "arguments": { "id": 17 } } }
When an agent reaches for this tool: a positive reply just landed and the agent wants to stop further automated sends to that recipient. Paired with update_contact to set status: "replied".
resume_sequence
Resumes a paused sequence and dispatches the next step immediately. Only valid against status == "paused". Sets next_message_at = now() and dispatches ProcessSequenceStep on the queue.
{
"name": "resume_sequence",
"description": "Resume a paused sequence (next message dispatched immediately).",
"inputSchema": {
"type": "object",
"properties": { "id": { "type": "integer" } }
}
}
Worked tools/call:
{ "jsonrpc": "2.0", "id": 14, "method": "tools/call",
"params": { "name": "resume_sequence", "arguments": { "id": 17 } } }
When an agent reaches for this tool: a sequence was paused during a holiday window or because a user asked to “hold for now,” and the condition has lifted.
stop_sequence
Terminates a sequence permanently. Valid against status in ("running", "paused"). Sets status: "stopped" and completed_at: now(). This is irreversible: there is no unstop_sequence tool.
{
"name": "stop_sequence",
"description": "Stop a sequence permanently (running or paused → stopped).",
"inputSchema": {
"type": "object",
"properties": { "id": { "type": "integer" } }
}
}
Worked tools/call:
{ "jsonrpc": "2.0", "id": 15, "method": "tools/call",
"params": { "name": "stop_sequence", "arguments": { "id": 17 } } }
When an agent reaches for this tool: cleanup of off-strategy campaigns, or bulk teardown when a user pivots an entire segment to a different template.
parse_csv
Parses a CSV string (up to 10 MB, 1000 rows) and returns a file_token, the column headers, and a three-row preview. It does not write anything: it informs the mapping the user will pick. The token expires in 30 minutes.
{
"name": "parse_csv",
"description": "Parse a CSV string. Returns a file_token plus headers and 3-row preview to inform the mapping the user wants. Limit: 10 MB / 1000 rows. The token expires in 30 minutes — chain immediately into commit_csv. Mapping is decided by the user from the returned headers; do not assume column meanings.",
"inputSchema": {
"type": "object",
"properties": { "csv_content": { "type": "string" } }
}
}
Worked tools/call:
{ "jsonrpc": "2.0", "id": 16, "method": "tools/call",
"params": { "name": "parse_csv",
"arguments": { "csv_content": "url,first,school\nhttps://linkedin.com/in/jane,Jane,MIT" } } }
When an agent reaches for this tool: phase one of any bulk import. The two-phase pattern (parse first, then commit) is the safest write path in the entire surface, because it forces a human-in-the-loop confirmation between read and write.
commit_csv
Commits a previously-parsed CSV using a user-supplied mapping. The mapping object’s keys are CSV header names; each value picks a destination: a system field (linkedin_url, first_name, etc.), a custom_data key, or ignore. The linkedin_url system field is required: at least one column must map to it.
{
"name": "commit_csv",
"description": "Commit a previously-parsed CSV. mapping is an object whose KEYS are CSV header names (exactly as returned by parse_csv) and whose VALUES describe how to map that column. Each value is one of three shapes: {\"type\":\"system\",\"key\":\"<system_field>\"} where system_field ∈ {first_name, last_name, full_name, linkedin_url, title, company}; {\"type\":\"custom\",\"key\":\"<your-key>\"} to store the column under custom_data[your-key]; or {\"type\":\"ignore\"} to skip the column. ...",
"inputSchema": {
"type": "object",
"properties": {
"file_token": { "type": "string" },
"mapping": { "type": "object" },
"group_id": { "type": "integer" },
"group_name": { "type": "string" }
}
}
}
Worked tools/call:
{ "jsonrpc": "2.0", "id": 17, "method": "tools/call",
"params": { "name": "commit_csv",
"arguments": {
"file_token": "ft_8f3a...",
"mapping": {
"url": { "type": "system", "key": "linkedin_url" },
"first": { "type": "system", "key": "first_name" },
"school": { "type": "custom", "key": "school" }
},
"group_name": "MIT cohort"
} } }
When an agent reaches for this tool: phase two of bulk import, after the user has reviewed the parse_csv preview and approved the mapping.
create_sequence_template
Authors a new outreach template. Each step is connect (LinkedIn invitation, body optional), dm (direct message after connecting, body required), or followup (subsequent message, body required). delay_days is decimal: 0.5 = 12h, 0.0833 ≈ 2h. The tool synthesizes workflow_data so the template can be re-opened in the React editor afterward.
{
"name": "create_sequence_template",
"description": "Create a new sequence template with an ordered list of steps. Each step is one of: connect (LinkedIn invitation, optional note), dm (direct message after connecting), or followup (subsequent message). ... delay_days is the gap from the previous step in days and accepts decimals.",
"inputSchema": {
"type": "object",
"properties": {
"name": { "type": "string" },
"description": { "type": "string" },
"steps": { "type": "array" }
}
}
}
Worked tools/call:
{ "jsonrpc": "2.0", "id": 18, "method": "tools/call",
"params": { "name": "create_sequence_template",
"arguments": {
"name": "Cold connect + 2 follow-ups",
"steps": [
{ "type": "connect", "body": "", "delay_days": 0 },
{ "type": "dm", "body": "Hi {{prenom}}, thanks for...", "delay_days": 2 },
{ "type": "followup", "body": "Following up on my note...", "delay_days": 5 }
]
} } }
When an agent reaches for this tool: shipping a new outreach script the user described in natural language (“write me a three-step sequence for cold-connecting to engineers”).
create_contact
Creates one contact from a LinkedIn URL plus an identity (either first_name + last_name, or full_name). The underlying Prospect is upserted by linkedin_id (the URL slug), so two callers with the same URL share one prospect record. Returns the existing contact unchanged if it already exists for the current user.
{
"name": "create_contact",
"description": "Create a contact (single) from a LinkedIn URL plus identity. Upserts the underlying Prospect by linkedin_id (slug) so two callers with the same URL share one Prospect. Returns the existing contact unchanged if it already exists for the current user. For bulk imports, prefer parse_csv + commit_csv.",
"inputSchema": {
"type": "object",
"properties": {
"linkedin_url": { "type": "string" },
"first_name": { "type": "string" },
"last_name": { "type": "string" },
"full_name": { "type": "string" },
"title": { "type": "string" },
"company_name": { "type": "string" },
"custom_data": { "type": "object" }
}
}
}
Worked tools/call:
{ "jsonrpc": "2.0", "id": 19, "method": "tools/call",
"params": { "name": "create_contact",
"arguments": {
"linkedin_url": "https://linkedin.com/in/jane-doe",
"full_name": "Jane Doe",
"title": "Engineering Lead",
"company_name": "Acme"
} } }
When an agent reaches for this tool: a single new prospect surfaces from research and the user wants to add it to the pipeline. For more than a handful at once, use parse_csv + commit_csv.
Execute tools (1): launch_sequence
launch_sequence is the only tool in the surface that triggers external side effects. Every other tool reads or mutates the Fintalio database. This one schedules real LinkedIn messages to real recipients on the user’s behalf, which is why it is the only tool that requires the sequences:execute ability scope, the only tool that gates on subscription state, and the only tool with a built-in dry-run preview.
launch_sequence
Launches a sequence template against a list of contact ids or a contact group. Without confirm: true, returns a preview: target count, first five names, template name, and counts of contacts already in an active or terminal sequence for the same template. With confirm: true, requires the sequences:execute scope, verifies the user is subscribed (config/plans.php single plan, €69/mo), then creates one Sequence per contact and dispatches ProcessSequenceStep for each.
{
"name": "launch_sequence",
"description": "Launch a sequence template against a list of contacts or a contact group. Without confirm=true, returns a dry-run preview (target count, first 5 names, template name). With confirm=true, requires the sequences:execute scope and triggers real LinkedIn sends. Each existing active sequence for the same (user, contact, template) is skipped.",
"inputSchema": {
"type": "object",
"properties": {
"template_id": { "type": "integer" },
"contact_ids": { "type": "array" },
"contact_group_id": { "type": "integer" },
"confirm": { "type": "boolean" }
}
}
}
Worked tools/call (dry run):
{ "jsonrpc": "2.0", "id": 20, "method": "tools/call",
"params": { "name": "launch_sequence",
"arguments": { "template_id": 3, "contact_group_id": 7 } } }
Worked tools/call (confirmed send):
{ "jsonrpc": "2.0", "id": 21, "method": "tools/call",
"params": { "name": "launch_sequence",
"arguments": { "template_id": 3, "contact_group_id": 7, "confirm": true } } }
When an agent reaches for this tool: the user has approved a campaign and explicitly said “send it.” The dry-run preview is the agent’s last safety net, and the already_completed count in the preview is the loudest signal in the response. If it is non-zero, the agent should re-confirm with the user before passing confirm: true.
What about resources?
The Fintalio MCP surface also exposes three resources alongside the 19 tools. Resources are the long-lived, URI-addressable view-of-the-world: agents subscribe to them to stay current, then call tools to act. The split is conceptual, not technical: anything you can fetch as a resource you can also fetch via the equivalent get_* tool. The reason both exist is host preference: some MCP hosts surface resources in their UI as first-class objects, others treat tools as the primary interface.
| Resource | URI template | What it returns |
|---|---|---|
contact |
fintalio://contact/{id} |
One contact with prospect, status, custom_data, last 10 messages |
sequence |
fintalio://sequence/{id} |
One sequence with status, current_step, full messages history |
template |
fintalio://template/{id} |
One template with its ordered message templates |
All three return application/json and require the read ability. URIs use the custom fintalio:// scheme so hosts can recognise them as Fintalio-owned without parsing.
How does this surface compare to the alternatives?
The table below maps action categories against four sources of LinkedIn capability for AI agents: the official LinkedIn API, Composio’s LinkedIn integration, a generic LinkedIn data provider (read-only screen-scrape category), and the Fintalio MCP. The framing is honest, not antagonistic: every column does some things well, and the right answer for many agents is to stack two MCPs in one Claude Desktop or Cursor host.
| Action category | Official LinkedIn API | Composio (LinkedIn) | Generic LinkedIn data provider | Fintalio MCP |
|---|---|---|---|---|
| Read contacts / connections | Limited | Read | Read | list_contacts, get_contact |
| Send connection requests / DMs | Not in partner API | No | No (read-only) | launch_sequence (via sequence) |
| Multi-step outreach sequences | No | No | No | launch_sequence, pause_sequence, resume_sequence, stop_sequence, create_sequence_template |
| Bulk import via CSV | No | No | No | parse_csv then commit_csv (two-phase) |
| Segment / group contacts | No | No | No | list_contact_groups, create_contact_group |
| Post / comment / ads | Yes | Yes | No | No (intentional, Composio’s domain) |
The honest framing: Fintalio is the LinkedIn-deep MCP for outbound-prospecting agents. Composio is the official-API MCP for content and ads agents. Both can stack in one agent host because Claude Desktop, Cursor, Windsurf, and Claude Code all support multiple MCPs concurrently. For the head-to-head, see /blog/fintalio-mcp-vs-composio-linkedin. For the engineering layer beneath this surface (transport, auth, rate limits, audit logs), see /blog/auth-rate-limits-audit-logs-linkedin-mcp.
How do I actually call these tools?
Three configurations cover the full surface. The first is the Claude Desktop config, the most common install path. The second is the raw curl invocation, for developers who want to verify the endpoint responds before wiring it into an agent host. The third is the MCP registry record, which lets any host that supports auto-discovery find Fintalio without manual config.
Claude Desktop
Paste this into ~/Library/Application Support/Claude/claude_desktop_config.json on macOS, or the equivalent path on Windows and Linux:
{
"mcpServers": {
"fintalio": {
"url": "https://fintalio.com/mcp",
"headers": { "Authorization": "Bearer <YOUR_SANCTUM_TOKEN>" }
}
}
}
Generate the token at /settings/tokens on a subscribed account. The full install walkthrough lives at /blog/claude-desktop-linkedin-agent.
Raw curl
To inspect tools/list from the command line:
curl -N \
-H "Authorization: Bearer <YOUR_SANCTUM_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \
https://fintalio.com/mcp
To call a tool directly:
curl -N \
-H "Authorization: Bearer <YOUR_SANCTUM_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"list_contacts","arguments":{"limit":10}}}' \
https://fintalio.com/mcp
The -N flag disables curl’s output buffering so SSE chunks stream as they arrive.
MCP registry
Fintalio is published in the official Model Context Protocol registry at registry.modelcontextprotocol.io as com.fintalio/linkedin-mcp. Hosts that support registry-driven discovery can resolve the server without a hand-written URL. The registry record points at the same https://fintalio.com/mcp endpoint and lists the same 19 tools documented above.
What changes between versions?
The current server version is 0.0.1 (declared by the #[Version('0.0.1')] attribute on FintalioServer). Tool counts, names, and inputSchema shapes in this reference are pinned to that version. When the version bumps, three things may change: a tool may be added (the 20th), a description may be refined for tool-selection accuracy, or an inputSchema may pick up a new optional property. Removed tools and breaking schema changes will be called out at the top of this page on the version-bump date.
For the build pattern behind the tool surface (transport choices, JSON-RPC framing, OAuth alternatives, idempotency), see the companion reference at /blog/how-to-build-linkedin-mcp-server. For the high-level category overview, see the pillar at /blog/linkedin-mcp. To skip the build and plug the surface into an agent, start a Fintalio subscription.
Plug LinkedIn into your AI agent
Fintalio is the MCP server for LinkedIn. Connect Claude, Cursor, or your custom agent and ship outreach workflows in minutes — with audit logs and rate-limit awareness baked in.
Get started