Skip to main content
Glama
ertiqah
by ertiqah

generate_linkedin_post

Transform any content into three LinkedIn post variants to optimize engagement. Input articles, newsletters, or notes to generate professional posts.

Instructions

Generate three LinkedIn post variants from any content (article, newsletter, notes, etc.) to optimize engagement.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
contentYesThe source content to transform into LinkedIn posts. Can be articles, emails, newsletters, notes, etc.
content_typeNoOptional. A short description of the content type (e.g., 'article', 'newsletter', 'notes'). Defaults to 'article'.

Implementation Reference

  • cli.js:512-627 (handler)
    Handler for the 'generate_linkedin_post' tool. Validates input parameters 'content' and optional 'content_type', proxies the request to the backend API (https://ligo.ertiqah.com/api/mcp/generate-linkedin-post), handles the response containing post variants, and returns formatted text content with success or error status.
    } else if (name === 'generate_linkedin_post') {
        console.error(`${packageName}: Received call for generate_linkedin_post tool.`);
        const apiKey = process.env.LINKEDIN_MCP_API_KEY;
        const content = args?.content;
        const contentType = args?.content_type || 'article';
    
        if (!apiKey) {
            sendResponse({ jsonrpc: "2.0", error: { code: -32001, message: "Server Configuration Error: API Key not set." }, id });
            return;
        }
        if (typeof content !== 'string' || content.trim() === '') {
            sendResponse({ jsonrpc: "2.0", error: { code: -32602, message: "Invalid arguments: 'content' (string) required." }, id });
            return;
        }
    
        try {
            const headers = { "Authorization": `Bearer ${apiKey}`, "Content-Type": "application/json", "Accept": "application/json" };
            const payload = { 
              "content": content,
              "contentType": contentType
            };
            console.error(`${packageName}: Calling generate post API: ${backendGeneratePostApiUrl} with payload:`, JSON.stringify(payload, null, 2));
            const apiResponse = await axios.post(backendGeneratePostApiUrl, payload, { headers, timeout: 60000 });
            console.error(`${packageName}: Generate post API response status: ${apiResponse.status}`);
            console.error(`${packageName}: Generate post API response data:`, JSON.stringify(apiResponse.data, null, 2));
    
            if (apiResponse.data && apiResponse.data.success) {
                if (apiResponse.data.variants && Array.isArray(apiResponse.data.variants)) {
                    // Handle the case where we get an array of variant posts
                    const variants = apiResponse.data.variants;
                    
                    // Create content items - first a text description, then one item for each variant
                    const contentItems = [
                        {
                            type: "text",
                            text: `Generated ${variants.length} LinkedIn post variants:`
                        }
                    ];
                    
                    // Add each variant as a separate text item for better formatting
                    variants.forEach((variant, index) => {
                        contentItems.push({
                            type: "text",
                            text: `Option ${index + 1}:\n${variant}`
                        });
                    });
                    
                    sendResponse({ 
                        jsonrpc: "2.0", 
                        result: { 
                            content: contentItems,
                            isError: false
                        }, 
                        id 
                    });
                } else {
                    // Fallback for backward compatibility
                    sendResponse({ 
                        jsonrpc: "2.0", 
                        result: { 
                            content: [
                                {
                                    type: "text",
                                    text: apiResponse.data.message || "Successfully generated LinkedIn post, but no variants were returned. Please check the backend implementation."
                                }
                            ],
                            isError: false
                        }, 
                        id 
                    });
                }
            } else {
                const errorMessage = apiResponse.data?.error || "Backend API Error (no detail)";
                console.error(`${packageName}: Generate post API Error: ${errorMessage}`);
                sendResponse({ 
                  jsonrpc: "2.0", 
                  result: {
                    content: [
                      {
                        type: "text",
                        text: `Failed to generate LinkedIn post: ${errorMessage}`
                      }
                    ],
                    isError: true
                  }, 
                  id 
                });
            }
    
        } catch (error) {
            let errorMessage = `Failed to call generate post API: ${error.message}`;
            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}: Generate post API Error Response:`, error.response.data); 
            } else if (error.request) {
                errorMessage = "No response received from generate post API.";
            }
            console.error(`${packageName}: ${errorMessage}`);
            
            sendResponse({ 
              jsonrpc: "2.0", 
              result: { 
                content: [
                  {
                    type: "text",
                    text: `Failed to generate LinkedIn post: ${errorMessage}`
                  }
                ],
                isError: true
              }, 
              id 
            });
        }
    } else if (name === 'get_linkedin_posts') {
  • Input schema definition for the 'generate_linkedin_post' tool, returned in the 'tools/list' MCP response. Specifies required 'content' string and optional 'content_type'.
        name: "generate_linkedin_post",
        description: "Generate three LinkedIn post variants from any content (article, newsletter, notes, etc.) to optimize engagement.",
        inputSchema: {
            type: "object",
            properties: {
                content: {
                    type: "string",
                    description: "The source content to transform into LinkedIn posts. Can be articles, emails, newsletters, notes, etc."
                },
                content_type: {
                    type: "string",
                    description: "Optional. A short description of the content type (e.g., 'article', 'newsletter', 'notes'). Defaults to 'article'."
                }
            },
            required: ["content"]
        }
    },
  • cli.js:1181-1375 (registration)
    The 'tools/list' handler statically registers all available tools including 'generate_linkedin_post' by returning the full list with schemas in the MCP protocol response.
    if (method === 'tools/list') {
        console.error(`${packageName}: Received tools/list request, sending known tool.`);
        sendResponse({
            jsonrpc: "2.0",
            id: id,
            result: {
                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"]
                        }
                    },
                    {
                        name: "schedule_linkedin_post",
                        description: "Schedule a text post for LinkedIn at a specific future date and time, optionally including media (images/videos) specified by URL.",
                        inputSchema: {
                            type: "object",
                            properties: {
                                post_text: {
                                    type: "string",
                                    description: "The text content of the LinkedIn post to be scheduled."
                                },
                                scheduled_date: {
                                    type: "string",
                                    description: "The date and time to publish the post, in ISO 8601 format (e.g., '2025-12-31T10:00:00Z' or '2025-12-31T15:30:00+05:30'). Must be in the future."
                                },
                                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., 'meeting_notes.mp4')."
                                            }
                                        },
                                        required: ["file_url", "filename"]
                                    }
                                }
                            },
                            required: ["post_text", "scheduled_date"]
                        }
                    },
                    {
                        name: "publish_twitter_post",
                        description: "Publish a text post (tweet) to Twitter.",
                        inputSchema: {
                            type: "object",
                            properties: {
                                post_text: {
                                    type: "string",
                                    description: "The text content of the tweet (maximum 280 characters)."
                                }
                            },
                            required: ["post_text"]
                        }
                    },
                    {
                        name: "analyze_linkedin_chat",
                        description: "Ask questions about the user's LinkedIn profile, content, or network, with support for multi-turn conversations.",
                        inputSchema: {
                            type: "object",
                            properties: {
                                query: {
                                    type: "string",
                                    description: "The question or request about LinkedIn data to be analyzed."
                                },
                                conversation_history: {
                                    type: "array",
                                    description: "Optional. Previous messages in the conversation for context. Each message must have 'role' (user/assistant) and 'content' (text).",
                                    items: {
                                        type: "object",
                                        properties: {
                                            role: {
                                                type: "string",
                                                description: "The sender of the message: 'user' or 'assistant'."
                                            },
                                            content: {
                                                type: "string",
                                                description: "The text content of the message."
                                            }
                                        },
                                        required: ["role", "content"]
                                    }
                                }
                            },
                            required: ["query"]
                        }
                    },
                    {
                        name: "generate_linkedin_post",
                        description: "Generate three LinkedIn post variants from any content (article, newsletter, notes, etc.) to optimize engagement.",
                        inputSchema: {
                            type: "object",
                            properties: {
                                content: {
                                    type: "string",
                                    description: "The source content to transform into LinkedIn posts. Can be articles, emails, newsletters, notes, etc."
                                },
                                content_type: {
                                    type: "string",
                                    description: "Optional. A short description of the content type (e.g., 'article', 'newsletter', 'notes'). Defaults to 'article'."
                                }
                            },
                            required: ["content"]
                        }
                    },
                    {
                        name: "get_linkedin_posts",
                        description: "Retrieve the user's recent LinkedIn posts with engagement metrics.",
                        inputSchema: {
                            type: "object",
                            properties: {
                                limit: {
                                    type: "number",
                                    description: "Optional. Number of posts to retrieve (1-20). Defaults to 5."
                                }
                            }
                        }
                    },
                    {
                        name: "get_linkedin_profile",
                        description: "Retrieve the user's LinkedIn profile information including headline, summary, experience, and education.",
                        inputSchema: {
                            type: "object",
                            properties: {}
                        }
                    },
                    {
                        name: "set_linkedin_url",
                        description: "Set or update the LinkedIn profile URL to analyze. Required before using profile/posts retrieval tools if not set previously.",
                        inputSchema: {
                            type: "object",
                            properties: {
                                linkedin_url: {
                                    type: "string",
                                    description: "The full LinkedIn profile URL (e.g., https://www.linkedin.com/in/username/)"
                                }
                            },
                            required: ["linkedin_url"]
                        }
                    },
                    {
                        name: "refresh_linkedin_profile",
                        description: "Force a refresh of the LinkedIn profile data to update any recent changes.",
                        inputSchema: {
                            type: "object",
                            properties: {}
                        }
                    },
                    {
                        name: "refresh_linkedin_posts",
                        description: "Force a refresh of LinkedIn posts data to capture recently published content.",
                        inputSchema: {
                            type: "object",
                            properties: {}
                        }
                    }
                ]
            }
        });
        return;
    } else if (method === 'resources/list' || method === 'prompts/list') {
  • cli.js:15-15 (helper)
    Configuration constant defining the backend API endpoint URL used by the generate_linkedin_post handler.
    const backendGeneratePostApiUrl = 'https://ligo.ertiqah.com/api/mcp/generate-linkedin-post';
Behavior2/5

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

No annotations are provided, so the description carries the full burden of behavioral disclosure. It mentions generating 'three LinkedIn post variants' and 'optimize engagement', which gives some context on output format and goal. However, it lacks details on rate limits, authentication needs, error handling, or whether this is a read-only or mutative operation (though 'generate' suggests creation, not modification of existing data).

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?

The description is a single, efficient sentence that front-loads the key action ('Generate three LinkedIn post variants') and purpose ('to optimize engagement'). It avoids unnecessary words and clearly communicates the tool's function without redundancy.

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

Completeness3/5

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

Given the tool has 2 parameters with full schema coverage but no annotations or output schema, the description is moderately complete. It covers the purpose and input context well, but as a generation tool with no output schema, it should ideally hint at the return format (e.g., 'three variants') or behavioral traits like non-destructive nature. It's adequate but has gaps in behavioral transparency.

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 description coverage is 100%, so the input schema already fully documents the two parameters ('content' and 'content_type'). The description adds minimal value beyond the schema by mentioning 'any content (article, newsletter, notes, etc.)', which aligns with the schema's description but doesn't provide additional syntax, format, or usage details. This meets the baseline for high schema coverage.

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

Purpose4/5

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

The description clearly states the tool's purpose: 'Generate three LinkedIn post variants from any content... to optimize engagement.' It specifies the verb ('generate'), resource ('LinkedIn post variants'), and outcome ('optimize engagement'). However, it doesn't explicitly differentiate from siblings like 'publish_linkedin_post' or 'schedule_linkedin_post', which are about posting rather than generating content.

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 by stating it transforms 'any content (article, newsletter, notes, etc.)' into LinkedIn posts, suggesting it's for content creation from various sources. However, it doesn't provide explicit guidance on when to use this tool versus alternatives like 'publish_linkedin_post' (for posting) or 'analyze_linkedin_chat' (for analysis), nor does it mention any exclusions or prerequisites.

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