Skip to main content
Glama

Post to Instagram / Threads

antix_compose_social_post

Book a post on the user's own connected Instagram and/or Threads channels (one post per channel). Set confirm: true ONLY after the user explicitly said to post — without it the post waits for approval (antix_approve_post). Nothing is live when this returns: the publisher posts within about a minute of the post's time — confirm with antix_get_post and say it is live only once it reports published with a permalink. FREE. Each request is checked first (caption length, hashtags, carousel size, video length); Instagram photos outside 4:5…1.91:1 are cropped and the response says so. Media: historyIds of AIGE generations, photos and/or videos (1 image = photo post, 1 video = Reel / Threads video, 2 or more = carousel that can mix photos and up to 4 videos — Instagram takes up to 10 items, Threads up to 20, and the server caps a post at 10), or a carousel deckId; neither = a Threads text post (Instagram needs media). when: "now", "queue" (each channel's own next free posting time from the schedule saved on it — see queueSlots / nextQueueSlot in antix_list_channels; a channel with no posting times, or none left in the next 90 days, is refused as VALIDATION_ERROR), "draft", or an ISO-8601 time WITH a timezone. LIMIT_REACHED ("limit reached on @handle") is a different thing: that channel already holds all the waiting posts it is allowed. Instagram Stories: instagram: { format: "story" } with exactly ONE image or video (a video of 3–60 seconds) — the caption isn't posted. Instagram lets apps post Stories only for Business accounts (accountType in antix_list_channels), so on any other Instagram channel (or with instagram.reminder: true, for stickers and links) the Story is a reminder: AIGE notifies the user at its time to post it themselves and never posts it — its status ends at handoff_ready, never published, so promise no permalink; the booking reply says which channels got a reminder. First comment: instagram: { firstComment } (up to 2,200 characters; Instagram channels only — a request without one is refused; not with a Story) is posted under each Instagram post once it is live; the channel needs instagram_business_manage_comments in grantedScopes, otherwise the booking is refused and the user reconnects in the browser. Threads thread: the Threads text is threads.text when set, else the caption. A Threads text over 500 characters (Threads' count: an emoji counts as several) is split into a thread automatically (at paragraph, then sentence breaks; up to 10 posts — the response says so), unless threads: { chain: [{ text, historyId?, altText? }] } is given — up to 9 replies of up to 500 characters each, posted one under another once the post is live, each with at most one IMAGE (a historyId) and its alt text; with a chain the Threads text itself must fit in 500. A thread (written or split) needs threads_manage_replies in the channel's grantedScopes, otherwise the booking is refused and the user reconnects in the browser. Threads topic tag, who can reply, poll: threads: { topicTag, replyControl, poll } — topicTag is the post's one topic tag (1–50 characters, no periods or &; without it the first usable entry of hashtags is used and the response says so, since Threads has no hashtag list), replyControl is who can reply ("everyone", "accounts_you_follow", "mentioned_only", "followers_only" or "parent_post_author_only"; omit it for Threads' default), and poll: { options } is a poll of 2–4 different options of up to 25 characters on a text post only — no historyIds or deckId, the caption is the question. All three apply to the post itself (a thread's first post), never to its replies, and need a Threads channel in the request. Threads extras: threads: { extras: { linkAttachment, quotePostId, ghost, spoilerMedia, spoilerRanges, replyApprovals, countries } }, each optional and on the post itself only — linkAttachment is an https:// link shown as a preview card (text posts only; Threads allows 5 links per post, counting the caption's), quotePostId quotes a Threads post (for the user's own live Threads post use its providerPostId from antix_get_post), ghost:true makes a text-only post that disappears after 24 hours (no media, thread, poll, link preview, quote or reply approvals), spoilerMedia:true hides the photos or videos behind a spoiler, spoilerRanges hides up to 10 parts of the Threads text ({ offset, length } counted as JavaScript counts — an emoji is 2 — from the start of threads.text, else the caption; inside that text, and for a long text split into a thread inside the first post; not overlapping), replyApprovals:true makes the user approve replies in the Threads app (AIGE has no inbox for them yet), and country limits (countries) are set in the AIGE app for now — a booking that sets them here is refused, so tell the user to set them in the app. Alt text: altTexts — one per historyIds item, same order ("" for an item with none), up to 1,000 characters each; Instagram sends it on photos only (a single photo or a carousel photo — never a Reel or a Story, and the response says when it isn't sent), Threads on photos and videos; not with a deckId. Collaborators: instagram: { collaborators: ["anna", "ben"] } invites up to 3 Instagram accounts to co-author the post (a photo, Reel or carousel; not a Story, not the channel's own account) — only while antix_list_channels reports features.instagramCollaborators: true; otherwise the booking is refused. Tagging people: userTags — one list per historyIds item, same order ([] for an item with none), up to 20 per item, each { username, x, y }; on a photo x and y (0–1 from the top-left corner of the photo as posted) are required, a Reel or a Story takes the username alone; a carousel is cropped to the shape of its FIRST item (a photo or a video), and a carousel video takes no tags (they aren't sent for it, and the response warns). Instagram only — a request with tags and no Instagram channel is refused; not with a deckId; and only while antix_list_channels reports features.instagramUserTags: true — otherwise the booking is refused. Reel options: instagram: { reel: { coverHistoryId, thumbOffsetMs, shareToFeed, audioName, trial } } — only when historyIds is exactly ONE video (no Story, no deck, no photo or carousel; anything else is refused): coverHistoryId is an IMAGE of the user's to use as the cover (Instagram crops it to 9:16, and the response warns when it isn't close), thumbOffsetMs picks a moment of the video as the cover instead (ignored when there is a cover; must be inside the video), shareToFeed:false keeps the Reel out of the main feed (default true), audioName renames the Reel's original audio (up to 100 characters; Instagram allows ONE rename in total, so it can't be changed later), and trial ("MANUAL" or "SS_PERFORMANCE") posts it as a Trial Reel shown to non-followers first. A different text per platform: the top-level caption goes to every picked channel unless instagram: { caption } and/or threads: { text } give that platform its own (a blank one means the caption; instagram: { caption } is refused without an Instagram channel) — e.g. a long Instagram caption beside a short Threads post; the Threads text is the one that is split into a thread when it is over 500, and spoilerRanges count from its start.

