Skip to main content
Glama

create_post

Create a new social media post, story, or reel.

IMPORTANT — Before calling this tool, make sure you have all required information from the user. If anything is missing, ASK the user before calling:

  1. Workspace: If the user has only one workspace, just use it (no need to ask). If the user has named a workspace in their request, switch to it once and remember it for the rest of the conversation. If multiple workspaces exist and the user has NOT named one, call list_workspaces and ASK which workspace to post to before continuing. Never silently pick a workspace when more than one exists — each workspace has different connected channels and different audiences. After a successful create/schedule/publish, mention the workspace name in your reply for clarity (e.g. "Scheduled to the Acme workspace for Tuesday 3pm").

  2. Content/caption: What text should the post have? If captions differ per platform, use one call with an object: { "default": "fallback text", "linkedin": "long version", "threads": "short version", "x": "short version", "bluesky": "short version" }. Always prefer one call per topic. RESPECT character limits per platform (see below).

  3. Channels: Which platforms to post to? Call list_accounts to show available options for the active workspace. Ask the user which channels to use.

  4. Schedule: When should it be published? (Or save as draft?)

  5. Media (REQUIRED for some types):

    • Stories: ALWAYS require an image or video. A story can carry up to 10 media items: each item is one slide, published as its own story in the order given. Ask the user which slides and in what order.

    • Reels: ALWAYS require a video.

    • Instagram posts: ALWAYS require at least one image or video.

    • TikTok posts: ALWAYS require at least one image or video.

    • Pinterest posts: ALWAYS require an image AND a board_id.

    • Other platforms (LinkedIn Profile, LinkedIn Page, X, Bluesky, etc.): Media is optional.

  6. Platform-specific options (ask only when relevant):

    • Pinterest board (auto-default to first board): If Pinterest is in channels and pinterest.board_id is NOT provided, do NOT block on asking the user — and do NOT skip Pinterest. Instead:

      1. Call get_account on the Pinterest account — the response includes a Pinterest Boards table with each board's name and ID.

      2. Use the FIRST board in that list as pinterest.board_id automatically.

      3. In your reply, explicitly mention which board you used (e.g. "Posted to your 'Marketing' board on Pinterest — let me know if you'd prefer a different one and I'll move it.") so the user can correct course. If the user named a board ("post to my Marketing board") or specified one in the request, match it (case-insensitive) against the list and use that one instead of the first.

    • YouTube: Title, privacy status, tags?

    • TikTok: Privacy level?

    • X threads vs long-form: A chained "thread" (the user explicitly asks for one) → pass x.thread_parts as an array of 2–25 { text } objects (each ≤ 280 chars); the top-level content is then ignored for X. A single long-form post on a Premium / Premium+ account → just put the full text (up to 25,000 chars) in content — no threading needed (check platform_details.subscription_type via list_accounts). On free / Basic, X caps a single post at 280 chars, so either split into a thread or shorten. Never cram "1/", "2/" prefixes into content — that posts one tweet, not a thread.

    • X posts containing a link use credits: X's API charges more for posts whose text contains a URL; OmniSocials passes that platform fee through as credits from the organisation's existing balance (threads: per link-containing part). Only a link written with http:// or https:// counts; a bare domain (brand.com) or a www. link is free. The create response includes a warnings entry (x_url_post_credits) with the cost and current balance — relay it to the user. Credits are only deducted after the post successfully publishes; a failed publish is never charged. If the balance can't cover it at publish time, only the X target fails (its error explains the shortfall) and the post can be retried later. Posts without links stay free — never remove a user's link to dodge the fee without asking them. Scheduling is also gated up front: every scheduled X link post reserves its cost, and a create/schedule that would push the reserved total past the balance is refused with a 402 x_credits_insufficient error (details carry credits_required / credits_balance / credits_reserved) — tell the user their X credit balance is too low for this post, don't silently retry.

VIDEO DURATION CAPS — MUST RESPECT THESE (returns 400 validation_error when exceeded):

Platform

Post mode

Reel mode

Facebook

240 min

240 min (the old 90 s Reel cap is gone)

YouTube Short

(no Post mode)

3 min

X

140 s

N/A

Bluesky

180 s

N/A

Threads

5 min

N/A

TikTok

10 min

10 min

