Skip to main content
Glama
ertiqah
by ertiqah

schedule_linkedin_post

Schedule a LinkedIn text post at a future date and time, with optional media attachments from URLs.

Instructions

Schedule a text post for LinkedIn at a specific future date and time, optionally including media (images/videos) specified by URL.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
post_textYesThe text content of the LinkedIn post to be scheduled.
scheduled_dateYesThe 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.
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:254-353 (handler)
    The handler for the 'schedule_linkedin_post' tool. It validates the API key, post_text, scheduled_date (ISO 8601 format), and optional media parameters, then calls the backend scheduling API (https://ligosocial.com/api/mcp/schedule-linkedin-post) via axios POST and returns the result as a JSON-RPC response.
    } else if (name === 'schedule_linkedin_post') {
        console.error(`${packageName}: Received call for schedule_linkedin_post tool.`);
        const apiKey = process.env.LINKEDIN_MCP_API_KEY;
        const postText = args?.post_text;
        const scheduledDate = args?.scheduled_date;
        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 (typeof scheduledDate !== 'string' || scheduledDate.trim() === '') {
            sendResponse({ jsonrpc: "2.0", error: { code: -32602, message: "Invalid arguments: 'scheduled_date' (ISO 8601 string) required." }, id });
            return;
        }
        if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/.test(scheduledDate)) {
           sendResponse({ jsonrpc: "2.0", error: { code: -32602, message: "Invalid arguments: 'scheduled_date' must be a valid ISO 8601 string (e.g., 2025-12-31T10:00:00Z)." }, 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,
              "scheduled_date": scheduledDate,
              "media": media || []
             };
            console.error(`${packageName}: Calling backend schedule API: ${backendScheduleApiUrl} with payload:`, JSON.stringify(payload, null, 2));
            const apiResponse = await axios.post(backendScheduleApiUrl, payload, { headers, timeout: 60000 });
            console.error(`${packageName}: Backend schedule API response status: ${apiResponse.status}`);
            console.error(`${packageName}: Backend schedule API response data:`, JSON.stringify(apiResponse.data, null, 2));
    
            if (apiResponse.data && apiResponse.data.success) {
                 const scheduleDetails = apiResponse.data.scheduled_job_id ?
                   ` (Scheduled Job ID: ${apiResponse.data.scheduled_job_id})` : '';
                 sendResponse({
                   jsonrpc: "2.0",
                   result: {
                     content: [
                       {
                         type: "text",
                         text: `✅ Successfully scheduled post for LinkedIn${scheduleDetails}.`
                       }
                     ],
                     isError: false
                   },
                   id
                 });
            } else {
                const errorMessage = apiResponse.data?.error || "Backend API Error (no detail)";
                console.error(`${packageName}: Backend Schedule API Error: ${errorMessage}`);
                sendResponse({
                  jsonrpc: "2.0",
                  result: {
                    content: [
                      {
                        type: "text",
                        text: `Failed to schedule post for LinkedIn: ${errorMessage}`
                      }
                    ],
                    isError: true // Indicate tool execution error
                  },
                  id
                });
            }
    
        } catch (error) {
            let errorMessage = `Failed to call backend schedule 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}: Backend Schedule API Error Response:`, error.response.data);
            } else if (error.request) {
                errorMessage = "No response received from backend schedule API.";
            }
            console.error(`${packageName}: ${errorMessage}`);
    
            sendResponse({
              jsonrpc: "2.0",
              result: {
                content: [
                  {
                    type: "text",
                    text: `Failed to schedule post for LinkedIn: ${errorMessage}`
                  }
                ],
                isError: true // Indicate tool execution error
              },
              id
            });
        }
  • cli.js:1239-1274 (registration)
    The tool registration for 'schedule_linkedin_post' in the tools/list response. It declares the tool name, description, and inputSchema specifying required fields (post_text, scheduled_date) and optional media array.
    {
        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"]
        }
    },
  • cli.js:12-20 (helper)
    The backend URL constant used by the schedule_linkedin_post handler to send scheduling requests.
    const backendScheduleApiUrl = 'https://ligosocial.com/api/mcp/schedule-linkedin-post';
    const backendTwitterApiUrl = 'https://ligosocial.com/api/mcp/publish-twitter-post';
    const backendAnalyzeChatApiUrl = 'https://ligosocial.com/api/mcp/analyze-linkedin-chat';
    const backendGeneratePostApiUrl = 'https://ligosocial.com/api/mcp/generate-linkedin-post';
    const backendLinkedinPostsApiUrl = 'https://ligosocial.com/api/mcp/linkedin/posts';
    const backendLinkedinProfileApiUrl = 'https://ligosocial.com/api/mcp/linkedin/profile';
    const backendLinkedinSetUrlApiUrl = 'https://ligosocial.com/api/mcp/linkedin/set-url';
    const backendLinkedinRefreshProfileApiUrl = 'https://ligosocial.com/api/mcp/linkedin/refresh-profile';
    const backendLinkedinRefreshPostsApiUrl = 'https://ligosocial.com/api/mcp/linkedin/refresh-posts';
Behavior3/5

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

No annotations provided, so the description must carry behavioral info. It discloses the tool schedules at a future date, but does not mention side effects (e.g., will the post be automatically published?), rate limits, or error handling for past dates (though schema enforces future). Adequate but not rich.

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 sentence, front-loaded with the action and resource. No wasted words. Every part earns its place.

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

Completeness4/5

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

For a tool with 3 parameters and no output schema, the description covers the main purpose and optional media. It lacks mention of return value or confirmation, but still provides sufficient context for an agent to use it correctly.

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 coverage is 100% with descriptions for all parameters. The description adds minimal extra meaning beyond 'optionally including media'. Baseline 3 is appropriate as the schema does the heavy lifting.

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 tool schedules a text post for LinkedIn at a specific future time, optionally with media. It uses specific verb (schedule) and resource (LinkedIn post), and the sibling 'publish_linkedin_post' implies immediate publishing, distinguishing this tool.

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

Usage Guidelines4/5

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

The description implies usage for scheduling future posts, and the sibling 'publish_linkedin_post' suggests an alternative for immediate publishing. However, it lacks explicit when-not-to-use or conditions like authentication requirements.

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