
Social media scheduler for AI agents: draft posts into a human-approved queue for 15 networks.
Call this server's tools from your browser. Nothing to install.
Bearer token using a posthell API key, e.g. 'Bearer ph_...'. Create one in the posthell dashboard's Agents tab (https://www.posthell.com/dashboard).
Requests go through mcptry because browsers can't call most MCP servers directly. Header values are sent to the server for that request only and are never stored or logged.
Tool list from our last check. Connect live to refresh it.
Save a post as a DRAFT in the user's posthell queue, with any photos or videos and per-network settings (Instagram Reel cover, YouTube title/tags). Nothing is published by this tool: the user approves it in the dashboard. Optionally propose a publish time. Warnings in the result are what would stop it publishing; fix them by calling again.
The caption. Optional when the post is a photo or video. For YouTube it becomes the description unless overrides.youtube is set.
Post to every connected account in this group, by name (e.g. "Bakery"). list_accounts shows the groups. Combine with platforms to send to only some of the group's networks.
Photos or videos, in order. One video = an Instagram Reel / a YouTube video.
Post to these accounts, by handle (e.g. "posthell_bakery") or id from list_accounts. Default: every connected account (narrowed by platforms).
A caption of its own for a network, used instead of body there. For YouTube this is the video description.
Only these networks.
Suggested publish time, ISO 8601. Only a suggestion - pre-fills the user's scheduler.
Settings for each network, keyed by network. Only the networks the post goes to are used.
This tool isn't marked read-only, so it may change something on the server or in an account you connected.
Tool list last changed Oct 23, 2026.
Save a post as a DRAFT in the user's posthell queue, with any photos or videos and per-network settings (Instagram Reel cover, YouTube title/tags). Nothing is published by this tool: the user approves it in the dashboard. Optionally propose a publish time. Warnings in the result are what would stop it publishing; fix them by calling again.
| Argument | Type | Description |
|---|---|---|
| body | string | The caption. Optional when the post is a photo or video. For YouTube it becomes the description unless overrides.youtube is set. |
| group | string | Post to every connected account in this group, by name (e.g. "Bakery"). list_accounts shows the groups. Combine with platforms to send to only some of the group's networks. |
| media | array | Photos or videos, in order. One video = an Instagram Reel / a YouTube video. |
| accounts | array | Post to these accounts, by handle (e.g. "posthell_bakery") or id from list_accounts. Default: every connected account (narrowed by platforms). |
| overrides | object | A caption of its own for a network, used instead of body there. For YouTube this is the video description. |
| platforms | array | Only these networks. |
| proposedTime | string | Suggested publish time, ISO 8601. Only a suggestion - pre-fills the user's scheduler. |
| platformOptions | object | Settings for each network, keyed by network. Only the networks the post goes to are used. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"body": {
"type": "string",
"maxLength": 5000,
"description": "The caption. Optional when the post is a photo or video. For YouTube it becomes the description unless overrides.youtube is set."
},
"group": {
"type": "string",
"maxLength": 60,
"description": "Post to every connected account in this group, by name (e.g. \"Bakery\"). list_accounts shows the groups. Combine with platforms to send to only some of the group's networks."
},
"media": {
"type": "array",
"items": {
"anyOf": [
{
"type": "string",
"maxLength": 2048
},
{
"type": "object",
"required": [
"url"
],
"properties": {
"alt": {
"type": "string",
"maxLength": 500,
"description": "Alt text describing it, for networks that show it"
},
"url": {
"type": "string",
"maxLength": 2048,
"description": "https URL: a mediaUrl from get_upload_url, or a public file"
},
"type": {
"enum": [
"image",
"video"
],
"type": "string",
"description": "Read from the file extension when omitted"
}
}
}
]
},
"maxItems": 10,
"description": "Photos or videos, in order. One video = an Instagram Reel / a YouTube video."
},
"accounts": {
"type": "array",
"items": {
"type": "string",
"maxLength": 120
},
"maxItems": 20,
"description": "Post to these accounts, by handle (e.g. \"posthell_bakery\") or id from list_accounts. Default: every connected account (narrowed by platforms)."
},
"overrides": {
"type": "object",
"properties": {
"x": {
"type": "string",
"maxLength": 5000
},
"reddit": {
"type": "string",
"maxLength": 5000
},
"tiktok": {
"type": "string",
"maxLength": 5000
},
"bluesky": {
"type": "string",
"maxLength": 5000
},
"discord": {
"type": "string",
"maxLength": 5000
},
"threads": {
"type": "string",
"maxLength": 5000
},
"youtube": {
"type": "string",
"maxLength": 5000
},
"facebook": {
"type": "string",
"maxLength": 5000
},
"linkedin": {
"type": "string",
"maxLength": 5000
},
"telegram": {
"type": "string",
"maxLength": 5000
},
"whatsapp": {
"type": "string",
"maxLength": 5000
},
"instagram": {
"type": "string",
"maxLength": 5000
},
"pinterest": {
"type": "string",
"maxLength": 5000
},
"googlebusiness": {
"type": "string",
"maxLength": 5000
}
},
"description": "A caption of its own for a network, used instead of body there. For YouTube this is the video description."
},
"platforms": {
"type": "array",
"items": {
"enum": [
"x",
"linkedin",
"instagram",
"threads",
"bluesky",
"facebook",
"tiktok",
"youtube",
"pinterest",
"reddit",
"telegram",
"discord",
"googlebusiness",
"whatsapp"
],
"type": "string"
},
"description": "Only these networks."
},
"proposedTime": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
"description": "Suggested publish time, ISO 8601. Only a suggestion - pre-fills the user's scheduler."
},
"platformOptions": {
"type": "object",
"properties": {
"reddit": {
"type": "object",
"properties": {
"nsfw": {
"type": "boolean",
"description": "Mark NSFW."
},
"title": {
"type": "string",
"maxLength": 300,
"description": "Title."
},
"spoiler": {
"type": "boolean",
"description": "Mark spoiler."
},
"flairText": {
"type": "string",
"maxLength": 64,
"description": "Flair."
},
"subreddit": {
"type": "string",
"maxLength": 100,
"description": "Subreddit. Posts go to your default subreddit unless set. Flair-required subs reject posts without a flair."
}
},
"description": "Reddit options"
},
"tiktok": {
"type": "object",
"properties": {
"draft": {
"type": "boolean",
"description": "Send to my TikTok inbox instead. It lands in your TikTok inbox so you can add a sound and post it from the app."
},
"allowDuet": {
"type": "boolean",
"description": "Allow duets. Video posts only. Default true."
},
"allowStitch": {
"type": "boolean",
"description": "Allow stitches. Video posts only. Default true."
},
"allowComment": {
"type": "boolean",
"description": "Allow comments. Default true."
},
"autoAddMusic": {
"type": "boolean",
"description": "Let TikTok add music. Photo posts only."
},
"privacyLevel": {
"enum": [
"PUBLIC_TO_EVERYONE",
"MUTUAL_FOLLOW_FRIENDS",
"FOLLOWER_OF_CREATOR",
"SELF_ONLY"
],
"type": "string",
"description": "Who can see it. TikTok asks you to choose this for every post. Required for TikTok. It must be one the account allows."
},
"videoMadeWithAi": {
"type": "boolean",
"description": "Made with AI. Set for you when the post uses an image made with AI."
},
"commercialContentType": {
"enum": [
"none",
"brand_organic",
"brand_content"
],
"type": "string",
"description": "Promotional?. TikTok labels promotional posts. Promoting your own business counts. Values: \"none\" = No, \"brand_organic\" = Yes, my own business, \"brand_content\" = Yes, a paid partnership."
}
},
"description": "TikTok options"
},
"youtube": {
"type": "object",
"properties": {
"tags": {
"type": "array",
"items": {
"type": "string",
"maxLength": 100
},
"maxItems": 60,
"description": "Tags. Search words for YouTube, comma-separated. Up to 500 characters in total."
},
"title": {
"type": "string",
"maxLength": 100,
"description": "Title."
},
"coverUrl": {
"type": "string",
"maxLength": 2048,
"description": "Thumbnail image. Video posts only. An https URL."
},
"coverAtMs": {
"type": "integer",
"maximum": 43200000,
"minimum": 0,
"description": "Thumbnail frame (ms). Video posts only."
},
"categoryId": {
"enum": [
"1",
"2",
"10",
"15",
"17",
"19",
"20",
"22",
"23",
"24",
"25",
"26",
"27",
"28",
"29"
],
"type": "string",
"description": "Category. Values: \"22\" = People & Blogs, \"26\" = Howto & Style, \"27\" = Education, \"28\" = Science & Technology, \"24\" = Entertainment, \"23\" = Comedy, \"1\" = Film & Animation, \"10\" = Music, \"15\" = Pets & Animals, \"17\" = Sports, \"19\" = Travel & Events, \"20\" = Gaming, \"25\" = News & Politics, \"29\" = Nonprofits & Activism, \"2\" = Autos & Vehicles."
},
"madeWithAi": {
"type": "boolean",
"description": "Realistic content made with AI. Tick when it shows realistic people, places or events that were made or changed with AI. YouTube adds a label. Animation and graphics don't need it."
},
"visibility": {
"enum": [
"public",
"unlisted",
"private"
],
"type": "string",
"description": "Visibility."
},
"madeForKids": {
"type": "boolean",
"description": "Made for kids."
}
},
"description": "YouTube options"
},
"facebook": {
"type": "object",
"properties": {
"title": {
"type": "string",
"maxLength": 255,
"description": "Reel title. A separate title shown on the Reel, apart from the caption."
},
"contentType": {
"enum": [
"reel",
"story"
],
"type": "string",
"description": "Post as. A normal post on your Page. One vertical video, shown in Reels. Shows for 24 hours, full screen. One photo or video, no caption. Values: \"reel\" = Reel, \"story\" = Story. Omit for a normal post."
}
},
"description": "Facebook options"
},
"instagram": {
"type": "object",
"properties": {
"coverUrl": {
"type": "string",
"maxLength": 2048,
"description": "Cover image. Video posts only. An https URL."
},
"audioName": {
"type": "string",
"maxLength": 100,
"description": "Audio name. Names the Reel's original sound. Instagram ignores it when the Reel uses licensed music. Video posts only."
},
"coverAtMs": {
"type": "integer",
"maximum": 3600000,
"minimum": 0,
"description": "Cover frame (ms). Video posts only."
},
"reelsOnly": {
"type": "boolean",
"description": "Show only in the Reels tab. Leave it off and the Reel also shows on your profile grid. Video posts only."
},
"contentType": {
"enum": [
"story"
],
"type": "string",
"description": "Post as. A photo or carousel goes to your feed, a video posts as a Reel. Shows for 24 hours, full screen. One photo or video, no caption. Values: \"story\" = Story. Omit for a normal post."
},
"collaborators": {
"type": "array",
"items": {
"type": "string",
"maxLength": 100
},
"maxItems": 3,
"description": "Collaborators. Invite up to 3 Instagram accounts as co-authors, so the post appears on their profile too. They get an invite and the post shows on their profile once they accept."
}
},
"description": "Instagram options"
},
"pinterest": {
"type": "object",
"properties": {
"link": {
"type": "string",
"maxLength": 2048,
"description": "Destination link. Where the pin sends people, usually your product or article page. Without it the pin links nowhere. An https URL."
},
"title": {
"type": "string",
"maxLength": 100,
"description": "Pin title. Pinterest is a search engine, so a clear keyword-led title matters more than the caption."
},
"boardId": {
"type": "string",
"maxLength": 200,
"description": "Board. Pins must go to a board. Pick which one this pin lands on. Omit to use the network's default."
}
},
"description": "Pinterest options"
}
},
"description": "Settings for each network, keyed by network. Only the networks the post goes to are used."
}
}
}The user's follower counts and 7-day growth per connected network, plus which network is growing fastest. Use this to decide where a post matters most or to report progress.
No arguments.
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {}
}Use this to post a file from the user's computer (a video you rendered, a photo). Returns uploadUrl and mediaUrl: PUT the raw file bytes to uploadUrl with its Content-Type header (the curl line in the result does it), then pass mediaUrl in the media list of create_draft or publish_post. Files are stored for good, so a draft keeps its video. Up to 50MB. Types: JPG, PNG, GIF, WebP, MP4, MOV, WebM, or PDF.
| Argument | Type | Description |
|---|---|---|
| size* | integer | File size in bytes |
| filename* | string | The file's name, e.g. reel-week-1.mp4 |
| contentType* | string | MIME type, e.g. video/mp4, video/quicktime, image/jpeg, image/png |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"filename",
"contentType",
"size"
],
"properties": {
"size": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1,
"description": "File size in bytes"
},
"filename": {
"type": "string",
"maxLength": 200,
"minLength": 1,
"description": "The file's name, e.g. reel-week-1.mp4"
},
"contentType": {
"type": "string",
"maxLength": 100,
"minLength": 3,
"description": "MIME type, e.g. video/mp4, video/quicktime, image/jpeg, image/png"
}
}
}The user's connected social accounts (id, network, handle), their account groups (a named set, e.g. one business's Instagram + YouTube), and what each network needs: caption limit, whether it needs a photo or video, and the settings it takes. Call this first, then pass a group name or account handles to create_draft or publish_post.
No arguments.
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {}
}Read the user's recent posts and drafts with per-network status, the live link once a post is up, and the reason when one failed. Published posts include engagement metrics (likes, comments, shares, engagementRate - impressions on plans with full analytics) once analytics have synced. Use it to avoid duplicating a topic AND to learn which topics performed before drafting the next post.
| Argument | Type | Description |
|---|---|---|
| limit | integer | Max results (default 15) |
| status | string | Filter by status (posted and published are synonyms) |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"limit": {
"type": "integer",
"maximum": 50,
"minimum": 1,
"description": "Max results (default 15)"
},
"status": {
"enum": [
"draft",
"scheduled",
"posted",
"published",
"failed",
"partly_posted"
],
"type": "string",
"description": "Filter by status (posted and published are synonyms)"
}
}
}Turn rough notes about what the user did (shipped a feature, fixed a bug, hit a number) into 2-3 finished social-post angles in the user's voice. Grounded only in the notes - never invents facts. Uses one AI generation from the user's monthly quota.
| Argument | Type | Description |
|---|---|---|
| notes* | string | Raw notes about what the user did. Rough is fine. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"notes"
],
"properties": {
"notes": {
"type": "string",
"maxLength": 4000,
"minLength": 8,
"description": "Raw notes about what the user did. Rough is fine."
}
}
}