Skip to main content
Glama
ertiqah
by ertiqah

publish_twitter_post

Publish text posts to Twitter by specifying the tweet content. Automate your social media updates.

Instructions

Publish a text post (tweet) to Twitter.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
post_textYesThe text content of the tweet (maximum 280 characters).

Implementation Reference

  • cli.js:354-442 (handler)
    The handler for the 'publish_twitter_post' tool. Extracts the API key from env, validates the 'post_text' argument, sends a POST request to the backend Twitter API (https://ligosocial.com/api/mcp/publish-twitter-post), and returns success/failure responses.
    } else if (name === 'publish_twitter_post') {
        console.error(`${packageName}: Received call for publish_twitter_post tool.`);
        const apiKey = process.env.LINKEDIN_MCP_API_KEY;
        const postText = args?.post_text;
    
        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;
        }
    
        try {
            const headers = { "Authorization": `Bearer ${apiKey}`, "Content-Type": "application/json", "Accept": "application/json" };
            const payload = { 
              "post_text": postText
            };
            console.error(`${packageName}: Calling Twitter API: ${backendTwitterApiUrl} with payload:`, JSON.stringify(payload, null, 2));
            const apiResponse = await axios.post(backendTwitterApiUrl, payload, { headers, timeout: 60000 });
            console.error(`${packageName}: Twitter API response status: ${apiResponse.status}`);
            console.error(`${packageName}: Twitter API response data:`, JSON.stringify(apiResponse.data, null, 2));
    
            if (apiResponse.data && apiResponse.data.success) {
                // Include tweet_id from backend if available
                const tweetDetails = apiResponse.data.tweet_id ? 
                  ` (Tweet ID: ${apiResponse.data.tweet_id})` : '';
                
                sendResponse({ 
                  jsonrpc: "2.0", 
                  result: { 
                    content: [
                      {
                        type: "text",
                        text: `✅ Successfully published tweet to Twitter${tweetDetails}.`
                      }
                    ],
                    isError: false
                  }, 
                  id 
                });
            } else {
                const errorMessage = apiResponse.data?.error || "Backend API Error (no detail)";
                console.error(`${packageName}: Twitter API Error: ${errorMessage}`);
                // Report error within the result object
                sendResponse({ 
                  jsonrpc: "2.0", 
                  result: {
                    content: [
                      {
                        type: "text",
                        text: `Failed to publish tweet to Twitter: ${errorMessage}`
                      }
                    ],
                    isError: true
                  }, 
                  id 
                });
            }
    
        } catch (error) {
            let errorMessage = `Failed to call Twitter API: ${error.message}`;
            // Determine a user-facing error message based on the error type
            if (error.response) {
                // Extract the error message directly from the backend response
                const backendError = error.response.data?.error || error.response.data?.message;
                errorMessage = backendError || `Twitter API Error (Status ${error.response.status})`;
                console.error(`${packageName}: Twitter API Error Response:`, error.response.data); 
            } else if (error.request) {
                errorMessage = "No response received from Twitter API.";
            }
            console.error(`${packageName}: ${errorMessage}`);
            
            // Report error within the result object
            sendResponse({ 
              jsonrpc: "2.0", 
              result: { 
                content: [
                  {
                    type: "text",
                    text: `Failed to publish tweet to Twitter: ${errorMessage}`
                  }
                ],
                isError: true
              }, 
              id 
            });
        }
  • Schema/tool definition for 'publish_twitter_post' returned in the 'tools/list' response. Defines the name, description, and input schema (requiring a 'post_text' string).
        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"]
        }
    },
  • cli.js:1200-1392 (registration)
    Registration of 'publish_twitter_post' via the MCP 'tools/list' response. The tool is listed among the available tools.
    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: {}
                        }
                    }
                ]
            }
        });
Behavior2/5

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

No annotations provided, so the description alone must disclose behavior. It only states the core action, with no mention of authentication, rate limits, or post limits beyond what the schema's parameter description covers.

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 sentence that conveys the essential purpose without any wasted words. It is front-loaded and concise.

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?

Despite having only one parameter and no output schema, the description fails to mention return values or side effects. For a write operation, behavioral details like authentication requirements or success/failure indicators are missing.

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% for the single parameter, so the baseline is 3. The tool description adds nothing beyond what the schema already provides.

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 identifies the action (publish), the resource (text post/tweet), and the platform (Twitter). It distinguishes from sibling tools which are all LinkedIn-related.

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

Usage Guidelines2/5

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

No explicit guidance on when to use this tool or when not to; no alternatives mentioned. The context signals that it is for Twitter, but usage context is minimal.

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