Skip to main content
Glama

threads_publish_carousel

Publish a carousel post on Threads with 2-20 images or videos, including captions and reply controls.

Instructions

Publish a carousel post on Threads with 2-20 images/videos.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
itemsYesArray of media items
textNoCaption text
reply_controlNoWho can reply
topic_tagNoTopic tag for the post
quote_post_idNoID of a post to quote

Implementation Reference

  • The handler for `threads_publish_carousel` which creates individual media containers and then publishes them as a carousel.
    // ─── threads_publish_carousel ────────────────────────────────
    server.tool(
      "threads_publish_carousel",
      "Publish a carousel post on Threads with 2-20 images/videos.",
      {
        items: z.array(z.object({
          type: z.enum(["IMAGE", "VIDEO"]).describe("Media type"),
          url: z.string().url().describe("Public HTTPS URL"),
          alt_text: z.string().max(1000).optional().describe("Alt text for this item"),
        })).min(2).max(20).describe("Array of media items"),
        text: z.string().max(500).optional().describe("Caption text"),
        reply_control: z.enum(["everyone", "accounts_you_follow", "mentioned_only", "parent_post_author_only", "followers_only"]).optional().describe("Who can reply"),
        topic_tag: z.string().max(50).optional().describe("Topic tag for the post"),
        quote_post_id: z.string().optional().describe("ID of a post to quote"),
      },
      async ({ items, text, reply_control, topic_tag, quote_post_id }) => {
        try {
          const childIds: string[] = [];
          for (const item of items) {
            const params: Record<string, unknown> = { media_type: item.type, is_carousel_item: true };
            if (item.type === "IMAGE") {
              params.image_url = item.url;
            } else {
              params.video_url = item.url;
            }
            if (item.alt_text) params.alt_text = item.alt_text;
            const { data: child } = await client.threads("POST", `/${client.threadsUserId}/threads`, params);
            const childId = (child as { id: string }).id;
            if (item.type === "VIDEO") {
              await waitForThreadsContainer(client, childId);
            }
            childIds.push(childId);
          }
          const carouselParams: Record<string, unknown> = {
            media_type: "CAROUSEL",
            children: childIds.join(","),
          };
          if (text) carouselParams.text = text;
          if (reply_control) carouselParams.reply_control = reply_control;
          if (topic_tag) carouselParams.topic_tag = topic_tag;
          if (quote_post_id) carouselParams.quote_post_id = quote_post_id;
          const { data: carousel } = await client.threads("POST", `/${client.threadsUserId}/threads`, carouselParams);
          const carouselId = (carousel as { id: string }).id;
          const { data, rateLimit } = await client.threads("POST", `/${client.threadsUserId}/threads_publish`, {
            creation_id: carouselId,
          });
          return { content: [{ type: "text", text: JSON.stringify({ ...data as object, _rateLimit: rateLimit }, null, 2) }] };
        } catch (error) {
          return { content: [{ type: "text", text: `Publish carousel failed: ${error instanceof Error ? error.message : String(error)}` }], isError: true };
        }
      }
    );

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/mikusnuz/meta-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server