LinkedIn / LinkedIn Page

10 min

N/A

Instagram

15 min

15 min

Pinterest

15 min

N/A

Reddit

15 min

N/A

Mastodon

(instance-dependent)

N/A

VIDEO FILE-SIZE CAPS — MUST RESPECT THESE (validated via ffprobe at schedule/publish time; drafts exempt):

Platform

Video cap

Mastodon

99 MB

Bluesky

100 MB

Instagram

300 MB

X (free tier)

512 MB

Threads / Reddit

1 GB

Pinterest

2 GB

Facebook / TikTok

4 GB

LinkedIn / LinkedIn Page

5 GB

YouTube

256 GB

Upload requests are capped at 100 MB on top of these; anything bigger gets rejected with code: file_too_large before the validator runs.

Cap-violation error shape (one sentence per offending platform):

{ "error": { "code": "validation_error", "message": "YouTube only allows videos up to 3min; yours is 3min 12s. Trim the video or deselect YouTube." } }

Before sending an oversized video, warn the user and offer to trim, deselect that platform, or split. Drafts can still be created without media — the validator only runs when transitioning to scheduled or publish_now.

CHARACTER LIMITS — MUST RESPECT THESE:

Platform

Max chars

Notes

X (free / Basic)

280

Long posts require Premium or Premium+ — Basic does NOT count

X (Premium / Premium+)

25,000

Check platform_details.subscription_type on the account

Bluesky

300

Counted in graphemes

Mastodon

500

Threads

500

YouTube

500

Description field

Pinterest

500

Pin description

Instagram

2,200

Caption

TikTok

2,200 (videos) / 4,000 (photo posts)

Videos have a single caption field

LinkedIn

3,000

Facebook

63,206

Very generous

When posting to multiple platforms with different limits, ALWAYS use per-platform captions. For example, if posting to LinkedIn (3000 chars) and X (280 chars), use: { "default": "full version", "x": "shortened version" }. Never post content that exceeds a platform's limit.

Channel IDs you can pass: instagram, facebook, threads, linkedin (personal profile), linkedin_page (company page), youtube, tiktok, pinterest, x, bluesky, mastodon. linkedin and linkedin_page are independent. A workspace can have both connected and post to each separately. Always confirm with list_accounts which are actually connected.

Do NOT call this tool without media when creating stories, reels, Instagram posts, TikTok posts, or Pinterest posts — it will fail.

IMPORTANT - When the user shares an image or screenshot in chat: You MUST upload it before creating the post. Do NOT skip the image. Do NOT create a text-only draft when an image was provided. Follow these steps:

  1. Call upload_media with method="upload_url" to get upload instructions

  2. Use code execution to upload the image file to OmniSocials

  3. Use the returned media ID in media_ids when creating the post Only if code execution is completely unavailable, save as a draft and tell the user to add the image at app.omnisocials.com.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