Input Schema

NameRequiredDescriptionDefault
whenYes"now", "queue" (each channel's next free posting time from the schedule the user saved on it — antix_list_channels shows `queueSlots` and `nextQueueSlot`; a channel without posting times, or with none left in the next 90 days, is refused as a VALIDATION_ERROR — not LIMIT_REACHED, which is the cap on waiting posts), "draft" (book it for approval later), or an ISO-8601 date-time WITH a timezone, e.g. "2026-10-16T09:00:00+03:00".
deckIdNoA carousel deck to post instead of historyIds. Never both.
captionYesThe post text, shared by every picked channel unless instagram.caption or threads.text gives that platform its own. Instagram: the caption (hashtags are appended). Threads: 500 characters per post (an emoji counts as several) — a longer text is split into a thread automatically (at paragraph, then sentence breaks; up to 10 posts) unless threads.chain is given, which needs the Threads text (threads.text when set, else this caption) to be at most 500.
confirmNotrue only after the user explicitly said to post. Without it the post waits for approval (antix_approve_post) — except a timed post on a channel the user put on autopilot, which posts on its own at its time. Posting "now" always needs confirm:true.
threadsNoThreads-only options: the Threads post's own text, a thread of several posts, a topic tag, who can reply, a poll and extras (link preview, quote, ghost post, spoilers, reply approvals). A Threads text over 500 characters is split into a thread automatically unless chain is given. A request with no Threads channel can't carry them. Instagram channels in the same request ignore them.
altTextsNoAlt text (accessibility descriptions), one per historyIds item, same order — use "" for an item with none. Up to 1,000 characters each; never more texts than items, and not with deckId. Instagram uses it on photos (a single photo or a carousel photo) and not on Reels or Stories — the response says so; Threads uses it on photos and videos.
hashtagsNoHashtags, with or without #. Instagram appends them to the caption. Threads has no hashtag list: the first one that can be a topic tag becomes the post's topic tag (unless threads.topicTag is given) and the rest are left off — the response says so.
userTagsNoPeople to tag on the Instagram post — one list per historyIds item, same order ([] for an item with none), up to 20 per item; not with deckId. Each tag is { username (with or without @), x, y }: on a PHOTO (a single photo or a carousel photo) x and y are required — send both, 0–1 from the top-left corner of the photo AS POSTED (x across, y down; 0.5/0.5 is the middle) — a feed photo outside 4:5 … 1.91:1 is cropped from the middle first, and every photo of a carousel takes the shape of the FIRST item (a photo or a video); a Reel or a Story takes the username alone (x and y are ignored), and a video in a carousel takes no tags — they aren't sent for it, and the response warns. Instagram only: a request with tags and no Instagram channel is refused (a Threads channel in the same request just doesn't get them). Only while antix_list_channels reports features.instagramUserTags: true — until then Instagram doesn't take photo tags from AIGE and the booking is refused, so don't offer it.
instagramNoInstagram-only options. Threads channels in the same request ignore them.
channelIdsYesChannel ids from antix_list_channels — one post is booked per channel.
historyIdsNoAIGE generations to post (ids from antix_get_history), photos and/or videos: 1 image = photo post, 1 video = Reel / Threads video, 2 or more = carousel (photos and videos can be mixed, up to 4 videos; Instagram takes up to 10 items, Threads up to 20 — the server caps a post at 10). Omit for a Threads text post.

Schema Changelog

Changes observed during successful MCP inspections.

  1. First observed

TDQS

A4.2/5.0
Behavior3/5

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

Annotations cover the safety profile (readOnly=false, destructive=false, openWorld=true), and the description adds valuable context: nothing is live on return, the publisher posts within about a minute, and status only reaches published with a permalink. However, it is a mutation tool with no explicit statement of reversibility beyond pointing at antix_cancel_post and antix_approve_post.

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?

The critical facts (confirm semantics, nothing live yet, FREE) are front-loaded, which is good, but the remainder is a single ~1,500-word paragraph mixing media rules, Stories, threads, extras, alt text, tags, Reels and per-platform captions. Backticked field names help, but an agent must rescan the block to find any one rule.

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 an 11-parameter tool with deep nesting, cross-channel conditional refusals and no output schema, the description is remarkably complete: it names every refusal condition, which fields are Instagram- vs Threads-only, and what the response will report back.

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

Parameters5/5

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

Schema coverage is already 100%, but the description adds substantial meaning the schema can't: which media combinations produce a photo/Reel/carousel/text post, why Instagram Stories degrade to reminders on non-Business accounts, that spoilerRanges count in JavaScript string units, and the one-shot audio rename rule.

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?

States a specific verb and resource: 'Book a post on the user's own connected Instagram and/or Threads channels', and immediately frames the approval flow via antix_approve_post. It does not, however, distinguish itself from the sibling antix_create_post, which is the most likely source of selection ambiguity.

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?

Explicitly says when to set confirm:true (only after the user said to post) and what happens without it, routes to antix_approve_post and antix_get_post for verification, and explains each `when` mode's preconditions including the queue refusal case. Alternatives and exclusions are named rather than implied.

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