Skip to main content
Glama
ertiqah
by ertiqah

publish_linkedin_post

Post text and optional media to LinkedIn. Specify post text plus image or video URLs to attach media.

Instructions

Publish a text post to LinkedIn, optionally including media (images/videos) specified by URL.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
post_textYesThe text content of the LinkedIn post.
mediaNoOptional. A list of media items to attach to the post. Each item must have a 'file_url' pointing to a direct image or video URL and a 'filename'.

Implementation Reference

  • cli.js:159-253 (handler)
    The handler function for 'publish_linkedin_post' tool. Validates API key, post_text, and optional media arguments, then calls the backend API at https://ligosocial.com/api/mcp/publish-linkedin-post via axios POST and returns success/error response.
    if (name === 'publish_linkedin_post') {
        console.error(`${packageName}: Received call for publish_linkedin_post tool.`);
        const apiKey = process.env.LINKEDIN_MCP_API_KEY;
        const postText = args?.post_text;
        const media = args?.media;
    
        if (!apiKey) {
            sendResponse({ jsonrpc: "2.0", error: { code: -32001, message: "Server Configuration Error: API Key not set." }, id });
            return;
        }
        if (typeof postText !== 'string' || postText.trim() === '') {
            sendResponse({ jsonrpc: "2.0", error: { code: -32602, message: "Invalid arguments: 'post_text' (string) required." }, id });
            return;
        }
        if (media && (!Array.isArray(media) || media.some(item => !item || typeof item !== 'object' || typeof item.file_url !== 'string' || typeof item.filename !== 'string'))) {
             sendResponse({ jsonrpc: "2.0", error: { code: -32602, message: "Invalid arguments: 'media' must be an array of objects, each with 'file_url' and 'filename' strings." }, id });
             return;
        }
    
        try {
            const headers = { "Authorization": `Bearer ${apiKey}`, "Content-Type": "application/json", "Accept": "application/json" };
            const payload = { 
              "post_text": postText,
              "media": media || []
             };
            console.error(`${packageName}: Calling backend API: ${backendApiUrl} with payload:`, JSON.stringify(payload, null, 2));
            const apiResponse = await axios.post(backendApiUrl, payload, { headers, timeout: 60000 });
            console.error(`${packageName}: Backend API response status: ${apiResponse.status}`);
            console.error(`${packageName}: Backend API response data:`, JSON.stringify(apiResponse.data, null, 2));
    
            if (apiResponse.data && apiResponse.data.success) {
                // Include post_urn from backend if available
                const postDetails = apiResponse.data.post_urn ? 
                  ` (Post ID: ${apiResponse.data.post_urn})` : '';
                
                sendResponse({ 
                  jsonrpc: "2.0", 
                  result: { 
                    content: [
                      {
                        type: "text",
                        text: `✅ Successfully published post to LinkedIn${postDetails}.`
                      }
                    ],
                    isError: false
                  }, 
                  id 
                });
            } else {
                const errorMessage = apiResponse.data?.error || "Backend API Error (no detail)";
                console.error(`${packageName}: Backend API Error: ${errorMessage}`);
                // Report error within the result object
                sendResponse({ 
                  jsonrpc: "2.0", 
                  result: {
                    content: [
                      {
                        type: "text",
                        text: `Failed to publish post to LinkedIn: ${errorMessage}`
                      }
                    ],
                    isError: true // Indicate tool execution error
                  }, 
                  id 
                });
            }
    
        } catch (error) {
            let errorMessage = `Failed to call backend API: ${error.message}`;
            // Preserve the original error message from the backend if available
            if (error.response) {
                // Extract the error message directly from the backend response
                const backendError = error.response.data?.error || error.response.data?.message;
                errorMessage = backendError || `Backend API Error (Status ${error.response.status})`;
                console.error(`${packageName}: Backend API Error Response:`, error.response.data); 
            } else if (error.request) {
                errorMessage = "No response received from backend API.";
            }
            console.error(`${packageName}: ${errorMessage}`);
            
            // Report error within the result object
            sendResponse({ 
              jsonrpc: "2.0", 
              result: { 
                content: [
                  {
                    type: "text",
                    text: `Failed to publish post to LinkedIn: ${errorMessage}`
                  }
                ],
                isError: true // Indicate tool execution error
              }, 
              id 
            });
        }
  • cli.js:1206-1238 (registration)
    Tool registration (tools/list response) for 'publish_linkedin_post' tool. Defines name, description, and inputSchema including post_text (required string) and media (optional array of objects with file_url and filename).
    tools: [
        {
            name: "publish_linkedin_post",
            description: "Publish a text post to LinkedIn, optionally including media (images/videos) specified by URL.",
            inputSchema: {
                type: "object",
                properties: {
                    post_text: {
                        type: "string",
                        description: "The text content of the LinkedIn post."
                    },
                    media: {
                        type: "array",
                        description: "Optional. A list of media items to attach to the post. Each item must have a 'file_url' pointing to a direct image or video URL and a 'filename'.",
                        items: {
                            type: "object",
                            properties: {
                                file_url: {
                                    type: "string",
                                    description: "A direct URL to the image or video file (e.g., ending in .jpg, .png, .mp4)."
                                },
                                filename: {
                                    type: "string",
                                    description: "A filename for the media item (e.g., 'promo_video.mp4')."
                                }
                            },
                            required: ["file_url", "filename"]
                        }
                    }
                },
                required: ["post_text"]
            }
        },
  • cli.js:11-11 (helper)
    Backend API URL constant used by the publish_linkedin_post handler to make the HTTP POST request.
    const backendApiUrl = 'https://ligosocial.com/api/mcp/publish-linkedin-post';
Behavior2/5

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

No annotations provided. The description only indicates a create/mutation action without disclosing side effects, error handling, rate limits, or return information.

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

Conciseness5/5

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

Single, front-loaded sentence with no redundancy. Efficient delivery of core purpose.

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

Completeness2/5

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

Missing behavioral context (e.g., success output, error cases) and media constraints (formats, size limits). For a tool with no output schema, description should clarify return value.

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

Parameters3/5

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

Schema covers both parameters with descriptions. The description slightly reinforces media type as images/videos by URL, but adds no new constraints or formatting details beyond schema.

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

Purpose5/5

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

The description clearly states the action (publish), the target resource (text post to LinkedIn), and optional media. It effectively distinguishes from siblings like schedule_linkedin_post and generate_linkedin_post.

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

Usage Guidelines3/5

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

The description implies usage for immediate publishing, but does not explicitly state when to use this tool over alternatives like schedule_linkedin_post or under what conditions media is supported.

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

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ertiqah/linkedin-mcp-runner'

If you have feedback or need assistance with the MCP directory API, please join our Discord server