xNoX (Twitter) options, including thread mode via `thread_parts`.
typeNoContent type. 'story' takes 1 to 10 media items; each is one slide, published in order.
tiktokNoTikTok options
blueskyNoBluesky options, including thread mode via `thread_parts`.
contentYesPost caption. String for same text on all channels, or object with platform keys for per-channel captions: { "default": "fallback", "linkedin": "long version", "threads": "short version" }. The "default" key is used for any selected channel without its own key. Always prefer one call per topic, even when captions differ across platforms.
threadsNoThreads options: thread mode via `thread_parts`, location tag via `location_id`.
youtubeNoYouTube Shorts options. Only applies when type is 'reel' and youtube is among the selected channels. A custom Shorts thumbnail is set with the top-level `video_cover` (a `youtube` override for a YouTube-only image); it shows on Shorts only on channels where YouTube has enabled custom Shorts thumbnails (Partner Program channels first, since July 2026), other channels show a frame from the video.
channelsNoArray of channel IDs to post to (e.g. linkedin, linkedin_page, instagram). Get available IDs from list_accounts.
facebookNoFacebook options
link_urlNoURL to share as a rich preview card on platforms that support link-share posts (LinkedIn and Facebook). Renders as a tile with thumbnail/title/description instead of plain text. Ignored on platforms that don't support link shares, and ignored on posts that already have media attached (media wins).
linkedinNoLinkedIn Profile options
mastodonNoMastodon options, including thread mode via `thread_parts`.
instagramNoInstagram options
media_idsNoMedia IDs — flat array or per-platform object
pinterestNo
user_tagsNoInstagram only. Tag public accounts at x/y positions on a PHOTO (not video/reels/stories). For a single image omit image_index; for a carousel, set image_index to the slide each tag belongs to. Private/non-existent usernames are rejected at publish time. Ignored by other platforms.
link_titleNoOptional title for the link-share preview. LinkedIn uses this when set; Facebook ignores it and fetches OG metadata server-side. Omit to let LinkedIn auto-fetch the page title.
media_urlsNoExternal image/video/PDF URLs — flat array or per-platform object. Max 10 total (Pinterest: max 5 images per carousel pin), each file ≤ 100 MB. Entries are URL strings or { url, alt } objects (alt = accessibility description, delivered to Mastodon/Bluesky/X/Pinterest/Instagram (images)/LinkedIn (images)). For larger files (up to 1 GB): upload_media with method 'url' first, then pass the returned media id in `media`.
hashtag_setNoName of a saved hashtag set (from list_hashtag_sets, matched case-insensitively) to apply to this post. The set's tags are merged in once at create time; tags already present in a caption are skipped. When the user says something like 'add my usual hashtags', check list_hashtag_sets first. Instagram's 30-hashtag cap is enforced with a clear error (hashtag_limit_exceeded).
location_idNoInstagram only. Facebook Place ID for a single physical venue (with a street address) to tag the post's location. Find it via the location search in the OmniSocials dashboard. Ignored by other platforms.
video_coverNoVideo thumbnail for a post whose media is ONE video. Applied on Instagram (feed videos and reels), Facebook (feed videos and reels), LinkedIn Profile and Page, TikTok, Pinterest and YouTube Shorts. YouTube Shorts: the cover shows on Shorts only on channels where YouTube has enabled custom Shorts thumbnails (rolling out since July 2026, Partner Program channels first); on other channels YouTube stores it as the default thumbnail but shows a frame from the video on Shorts. Say that it depends on the channel; do not promise it. TikTok only takes a frame: a 'custom' cover is skipped there, so add a tiktok override with type 'frame' when the user wants a specific TikTok frame. The per-platform reel fields (instagram.thumb_offset / cover_url, tiktok.video_cover_timestamp_ms, pinterest.video_cover) keep working and win over the base cover for their platform. get_post reads it back as `video_cover`.
scheduled_atNoISO 8601 date for scheduled publishing
collaboratorsNoInstagram only. Up to 3 public Instagram usernames to invite as co-authors (the 'Collab' feature). Works on image, carousel, and reel posts — NOT Stories. Invited users get an invite in the Instagram app; once they accept, the post also appears on their profile and feed. A leading '@' is stripped; usernames are case-insensitive. Private or non-existent usernames are rejected by Instagram at publish time. Ignored by other platforms.
linkedin_pageNoLinkedIn Company Page options
linkedin_pollNoNon-sponsored LinkedIn poll(s) — independent per channel, keyed by `linkedin` (personal profile) / `linkedin_page` (company page). A poll is mutually exclusive with media and a link share on that channel's post — a poll takes priority over both at publish time. Still requires `content.linkedin` (or `content.default`) as that channel's caption; the poll itself only carries the question/options/duration. On update_post, set a channel's key to `null` to clear that channel's poll and revert it to a normal post — send the full desired state for both channels, since the whole object replaces wholesale.
google_businessNoGoogle Business Profile options. Use to publish EVENT or OFFER posts, attach a CTA button, or both. Shape mirrors Google's LocalPost resource (see https://developers.google.com/my-business/reference/rest/v4/accounts.locations.localPosts#LocalPost). Google Business caption rules (enforced at scheduling — text that violates these will return a `validation_error` 400 before the post is saved): • Phone numbers in the caption are rejected — use a CALL button instead. • Inline URLs / bare domains / emails are rejected — use LEARN_MORE / BOOK / SHOP / SIGN_UP / ORDER buttons instead. • Caption max 1500 characters. • Media is optional (text-only posts are allowed). If attached: exactly one JPEG/PNG/WebP image (no video, no carousels). • The workspace must have a Google Business location selected (Settings → Organisation → Workspaces → Google Business) before scheduling — otherwise returns a 400.
link_descriptionNoOptional description for the link-share preview. LinkedIn uses this when set; Facebook auto-fetches the OG description.
hashtag_placementNoWhere the set's tags land. caption_append (default): appended to each target caption after a blank line. first_comment: posted as the auto first comment on Instagram/Facebook/LinkedIn/LinkedIn Page/YouTube/TikTok (TikTok only when the workspace enabled TikTok comments) (keeps hashtags out of the caption — appended after any explicit first_comment); platforms without a comment API fall back to caption_append. Stories always use captions.
hashtag_platformsNoOptional subset of the post's channels to apply the hashtag set to (e.g. ["instagram", "tiktok"]). Defaults to all selected channels.
link_thumbnail_urlNoOptional thumbnail image URL for the preview card. Currently applied on Facebook; reserved for LinkedIn.
approval_workflow_idNoRoute the post through a saved approval workflow (id from list_approval_workflows). The post is created as `in_approval` instead of `scheduled`: its approvers are notified, they review it on the Approvals page, and it publishes at schedule_at only once the workflow's last step approves it (or approve_post). Use this whenever the user wants to review/approve agent-created posts before they go out. Requires schedule_at; not allowed with publish_now (use create_post, never create_and_publish_post). A workflow with no approvers on its first step is rejected with validation_error.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • addedInput schema / properties / pinterest / properties / product_tags
      Added value: +{
      +  "description": "Products to tag on the Pin, so people can shop the items in the image. Up to 24 product Pins of the connected Pinterest account, each as a Pin ID string or a Pin link (https://www.pinterest.com/pin/<id>/). Get the IDs with list_pinterest_products. Only the account's own product Pins can be tagged (public, with a link on a website the account claimed on Pinterest); products of other merchants cannot. The tags are added right after the Pin is published; a product Pinterest refuses never fails the post, and get_post shows the outcome (product_tags_result). On update_post the pinterest object replaces the stored one, so leave product_tags out to remove the tags.",
      +  "items": {
      +    "type": "string"
      +  },
      +  "maxItems": 24,
      +  "type": "array"
      +}
  2. Changed5 schema fields changed
    • addedInput schema / properties / facebook / properties / cover_url
      Added value: +{
      +  "description": "Custom thumbnail image URL (JPEG/PNG, max 10 MB). Used with thumbnail_type 'from-library'.",
      +  "type": "string"
      +}
    • addedInput schema / properties / facebook / properties / thumb_offset
      Added value: +{
      +  "description": "Frame timestamp in MILLISECONDS from the start of the video (e.g. 3000 = 0:03). Used with thumbnail_type 'from-video'.",
      +  "type": "number"
      +}
    • addedInput schema / properties / facebook / properties / thumbnail_type
      Added value: +{
      +  "anyOf": [
      +    {
      +      "enum": [
      +        "from-video",
      +        "from-library"
      +      ],
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "description": "Video thumbnail for Facebook feed videos and reels: 'from-video' uses the frame at thumb_offset, 'from-library' uploads the image at cover_url. Applied after the video is live; a thumbnail failure never fails the post. On update_post, null removes the Facebook override."
      +}
    • addedInput schema / properties / video_cover
      Added value: +{
      +  "description": "Video thumbnail for a post whose media is ONE video. Applied on Instagram (feed videos and reels), Facebook (feed videos and reels), LinkedIn Profile and Page, TikTok, Pinterest and YouTube Shorts. YouTube Shorts: the cover shows on Shorts only on channels where YouTube has enabled custom Shorts thumbnails (rolling out since July 2026, Partner Program channels first); on other channels YouTube stores it as the default thumbnail but shows a frame from the video on Shorts. Say that it depends on the channel; do not promise it. TikTok only takes a frame: a 'custom' cover is skipped there, so add a tiktok override with type 'frame' when the user wants a specific TikTok frame. The per-platform reel fields (instagram.thumb_offset / cover_url, tiktok.video_cover_timestamp_ms, pinterest.video_cover) keep working and win over the base cover for their platform. get_post reads it back as `video_cover`.",
      +  "properties": {
      +    "cover_url": {
      +      "description": "Public image URL, JPEG or PNG (type 'custom').",
      +      "type": "string"
      +    },
      +    "overrides": {
      +      "additionalProperties": {
      +        "anyOf": [
      +          {
      +            "properties": {
      +              "cover_url": {
      +                "description": "Public image URL, JPEG or PNG (type 'custom').",
      +                "type": "string"
      +              },
      +              "thumb_offset": {
      +                "description": "Milliseconds into the video (type 'frame'). 3000 = 0:03.",
      +                "maximum": 9007199254740991,
      +                "minimum": 0,
      +                "type": "integer"
      +              },
      +              "type": {
      +                "description": "'frame' uses the video frame at thumb_offset; 'custom' uploads the image at cover_url.",
      +                "enum": [
      +                  "frame",
      +                  "custom"
      +                ],
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "type"
      +            ],
      +            "type": "object"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ]
      +      },
      +      "description": "Per-platform overrides keyed by platform id (instagram, facebook, linkedin, linkedin_page, tiktok, pinterest, youtube). An override wins over the base cover for that platform.",
      +      "propertyNames": {
      +        "type": "string"
      +      },
      +      "type": "object"
      +    },
      +    "thumb_offset": {
      +      "description": "Milliseconds into the video (type 'frame'). 3000 = 0:03.",
      +      "maximum": 9007199254740991,
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "type": {
      +      "description": "'frame' uses the video frame at thumb_offset; 'custom' uploads the image at cover_url.",
      +      "enum": [
      +        "frame",
      +        "custom"
      +      ],
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "type"
      +  ],
      +  "type": "object"
      +}
    • changedInput schema / properties / youtube / description
      Previous value: -"YouTube Shorts options. Only applies when type is 'reel' and youtube is among the selected channels."New value: +"YouTube Shorts options. Only applies when type is 'reel' and youtube is among the selected channels. A custom Shorts thumbnail is set with the top-level `video_cover` (a `youtube` override for a YouTube-only image); it shows on Shorts only on channels where YouTube has enabled custom Shorts thumbnails (Partner Program channels first, since July 2026), other channels show a frame from the video."
  3. First observed

TDQS

A4.7/5.0
Behavior5/5

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

Annotations are minimal (readOnlyHint=false, destructiveHint=false, openWorldHint=false), so the description carries the behavioral burden, and it does: it discloses the credit/fee model for X URL posts including the 402 x_credits_insufficient error, the reservation model for scheduled link posts, the 100 MB upload cap and per-platform file-size/ffprobe validation, the draft-exempt rule, the type/media validation failures, and the publish-time failure semantics. This is far more than the annotations provide.

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

Conciseness3/5

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

Front-loaded with a clear purpose line and a numbered checklist, which is good structure. But the body is very long — large tables that partially duplicate the schema (character limits, video caps), and the Pinterest default flow is repeated in narrative form. It earns most of its length, but the duplication and the 400+ word length keep it out of 4-5.

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

Completeness5/5

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

For a 31-param, deeply nested mutation tool with no output schema and sparse annotations, the description covers preflight steps, per-platform media requirements, validation error shapes, credit semantics, and scheduling/approval flows. Nothing critical an agent needs to call this correctly is missing.

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

Parameters4/5

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

Schema description coverage is 97%, so the schema does most of the work. The description still adds value the schema does not: channel ID list, platform-specific caption object shape with example keys, X thread vs long-form decision path, Pinterest board_id auto-default behavior, character limits table, and video duration/file-size caps. It could go further on some top-level params (link_url, hashtag_set, location_id) but for a 31-param tool this is strong.

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?

States a specific verb+resource ('Create a new social media post, story, or reel') and enumerates the three content types. The sibling set contains create_and_publish_post, so the description's careful 'save as draft / schedule / publish_now' framing plus the explicit approval_workflow guidance lets an agent distinguish it from the publish-immediately variant.

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

Usage Guidelines5/5

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

Explicit when-to-use and when-not-to for the major alternatives: it names list_workspaces, list_accounts, upload_media and get_account as required preflight steps, tells the agent to ASK the user for missing info, and gives platform-specific gate conditions (Pinterest board auto-default, X thread vs long-form). The only reason it isn't a 5 is that it doesn't explicitly say 'use create_and_publish_post instead when the user wants immediate publish,' but the approval_workflow paragraph implies the boundary.

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

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources