PostWire
Writes a native post per network from one idea and publishes it: TikTok, Instagram, YouTube & more
Should I use this
Quality & Safety
Based on automated analysis of tool definitions and protocol compliance.
Context Cost
This is the approximate number of tokens consumed each time the server's tools are loaded into a model's context. Higher counts reduce the attention available for other tasks.
Install
One-Click Install
Add this to your `claude_desktop_config.json` file:
{
"mcpServers": {
"postwire-mcp": {
"command": "npx",
"args": [
"postwire-mcp"
]
}
}
}Runnable packages
0.3.5stdioRemote endpoints
https://postwire.io/api/mcpstreamable-httpWhat it can do
Tool inventory
Tools (15)
π’list_platforms
Lists the social platforms PostWire can publish to and, for each, whether it connects with OAuth or with credentials. Does not need a PostWire account.
Input Schema
{
"type": "object",
"properties": {},
"additionalProperties": false
}π’my_account
Shows the signed-in PostWire account: plan, usage against each plan limit (posts this month, brands, AI drafts today), brands, and which social accounts are connected, each with its brand and the handle, display name and picture the network reports for it. When a limit is at least 80 % used, the result includes the plan that raises it, its monthly price and a checkout link. When no social account is connected, it includes a one-hour link to connect one.
Input Schema
{
"type": "object",
"properties": {},
"additionalProperties": false
}π’generate_posts(prompt, platforms, media_url, brand_voice)
Writes one draft per platform from a single idea, adapted to each network's rules (character limit, hashtags, title and tags for YouTube, hook-first caption for TikTok and Reels, link placement for LinkedIn and X). Nothing is published. Returns { drafts: { <platform>: { text, title?, tags? } } } and, if the writer skipped a platform, { missing: [...] }. Counts toward the account's daily AI limit.
Input Schema
{
"type": "object",
"properties": {
"prompt": {
"type": "string",
"minLength": 1,
"maxLength": 4000,
"description": "The idea or message to communicate. More detail gives better drafts."
},
"platforms": {
"type": "array",
"items": {
"type": "string",
"enum": [
"telegram",
"bluesky",
"mastodon",
"discord",
"tiktok",
"youtube",
"reddit",
"linkedin",
"facebook",
"instagram",
"x"
]
},
"minItems": 1,
"description": "Platforms to write for, e.g. [\"linkedin\",\"x\",\"bluesky\"]."
},
"media_url": {
"type": "string",
"format": "uri",
"description": "Optional public https URL of the photo or video the post is about."
},
"brand_voice": {
"type": "string",
"maxLength": 1500,
"description": "Optional tone or style notes, e.g. \"friendly, no emojis, first person plural\"."
}
},
"required": [
"prompt",
"platforms"
],
"additionalProperties": false
}π΄post_to_social(platforms, text, per_platform, title, video_url, ...)
Publishes a post immediately and publicly to the listed platforms through the social accounts connected to the user's PostWire account. A published post cannot be withdrawn from PostWire. Accepts one text for all platforms or a separate per_platform draft for each. YouTube requires video_url; TikTok requires video_url or photos (photo_url or media); Instagram requires a photo or video, and two or more media items make a carousel. Every platform must already be connected; otherwise nothing is published and the error names the missing ones. The same payload sent twice within 2 minutes is refused as a duplicate unless idempotency_key differs. When a platform is connected in more than one brand and brand_id is omitted, nothing is published and the error lists the brands. Returns { posted, published_to, results: [{ platform, ok, id?, url?, account?, error? }] }, where account and published_to name the handle and brand each post went to; when the monthly post limit stops a platform, the result also names the plan that raises it, its price and a checkout link.
Input Schema
{
"type": "object",
"properties": {
"platforms": {
"type": "array",
"items": {
"type": "string",
"enum": [
"telegram",
"bluesky",
"mastodon",
"discord",
"tiktok",
"youtube",
"reddit",
"linkedin",
"facebook",
"instagram",
"x"
]
},
"minItems": 1,
"description": "Platforms to publish to, all in one call, e.g. [\"linkedin\",\"bluesky\"]."
},
"text": {
"type": "string",
"description": "Post text used for every platform that has no per_platform draft."
},
"per_platform": {
"type": "object",
"description": "Per-platform drafts: { \"<platform>\": { \"text\": \"β¦\", \"title\": \"β¦\", \"tags\": [\"β¦\"] } }.",
"additionalProperties": {
"type": "object",
"properties": {
"text": {
"type": "string"
},
"title": {
"type": "string"
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
},
"title": {
"type": "string",
"description": "Title, used by YouTube."
},
"video_url": {
"type": "string",
"format": "uri",
"description": "Public https URL of a video. Required for YouTube; TikTok takes a video or photos."
},
"photo_url": {
"type": "string",
"format": "uri",
"description": "Public https URL of an image."
},
"media": {
"type": "array",
"minItems": 1,
"maxItems": 35,
"description": "Several images (or images and videos) in one post, in order: an Instagram carousel (up to 10), TikTok photo post (up to 35 JPEG/WebP images), Bluesky (up to 4 images), Mastodon (up to 4), LinkedIn (up to 20 images, or one PDF document). Networks that take one item get the first. Each item: { url, type: image|video|document, alt? }.",
"items": {
"type": "object",
"properties": {
"url": {
"type": "string",
"format": "uri",
"description": "Public https URL of the file."
},
"type": {
"type": "string",
"enum": [
"image",
"video",
"document"
],
"description": "Default image."
},
"alt": {
"type": "string",
"maxLength": 1500,
"description": "Alt text (used by Bluesky, Mastodon and LinkedIn)."
},
"title": {
"type": "string",
"maxLength": 200,
"description": "Document title, used by LinkedIn."
}
},
"required": [
"url"
],
"additionalProperties": false
}
},
"privacy": {
"type": "string",
"enum": [
"public",
"unlisted",
"private"
],
"description": "YouTube visibility. Default: the platform's default."
},
"brand_id": {
"type": "string",
"description": "Which brand's accounts to use. Omit to use the default brand."
},
"idempotency_key": {
"type": "string",
"maxLength": 200,
"description": "Optional unique key; a repeat with the same key within 24 h is refused instead of posted twice."
}
},
"required": [
"platforms"
],
"additionalProperties": false
}π΄schedule_post(run_at, platforms, text, per_platform, title, ...)
Queues a post to be published publicly at a future time (run_at, ISO 8601 with timezone, up to 365 days ahead) through the connected accounts. Takes the same content fields as publishing now. Every platform must already be connected and media must suit each platform, or it is refused now instead of failing later. When a platform is connected in more than one brand and brand_id is omitted, nothing is queued and the error lists the brands. Returns the queued item with its id and, for each platform, the handle and brand it will publish to. A queued post can be canceled before it runs.
Input Schema
{
"type": "object",
"properties": {
"run_at": {
"type": "string",
"format": "date-time",
"description": "When to publish, ISO 8601 with offset, e.g. \"2026-10-01T09:00:00-05:00\"."
},
"platforms": {
"type": "array",
"items": {
"type": "string",
"enum": [
"telegram",
"bluesky",
"mastodon",
"discord",
"tiktok",
"youtube",
"reddit",
"linkedin",
"facebook",
"instagram",
"x"
]
},
"minItems": 1,
"description": "Platforms to publish to."
},
"text": {
"type": "string",
"description": "Post text for platforms without a per_platform draft."
},
"per_platform": {
"type": "object",
"description": "Per-platform drafts: { \"<platform>\": { \"text\": \"β¦\" } }.",
"additionalProperties": {
"type": "object"
}
},
"title": {
"type": "string",
"description": "Title, used by YouTube."
},
"video_url": {
"type": "string",
"format": "uri",
"description": "Public https URL of a video (YouTube needs one; TikTok takes a video or photos)."
},
"photo_url": {
"type": "string",
"format": "uri",
"description": "Public https URL of an image."
},
"media": {
"type": "array",
"minItems": 1,
"maxItems": 35,
"description": "Several images (or images and videos) in one post, in order: an Instagram carousel (up to 10), TikTok photo post (up to 35 JPEG/WebP images), Bluesky (up to 4 images), Mastodon (up to 4), LinkedIn (up to 20 images, or one PDF document). Networks that take one item get the first. Each item: { url, type: image|video|document, alt? }.",
"items": {
"type": "object",
"properties": {
"url": {
"type": "string",
"format": "uri",
"description": "Public https URL of the file."
},
"type": {
"type": "string",
"enum": [
"image",
"video",
"document"
],
"description": "Default image."
},
"alt": {
"type": "string",
"maxLength": 1500,
"description": "Alt text (used by Bluesky, Mastodon and LinkedIn)."
},
"title": {
"type": "string",
"maxLength": 200,
"description": "Document title, used by LinkedIn."
}
},
"required": [
"url"
],
"additionalProperties": false
}
},
"brand_id": {
"type": "string",
"description": "Brand whose accounts to use; omit for the default brand."
},
"label": {
"type": "string",
"maxLength": 120,
"description": "Optional short label shown in the PostWire queue."
}
},
"required": [
"run_at",
"platforms"
],
"additionalProperties": false
}π’list_scheduled_posts(from, to)
Lists the account's scheduled posts (queued, publishing, done, failed or canceled) with their id, time, platforms and status. Optional from/to limit the time range.
Input Schema
{
"type": "object",
"properties": {
"from": {
"type": "string",
"format": "date-time",
"description": "Only posts scheduled at or after this time."
},
"to": {
"type": "string",
"format": "date-time",
"description": "Only posts scheduled before this time."
}
},
"additionalProperties": false
}π΄cancel_scheduled_post(id)
Cancels a queued or held post so it is never published. Only works before it starts publishing. Takes the id of the scheduled post.
Input Schema
{
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Scheduled post id."
}
},
"required": [
"id"
],
"additionalProperties": false
}π’get_post_status(platform, id, brand_id)
Returns the status and link of a published post, by platform and the post id returned when it was published. For TikTok and YouTube it asks the platform for the processing status and returns the public link once there is one. For networks that publish immediately it returns status "published" and, where the id allows it, the post's link (Telegram channels, including private ones as t.me/c/<channel>/<message>; Bluesky; LinkedIn; Facebook).
Input Schema
{
"type": "object",
"properties": {
"platform": {
"type": "string",
"enum": [
"telegram",
"bluesky",
"mastodon",
"discord",
"tiktok",
"youtube",
"reddit",
"linkedin",
"facebook",
"instagram",
"x"
],
"description": "Platform of the post, e.g. \"tiktok\"."
},
"id": {
"type": "string",
"description": "The post id returned when it was published on that platform."
},
"brand_id": {
"type": "string",
"description": "Brand whose account published it; omit for the default brand."
}
},
"required": [
"platform",
"id"
],
"additionalProperties": false
}π‘create_connect_link(platform, brand_id)
Creates a one-hour link the user opens in a browser to connect a social account (TikTok, YouTube, LinkedIn, Blueskyβ¦) to their PostWire account. Nothing is connected until the user completes it on the page. With brand_id the account is connected to that brand. Returns the url of that page.
Input Schema
{
"type": "object",
"properties": {
"platform": {
"type": "string",
"enum": [
"telegram",
"bluesky",
"mastodon",
"discord",
"tiktok",
"youtube",
"reddit",
"linkedin",
"facebook",
"instagram",
"x"
],
"description": "Platform to connect. Omit to let the user choose on the page."
},
"brand_id": {
"type": "string",
"description": "Brand to connect it to. Omit for the default brand."
}
},
"additionalProperties": false
}π΄plan_week(topic, platforms, days, hour, timezone, ...)
Writes one post per day for 1 to 7 days from a single topic, each day from a different angle and each platform in its own native format, and queues them to be published publicly at the given hour on each day starting tomorrow, through the connected accounts. Text only: platforms that require a video or photo (TikTok, YouTube, Instagram) are refused. Every platform must already be connected. Each day counts as one AI draft toward the daily AI limit. Days that do not fit in the plan's monthly post limit are saved as held (never published on the current plan) and are scheduled automatically when the plan is upgraded; the result then also gives that plan, its price and a checkout link. Returns the queued and held items with their id, time and a preview of each platform's text; any of them can be canceled before it runs.
Input Schema
{
"type": "object",
"properties": {
"topic": {
"type": "string",
"minLength": 1,
"maxLength": 2000,
"description": "What the week is about, e.g. \"our new autumn menu and the farmers behind it\"."
},
"platforms": {
"type": "array",
"items": {
"type": "string",
"enum": [
"telegram",
"bluesky",
"mastodon",
"discord",
"tiktok",
"youtube",
"reddit",
"linkedin",
"facebook",
"instagram",
"x"
]
},
"minItems": 1,
"description": "Text-capable platforms to post to each day, e.g. [\"linkedin\",\"bluesky\"]."
},
"days": {
"type": "integer",
"minimum": 1,
"maximum": 7,
"description": "How many days, starting tomorrow. Default 5."
},
"hour": {
"type": "integer",
"minimum": 0,
"maximum": 23,
"description": "Hour of the day to publish, on the timezone's clock. Default 10."
},
"timezone": {
"type": "string",
"maxLength": 60,
"description": "IANA timezone of that hour, e.g. \"America/Lima\". Default UTC."
},
"brand_voice": {
"type": "string",
"maxLength": 1500,
"description": "Optional tone or style notes."
},
"brand_id": {
"type": "string",
"description": "Brand whose accounts to use; omit for the default brand."
}
},
"required": [
"topic",
"platforms"
],
"additionalProperties": false
}π’list_brands
Lists the account's brands (one business each) with the social accounts connected to each: platform, the handle, display name, picture and profile link the network reports, when it was connected, and whether posts to it need only text, a video, or a photo or video. Also returns the plan's brand limit.
Input Schema
{
"type": "object",
"properties": {},
"additionalProperties": false
}π‘create_brand(name)
Creates a new, empty brand (a separate business with its own connected social accounts) on the PostWire account and returns its id. The plan limits the number of brands; at the limit nothing is created and the response names the plan that includes more brands, its monthly price and a checkout link.
Input Schema
{
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 80,
"description": "Brand name, e.g. the client's business name."
}
},
"required": [
"name"
],
"additionalProperties": false
}π‘create_upload_link
Creates a single-use link, valid for 24 hours, to a PostWire page where the user picks one photo or video from any device (JPG, PNG, WebP, GIF, MP4, MOV or WebM, up to 50 MB). The file is kept in the account's PostWire media storage for 30 days. Returns the page url and an upload_id for checking the upload's status.
Input Schema
{
"type": "object",
"properties": {},
"additionalProperties": false
}π’get_uploaded_file(upload_id)
Returns the status of a file uploaded through a PostWire upload link, by upload_id: "waiting" until the file has arrived, then "done" with its media_url (an https URL valid for 24 hours that works as video_url or photo_url), kind (photo or video), size and content type.
Input Schema
{
"type": "object",
"properties": {
"upload_id": {
"type": "string",
"minLength": 8,
"maxLength": 40,
"description": "The upload_id returned with the upload link."
}
},
"required": [
"upload_id"
],
"additionalProperties": false
}π’get_upgrade_link(plan)
Returns PostWire's paid plans with their monthly price and what each includes (posts a month, brands, AI drafts a day), the account's current plan, and a checkout link for one plan (the next plan up when none is given). The link opens a Stripe payment page in the browser and nothing is charged unless the user pays there; for an account that already has a subscription it opens the plan page of the PostWire dashboard.
Input Schema
{
"type": "object",
"properties": {
"plan": {
"type": "string",
"enum": [
"starter",
"pro",
"agency",
"scale"
],
"description": "Plan to check out. Omit for the next plan up."
}
},
"additionalProperties": false
}Community
Evidence