Posthell

Social media scheduler for AI agents: draft posts into a human-approved queue for 15 networks.

Should I use this

Quality & Safety

A
Description quality
95%
Schema completeness
73%
Naming quality
97%
Poisoning risk
100%
Permission match
90%
Protocol compliance
100%

Findings (2)

  • LOWTool 'shape_post' description lacks action verbin shape_post
  • LOWTool 'get_upload_url' suggests web access but openWorldHint=falsein get_upload_url

Based on automated analysis of tool definitions and protocol compliance.

Context Cost

~3,055Tokens (tool definitions)
~4.7 KBTypical response size
Significant attention impact (2.39% of 128k context)

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": {
    "posthell": {
      "url": "https://www.posthell.com/api/mcp"
    }
  }
}

Remote endpoints

https://www.posthell.com/api/mcpstreamable-http

What it can do

Tool inventory

Tools (6)

🟢 Read-only🟡 Write🔴 Delete⚪ Unknown
🟡shape_post(notes)

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.

Input Schema

{
  "type": "object",
  "properties": {
    "notes": {
      "type": "string",
      "minLength": 8,
      "maxLength": 4000,
      "description": "Raw notes about what the user did. Rough is fine."
    }
  },
  "required": [
    "notes"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢list_accounts

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.

Input Schema

{
  "type": "object",
  "properties": {},
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡get_upload_url(filename, contentType, size)

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.

Input Schema

{
  "type": "object",
  "properties": {
    "filename": {
      "type": "string",
      "minLength": 1,
      "maxLength": 200,
      "description": "The file's name, e.g. reel-week-1.mp4"
    },
    "contentType": {
      "type": "string",
      "minLength": 3,
      "maxLength": 100,
      "description": "MIME type, e.g. video/mp4, video/quicktime, image/jpeg, image/png"
    },
    "size": {
      "type": "integer",
      "minimum": 1,
      "maximum": 9007199254740991,
      "description": "File size in bytes"
    }
  },
  "required": [
    "filename",
    "contentType",
    "size"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡create_draft(body, group, accounts, platforms, media, ...)

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.

Input Schema

{
  "type": "object",
  "properties": {
    "body": {
      "description": "The caption. Optional when the post is a photo or video. For YouTube it becomes the description unless overrides.youtube is set.",
      "type": "string",
      "maxLength": 5000
    },
    "group": {
      "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.",
      "type": "string",
      "maxLength": 60
    },
    "accounts": {
      "description": "Post to these accounts, by handle (e.g. \"posthell_bakery\") or id from list_accounts. Default: every connected account (narrowed by platforms).",
      "maxItems": 20,
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 120
      }
    },
    "platforms": {
      "description": "Only these networks.",
      "type": "array",
      "items": {
        "type": "string",
        "enum": [
          "x",
          "linkedin",
          "instagram",
          "threads",
          "bluesky",
          "facebook",
          "tiktok",
          "youtube",
          "pinterest",
          "reddit",
          "telegram",
          "discord",
          "googlebusiness",
          "whatsapp"
        ]
      }
    },
    "media": {
      "description": "Photos or videos, in order. One video = an Instagram Reel / a YouTube video.",
      "maxItems": 10,
      "type": "array",
      "items": {
        "anyOf": [
          {
            "type": "string",
            "maxLength": 2048
          },
          {
            "type": "object",
            "properties": {
              "url": {
                "type": "string",
                "maxLength": 2048,
                "description": "https URL: a mediaUrl from get_upload_url, or a public file"
              },
              "type": {
                "description": "Read from the file extension when omitted",
                "type": "string",
                "enum": [
                  "image",
                  "video"
                ]
              },
              "alt": {
                "description": "Alt text describing it, for networks that show it",
                "type": "string",
                "maxLength": 500
              }
            },
            "required": [
              "url"
            ]
          }
        ]
      }
    },
    "platformOptions": {
      "description": "Settings for each network, keyed by network. Only the networks the post goes to are used.",
      "type": "object",
      "properties": {
        "reddit": {
          "description": "Reddit options",
          "type": "object",
          "properties": {
            "subreddit": {
              "type": "string",
              "maxLength": 100,
              "description": "Subreddit. Posts go to your default subreddit unless set. Flair-required subs reject posts without a flair."
            },
            "flairText": {
              "type": "string",
              "maxLength": 64,
              "description": "Flair."
            },
            "title": {
              "type": "string",
              "maxLength": 300,
              "description": "Title."
            },
            "nsfw": {
              "type": "boolean",
              "description": "Mark NSFW."
            },
            "spoiler": {
              "type": "boolean",
              "description": "Mark spoiler."
            }
          }
        },
        "pinterest": {
          "description": "Pinterest options",
          "type": "object",
          "properties": {
            "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."
            },
            "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."
            }
          }
        },
        "instagram": {
          "description": "Instagram options",
          "type": "object",
          "properties": {
            "contentType": {
              "type": "string",
              "enum": [
                "story"
              ],
              "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": {
              "maxItems": 3,
              "type": "array",
              "items": {
                "type": "string",
                "maxLength": 100
              },
              "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."
            },
            "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."
            },
            "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."
            },
            "coverUrl": {
              "type": "string",
              "maxLength": 2048,
              "description": "Cover image. Video posts only. An https URL."
            },
            "coverAtMs": {
              "type": "integer",
              "minimum": 0,
              "maximum": 3600000,
              "description": "Cover frame (ms). Video posts only."
            }
          }
        },
        "facebook": {
          "description": "Facebook options",
          "type": "object",
          "properties": {
            "contentType": {
              "type": "string",
              "enum": [
                "reel",
                "story"
              ],
              "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."
            },
            "title": {
              "type": "string",
              "maxLength": 255,
              "description": "Reel title. A separate title shown on the Reel, apart from the caption."
            }
          }
        },
        "tiktok": {
          "description": "TikTok options",
          "type": "object",
          "properties": {
            "privacyLevel": {
              "type": "string",
              "enum": [
                "PUBLIC_TO_EVERYONE",
                "MUTUAL_FOLLOW_FRIENDS",
                "FOLLOWER_OF_CREATOR",
                "SELF_ONLY"
              ],
              "description": "Who can see it. TikTok asks you to choose this for every post. Required for TikTok. It must be one the account allows."
            },
            "allowComment": {
              "type": "boolean",
              "description": "Allow comments. Default true."
            },
            "allowDuet": {
              "type": "boolean",
              "description": "Allow duets. Video posts only. Default true."
            },
            "allowStitch": {
              "type": "boolean",
              "description": "Allow stitches. Video posts only. Default true."
            },
            "commercialContentType": {
              "type": "string",
              "enum": [
                "none",
                "brand_organic",
                "brand_content"
              ],
              "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."
            },
            "videoMadeWithAi": {
              "type": "boolean",
              "description": "Made with AI. Set for you when the post uses an image made with AI."
            },
            "autoAddMusic": {
              "type": "boolean",
              "description": "Let TikTok add music. Photo posts only."
            },
            "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."
            }
          }
        },
        "youtube": {
          "description": "YouTube options",
          "type": "object",
          "properties": {
            "title": {
              "type": "string",
              "maxLength": 100,
              "description": "Title."
            },
            "visibility": {
              "type": "string",
              "enum": [
                "public",
                "unlisted",
                "private"
              ],
              "description": "Visibility."
            },
            "tags": {
              "maxItems": 60,
              "type": "array",
              "items": {
                "type": "string",
                "maxLength": 100
              },
              "description": "Tags. Search words for YouTube, comma-separated. Up to 500 characters in total."
            },
            "categoryId": {
              "type": "string",
              "enum": [
                "1",
                "2",
                "10",
                "15",
                "17",
                "19",
                "20",
                "22",
                "23",
                "24",
                "25",
                "26",
                "27",
                "28",
                "29"
              ],
              "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."
            },
            "madeForKids": {
              "type": "boolean",
              "description": "Made for kids."
            },
            "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."
            },
            "coverUrl": {
              "type": "string",
              "maxLength": 2048,
              "description": "Thumbnail image. Video posts only. An https URL."
            },
            "coverAtMs": {
              "type": "integer",
              "minimum": 0,
              "maximum": 43200000,
              "description": "Thumbnail frame (ms). Video posts only."
            }
          }
        }
      }
    },
    "overrides": {
      "description": "A caption of its own for a network, used instead of body there. For YouTube this is the video description.",
      "type": "object",
      "properties": {
        "x": {
          "type": "string",
          "maxLength": 5000
        },
        "linkedin": {
          "type": "string",
          "maxLength": 5000
        },
        "instagram": {
          "type": "string",
          "maxLength": 5000
        },
        "threads": {
          "type": "string",
          "maxLength": 5000
        },
        "bluesky": {
          "type": "string",
          "maxLength": 5000
        },
        "facebook": {
          "type": "string",
          "maxLength": 5000
        },
        "tiktok": {
          "type": "string",
          "maxLength": 5000
        },
        "youtube": {
          "type": "string",
          "maxLength": 5000
        },
        "pinterest": {
          "type": "string",
          "maxLength": 5000
        },
        "reddit": {
          "type": "string",
          "maxLength": 5000
        },
        "telegram": {
          "type": "string",
          "maxLength": 5000
        },
        "discord": {
          "type": "string",
          "maxLength": 5000
        },
        "googlebusiness": {
          "type": "string",
          "maxLength": 5000
        },
        "whatsapp": {
          "type": "string",
          "maxLength": 5000
        }
      }
    },
    "proposedTime": {
      "description": "Suggested publish time, ISO 8601. Only a suggestion - pre-fills the user's scheduler.",
      "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)))$"
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢list_posts(status, limit)

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.

Input Schema

{
  "type": "object",
  "properties": {
    "status": {
      "description": "Filter by status (posted and published are synonyms)",
      "type": "string",
      "enum": [
        "draft",
        "scheduled",
        "posted",
        "published",
        "failed",
        "partly_posted"
      ]
    },
    "limit": {
      "description": "Max results (default 15)",
      "type": "integer",
      "minimum": 1,
      "maximum": 50
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢get_growth

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.

Input Schema

{
  "type": "object",
  "properties": {},
  "$schema": "http://json-schema.org/draft-07/schema#"
}

Community

Rate this Server

Evidence

Recent observations

verifiedversion not recorded6 tools
verifiedversion not recorded4 tools
verifiedversion not recorded4 tools
verifiedversion not recorded4 tools
verifiedversion not recorded4 tools
verifiedversion not recorded4 tools