Connect LinkedIn Personal to Claude: Publish Content and Media Assets
Learn how to connect LinkedIn Personal to Claude using Truto's managed MCP server. Automate post publishing and complex media uploads with step-by-step code.
If you need to connect LinkedIn Personal to Claude to automate social media scheduling, publish multi-format content, or manage media assets, you need a Model Context Protocol (MCP) server. This server acts as the translation layer between Claude's function calls and LinkedIn's RestLi APIs. You can either build and maintain this infrastructure yourself, or use a managed integration platform like Truto to dynamically generate a secure, authenticated MCP server URL. If your team uses ChatGPT, check out our guide on connecting LinkedIn Personal to ChatGPT or explore our broader architectural overview on connecting LinkedIn Personal to AI Agents.
Giving a Large Language Model (LLM) read and write access to LinkedIn Personal is an engineering challenge. You are forced to navigate LinkedIn's custom RestLi protocol, handle fragmented media upload lifecycles, and deal with Universal Resource Names (URNs) instead of standard IDs. Every time an upload flow changes or an endpoint is deprecated, you have to update your server code, redeploy, and test the integration.
This guide breaks down exactly how to use Truto to generate a secure, managed MCP server for LinkedIn Personal, connect it natively to Claude, and execute complex publishing workflows using natural language.
The Engineering Reality of the LinkedIn Personal API
A custom MCP server is a self-hosted integration layer. While the open MCP standard provides a predictable way for models to discover tools, the reality of implementing it against LinkedIn's API is painful. LinkedIn does not use standard REST; it uses RestLi, an internal framework that introduces highly specific quirks into how payloads are structured and updated.
If you decide to build a custom MCP server for LinkedIn Personal, here are the specific integration challenges you will face:
URN-Based Identity and Relationships
LinkedIn does not use standard UUIDs or integer IDs. Everything is a Universal Resource Name (URN). A user is urn:li:person:{sub}, an image is urn:li:image:{id}, and a post is urn:li:share:{id}. To publish a post, the LLM must first fetch the user's OpenID Connect profile to extract the sub claim, format it into the correct URN, and attach it as the author. An LLM lacks this structural context unless your tool schemas strictly guide it to assemble and pass these URNs correctly.
Multi-Step Media Upload Pipelines
Publishing an image or video to LinkedIn is never a single API call. It is a convoluted, multi-step pipeline. For images, you must first call an initialization endpoint to register the media, which returns an upload URL and an image URN. You then PUT the raw bytes to that URL. For videos, it is even worse: you must initialize the upload, chunk the video into exact byte ranges, upload each chunk individually while capturing the ETag response headers, and then submit a finalization request containing those ETags in sequential order. Expecting an LLM to orchestrate HTTP headers and chunked binary uploads natively will fail. Your MCP server must abstract these into discrete, composable tools.
RestLi Partial Updates and Strict Schemas
Updating a post on LinkedIn requires a specific HTTP method (POST with an X-RestLi-Method: PARTIAL_UPDATE header) and a highly nested payload structure ({"patch": {"$set": {...}}}). If your LLM attempts to send a standard PATCH request with a flat JSON body, the LinkedIn API will reject it. Truto's managed proxy layer handles this transformation automatically, allowing the LLM to send flat fields while Truto builds the RestLi-compliant request under the hood.
Opaque Rate Limiting
LinkedIn strictly enforces rate limits, but handles them via standard IETF headers. It is critical to note that Truto does not magically absorb, retry, or apply backoff to these rate limit errors. When the upstream LinkedIn API returns an HTTP 429, Truto passes that error directly to Claude. However, Truto normalizes the upstream rate limit information into standardized headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset). The calling LLM or agent is fully responsible for reading these headers and executing its own retry or backoff logic.
Generating the LinkedIn Personal MCP Server
Truto derives MCP tools dynamically from the underlying integration's resource definitions and documentation. You can generate a self-contained MCP server URL for LinkedIn Personal via the Truto UI or programmatically via the API.
Method 1: Via the Truto UI
For ad-hoc tasks or local agent development, generating a server through the dashboard is the fastest path.
- Navigate to the Integrated Accounts page in your Truto dashboard and select your connected LinkedIn Personal account.
- Click the MCP Servers tab.
- Click Create MCP Server.
- Select your desired configuration. You can filter by methods (e.g., only
readorwrite) or by tags to restrict the LLM's access scope. - Copy the generated MCP server URL (e.g.,
https://api.truto.one/mcp/a1b2c3d4...).
Method 2: Via the Truto API
For programmatic, multi-tenant AI agents, you can generate MCP servers dynamically on behalf of your users. The API validates that the integration has tools available, generates a secure, cryptographically hashed token, and stores the configuration in a distributed key-value store.
curl -X POST https://api.truto.one/integrated-account/{integrated_account_id}/mcp \
-H "Authorization: Bearer YOUR_TRUTO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "LinkedIn Publishing Server",
"config": {
"methods": ["read", "write", "custom"]
}
}'The response contains the secure URL needed to connect Claude:
{
"id": "mcp_srv_987654321",
"name": "LinkedIn Publishing Server",
"config": { "methods": ["read", "write", "custom"] },
"expires_at": null,
"url": "https://api.truto.one/mcp/a1b2c3d4e5f6..."
}Connecting the MCP Server to Claude
Because Truto's MCP servers are fully self-contained, the URL encodes the specific integrated account, tenant, and allowed tools. No additional authentication headers are required by default.
Method 1: Via the Claude UI (Desktop or Web)
If you are using Claude Desktop or Claude for Work:
- Copy the MCP server URL from Truto.
- In Claude, navigate to Settings -> Integrations -> Add MCP Server.
- Paste the Truto URL and click Add.
Claude will immediately execute an MCP initialize handshake, request the tools/list, and make the LinkedIn Personal tools available in your chat context.
Method 2: Via Manual Configuration File
If you are deploying Claude Desktop manually or building a custom LangChain/LangGraph agent, you can mount the server via your claude_desktop_config.json. Since Truto uses HTTP POST for JSON-RPC, you must bridge the Server-Sent Events (SSE) transport using the official MCP CLI wrapper.
{
"mcpServers": {
"linkedin_personal": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-sse",
"https://api.truto.one/mcp/a1b2c3d4e5f6..."
]
}
}
}Restart Claude Desktop, and the tools will automatically populate.
Hero Tools for LinkedIn Personal
Truto exposes a comprehensive suite of proxy APIs for LinkedIn Personal. Below are the highest-leverage tools available for orchestrating content publishing and media management.
list_all_linked_in_personal_me
Fetches the connected member's OpenID Connect profile from LinkedIn's userinfo endpoint. This is the critical first step in any publishing workflow, as it provides the sub claim needed to construct the author URN.
Usage Note: LinkedIn returns a single object containing the sub claim. Use this value to build the author identifier: urn:li:person:{sub}.
"Fetch my LinkedIn profile data and extract the 'sub' claim so we can construct my author URN for publishing a new post."
create_a_linked_in_personal_post
Publishes a post to the connected member's LinkedIn feed. Truto handles assembling the author URN automatically if you pass the sub value, but you must define the commentary and visibility (PUBLIC or CONNECTIONS).
Usage Note: If attaching media, the media must first be uploaded using the respective creation tools. Pass the resulting media URN into content.media.id. For link previews, send content.article. Returns the new post URN from the x-restli-id header.
"Draft a short LinkedIn post about our new AI product launch and publish it to my feed with PUBLIC visibility."
update_a_linked_in_personal_post_by_id
Edits an existing post by its URN. Truto abstracts the complex X-RestLi-Method: PARTIAL_UPDATE logic, allowing the LLM to simply pass flat fields that need changing.
Usage Note: Pass id as the plain post URN (e.g., urn:li:share:12345). You can only update commentary, contentCallToActionLabel, contentLandingPage, and lifecycleState.
"Update the commentary of post urn:li:share:6844785523593134080 to fix a typo, changing the text to 'Excited to announce our new funding round!'."
create_a_linked_in_personal_image
Initiates an image upload (LinkedIn's initializeUpload action). This is step one of the two-step image publishing process.
Usage Note: Requires no body payload. Returns value.uploadUrl, value.uploadUrlExpiresAt, and value.image (the URN you will need for the final post). This only registers the intent to upload.
"Initialize an image upload on LinkedIn so we can get an upload URL and an image URN for the chart I want to share."
create_a_linked_in_personal_upload
Executes the actual file upload for images or documents. This is step two of the media publishing process.
Usage Note: Pass the value.uploadUrl retrieved from the initialization step unchanged as the path, and provide the binary file. The URL is pre-signed, so no LinkedIn tokens are needed. Returns a 201 on success.
"Upload this JPG file using the pre-signed URL we just generated in the image initialization step."
create_a_linked_in_personal_video
Starts a multipart video upload. Video handling in RestLi is heavily fragmented, requiring you to register the upload and receive explicit byte ranges.
Usage Note: Send initializeUploadRequest with fileSizeBytes. Returns the video URN, an array of uploadInstructions (one URL per 4MB chunk), and an uploadToken. The agent must orchestrate uploading each chunk to its respective URL.
"Initialize a video upload for a 12MB MP4 file, retrieve the upload URLs for each 4MB chunk, and store the upload token."
linked_in_personal_videos_complete
Finalizes a multipart video upload after every byte chunk has been successfully transferred to LinkedIn.
Usage Note: Send finalizeUploadRequest with the video URN, uploadToken, and uploadedPartIds (the ETag headers returned from each chunk upload, in exact order). The video will process asynchronously before it can be attached to a post.
"Finalize the video upload by sending the upload token and the ETags we collected from all three chunk uploads."
For the complete inventory of available tools, required payloads, and JSON schemas, visit the LinkedIn Personal integration page.
Workflows in Action
Providing an LLM with discrete tools is only useful if it understands how to chain them together. Here is how Claude handles complex, multi-step LinkedIn operations using Truto's MCP server.
Scenario 1: The Image Publishing Pipeline
Publishing an image requires the LLM to orchestrate identity retrieval, media initialization, binary upload, and final publishing.
"Fetch my LinkedIn profile, initialize an image upload, upload this generated 'launch.jpg' file to the provided URL, and then publish a post with the image attached saying 'We are live!'."
Execution Steps:
list_all_linked_in_personal_me: Claude calls themeendpoint to extract thesubclaim and construct the author URN.create_a_linked_in_personal_image: Claude registers the image, receiving a pre-signeduploadUrland avalue.imageURN.create_a_linked_in_personal_upload: Claude uploads the binary JPG to the pre-signed URL.create_a_linked_in_personal_post: Claude crafts the final payload, embedding the text incommentaryand the image URN intocontent.media.id, successfully publishing the post.
Scenario 2: Multipart Video Orchestration
Video uploads are the ultimate test of an LLM's function-calling capability due to strict byte-chunking and ETag tracking requirements.
"I have a 10MB MP4 demo video. Initialize a video upload on LinkedIn, handle the chunked uploads, complete the process using the returned ETags, and draft a post containing the video."
Execution Steps:
sequenceDiagram
participant Claude as Claude Agent
participant Truto as Truto MCP
participant LinkedIn as LinkedIn API
Claude->>Truto: call create_a_linked_in_personal_video (size: 10MB)
Truto->>LinkedIn: POST /assets?action=registerUpload
LinkedIn-->>Truto: Return video URN, uploadToken, 3x URLs
Truto-->>Claude: Return URLs and instructions
rect rgb(245, 245, 245)
Note right of Claude: Agent executes direct PUT requests to URLs<br>and captures ETag response headers.
end
Claude->>Truto: call linked_in_personal_videos_complete
Note right of Claude: Passes video URN, uploadToken, <br>and array of captured ETags
Truto->>LinkedIn: POST /assets?action=finalizeUpload
LinkedIn-->>Truto: 200 OK
Claude->>Truto: call create_a_linked_in_personal_post
Note right of Claude: Attaches video URN to post
Truto->>LinkedIn: POST /ugcPosts
LinkedIn-->>Truto: 201 Created (x-restli-id)Result: Claude successfully navigates the RestLi multipart constraints, tracks state (ETags) across parallel HTTP requests, and binds the final processed video URN to a new user feed post.
Security and Access Control
Exposing an authenticated LinkedIn channel to an autonomous agent carries inherent risk. Truto's MCP architecture provides native security controls to restrict the LLM's operational radius.
- Method Filtering: Limit the MCP server to specific HTTP actions. Pass
methods: ["read"]during server creation to prevent the LLM from publishing or deleting posts, restricting it strictly to profile lookups. - Tag Filtering: Restrict tools by functional domain. If the integration defines
tool_tags, you can passtags: ["publishing"]to expose only media and post endpoints, hiding unrelated account management resources. - Additional Authentication (
require_api_token_auth): By default, possessing the MCP server URL grants access. For sensitive environments, enabling this flag forces the client to also provide a valid Truto API token in theAuthorizationheader, meaning the URL alone is useless if leaked. - Automatic Expiration (
expires_at): For temporary workflows—like granting a contractor agent access to publish a campaign—set an ISO datetime. Once expired, a distributed cleanup routine purges the server configuration from memory and storage instantly.
Architecting for Agentic Publishing
Building a custom integration for LinkedIn Personal requires an intimate understanding of the RestLi protocol, URN management, and chunked binary handling. By using Truto to generate a managed MCP server, you offload the complexities of rate limit normalization, RestLi schema transformations, and OAuth token lifecycles.
Instead of maintaining fragile API wrappers and mapping code, your engineering team can focus on what actually matters: designing LLM prompts and agent architectures that produce high-quality, engaging social content.
FAQ
- Does Truto automatically handle LinkedIn's rate limits?
- No. Truto passes HTTP 429 rate limit errors directly to Claude and normalizes the response headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset) per IETF specs. The LLM or agent is responsible for implementing retry and backoff logic.
- How do I update a LinkedIn post via the MCP server?
- You use the update_a_linked_in_personal_post_by_id tool. Truto automatically translates the LLM's flat JSON input into the required X-RestLi-Method: PARTIAL_UPDATE request that LinkedIn's API expects.
- Can Claude upload videos to LinkedIn using this integration?
- Yes. Claude can execute the multi-step video upload process by first calling create_a_linked_in_personal_video to get chunk URLs, uploading the bytes and capturing ETags, and finally calling linked_in_personal_videos_complete.
- How do I restrict the MCP server so Claude can only read data, not post?
- When generating the MCP server via the Truto UI or API, set the methods filter to ["read"]. This ensures tools like create_a_linked_in_personal_post are entirely hidden from the LLM.