MCP Server
Schedule posts from Claude, ChatGPT, Cursor, or any MCP-compatible client, over stdio (npm) or HTTP.
posterly speaks the Model Context Protocol so any MCP-compatible AI client can list connected accounts, schedule posts, and pull analytics on the user's behalf. Two connection options are available, pick the one that fits your client.
New accounts that start from /mcp get a plan plus API & MCP in one Stripe subscription (Starter + API is $10/month, or $96/year from the pricing page) with a 7-day free trial, then billed on the same monthly or yearly cycle as the plan. An account that already had a trial is charged immediately. Trial limits apply: 20 write and 100 read requests per hour, 25 posts created through the API and MCP, and batch posting, AI video, webhooks and OAuth clients unlock when the paid plan starts. After checkout, create a key at Dashboard → API & MCP.
Two connection options
1. Stdio (npm package), desktop AI clients
For Claude Code, Cursor, Windsurf, Cline, Claude Desktop local developer configuration, and other clients that run a local MCP subprocess. Claude chat uses the hosted option below without npm. ChatGPT uses the plugin listing. Developer mode is the advanced alternative on the same hosted URL.
You do not need to install anything globally. Add this to your client's MCP config and let npx run the current server:
{
"mcpServers": {
"posterly": {
"command": "npx",
"args": ["-y", "posterly-mcp-server@latest"],
"env": {
"POSTERLY_API_KEY": "pst_live_your_key_here"
}
}
}
}
Quick setup, copy for your AI: Use Copy setup for your AI at Dashboard → API & MCP. It explains both hosted MCP and local npm setup, then helps your AI choose the option that fits your client. Local npm setup needs an API key; hosted OAuth connectors use posterly sign-in.
If the user has not signed up yet, install the same server without POSTERLY_API_KEY. The public tools get_agent_signup_info, start_signup, and get_signup_session work before a key exists, so the AI can start the 7-day free trial (a card is required, nothing is charged today, and the card is charged on day 8 unless the paid plan starts sooner), send the posterly checkout handoff URL, or complete Checkout only with a reusable card, then poll progress while the user sets a password in the browser. API and MCP stay limited during the trial, and the API add-on is still required. See Pay for posterly from an agent.
2. HTTP, browser-based AI clients
For Claude.ai, Claude Desktop chat connectors, ChatGPT, Cursor in browser, Grok Bot, or any web-based or cloud agent that can't spawn a local process. Add posterly in ChatGPT from the plugin listing. Developer mode is the advanced alternative. Dedicated connect pages: Claude, Add posterly in ChatGPT, Gemini, Cursor, Grok Bot, Poke, Hermes, OpenClaw, Muse, Manus, and Cue. Gemini Spark uses the same URL. OAuth sign-in from gemini.google.com is still being validated. Manus and Cue are Custom MCP by URL. A verified live connect for those clients is still being validated. First-schedule walkthroughs: ChatGPT, Claude, Cursor, Poke, Hermes, OpenClaw, Grok Bot Marketplace. Media bodies: Solving the 4MB MCP limit.
In Claude, open Settings → Connectors → Add custom connector. Name it posterly, paste https://www.poster.ly/api/mcp, then choose Connect, sign in to posterly and press Allow. Leave the advanced OAuth client ID and secret fields empty. No npm install or API key is needed for this OAuth connection. Teammates use the workspace API access their owner enabled.
Use the exact HTTPS URL with www. https://poster.ly/api/mcp returns a 307 redirect to it; some connector clients do not handle that redirect. If consent says the connection request expired, return to the AI client's connector settings and start Connect again. Press Allow once and wait while the connection completes.
- Endpoint:
POST https://www.poster.ly/api/mcp - Wire format: JSON-RPC 2.0 (single request, no SSE or streamable HTTP in v1)
- Authentication: OAuth sign-in for hosted custom connectors, or
Authorization: Bearer pst_live_your_key_herein clients that support custom headers - Capability hint:
GET /api/mcpreturns server info without auth. - Muse Custom Connector: Connect posterly to Muse. OpenAPI plus Bearer is the primary path. Hosted MCP is optional. If Muse requires streamable HTTP, stay on OpenAPI and treat hosted MCP as a known gap.
- Manus and Cue: Manus and Cue. Custom MCP by URL at
https://www.poster.ly/api/mcp(www required). OAuth is preferred, with Authorization Bearerpst_live_…as the fallback. This is not a directory listing. A verified live connect is still being validated because v1 is a JSON-RPC 2.0 single POST, with no SSE or streamable HTTP.
Quick smoke test from any terminal:
curl -s https://www.poster.ly/api/mcp \
-H "Authorization: Bearer pst_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Both options use the same API access and route-aware API limits. Hosted OAuth creates a token after browser consent; local npm and custom-header connections use an API key. They expose the same authenticated toolset, but media upload ergonomics differ by transport because hosted HTTP MCP tool calls are JSON only.
Create-post calls are limited to 100 requests per hour per key. This does not mean you can only schedule 100 posts per hour: use create_posts_batch to create up to 25 posts in one confirmed request. Media writes and read-only calls have separate higher limits.
User-created API keys are tier-based: Starter 1, Pro 2, Power 3, Agency 4. Keys can also be scoped to one workspace; connection handoff and webhook tools use the scoped workspace automatically and reject a different workspace_id.
Managed connection through Smithery
Smithery provides a managed connection to the same hosted HTTP MCP endpoint. It uses posterly OAuth, so users authorize their own account without pasting a posterly API key into Smithery.
- Open the posterly server on Smithery.
- Add or connect it to your Smithery toolbox.
- Sign in to posterly, or create an account if needed.
- Review the requested account, post, media, and analytics scopes.
- Select Allow, then return to Smithery and test with
whoamiorlist_accounts.
Each OAuth connection belongs to the posterly user who approved it. Other Smithery users cannot access that user's accounts, posts, media, or analytics. An active posterly plan plus the API/MCP add-on is still required; Smithery does not provide free posterly API access.
For permission explanations, example prompts, and troubleshooting, read the Smithery social media MCP setup guide.
Media upload: where the 4MB limit exists, and how to get past it
Vercel caps request bodies to posterly API routes at about 4MB. Hosted MCP (POST /api/mcp) is JSON on that same path, so a base64 file inside upload_media counts against it. Base64 also inflates the file, so hosted upload_media is only for small images. Our relay cap is 5MB decoded; treat anything larger as signed upload.
This is not an MCP-protocol file limit, and it is not posterly's plan storage cap. It is the function body on Vercel.
| Path | Hits the ~4MB Vercel body? | What to use it for |
|---|---|---|
Hosted MCP upload_media (base64 JSON to /api/mcp) | Yes | Small images only |
REST POST /api/v1/media/upload (base64) | Yes | Small images only |
Legacy PUT /api/v1/media/signed-upload/upload | Yes | Do not use. Returns FUNCTION_PAYLOAD_TOO_LARGE on large videos |
upload_media with url / create_post with a third-party media_url | The JSON call is small. posterly then fetches the URL on the server | Small public files. About 5MB on the relay path, 60MB remote-fetch hard cap. Large R2/S3 URLs fail with remote_media_too_large |
MCP create_signed_upload, then PUT bytes to upload_url | No. The PUT goes to object storage (R2/Supabase), not Vercel | Videos and large images. Plan caps: Starter 500MB, Pro 750MB, Power 1GB, Agency 4GB |
MCP create_media_drop, human opens /drop/<token> | No. The browser PUTs to object storage | ChatGPT web, Claude.ai, and Gemini web laptop files. Agent then calls list_media |
Stdio upload_media with file_path | No. The npm server reads the disk and uses signed upload for large files | Cursor, Claude Code, Claude Desktop, Codex, Hermes: give a real local path |
CLI media:signed-upload then PUT | No | Scripts and coding agents that can HTTP PUT |
| Dashboard composer and Media Library | No. They already use signed / direct storage | Humans in the app |
create_signed_upload is the bypass when the agent can PUT the file itself (know filename, content_type, and exact size, then PUT raw bytes to upload_url with the returned headers, then pass public_url to create_post). It handles 1 to 20 files per call: pass files and each file gets its own slot or its own error, and slots expire in 15 minutes. Pass pin_content_type: true to lock each slot to the content_type you declare: the PUT must then send exactly the returned Content-Type header or storage answers 403 (the slot says content_type_pinned: true; posterly may turn pinning on by default in the future, so always send the returned Content-Type). The npm stdio upload_media with file_path already sends the returned headers as is. It also takes a PDF (content_type application/pdf, filename ending in .pdf, up to 50MB): to publish it, call create_post with post_type document, media_url set to the public_url, and a document_title in settings. Only LinkedIn publishes documents. Cursor, Claude Code, and Codex can do that.
ChatGPT web, Claude.ai, and Gemini web cannot PUT a laptop file, and chat paperclips never reach MCP. For those clients call create_media_drop, send the user drop_url (https://www.poster.ly/drop/<token>), wait, then call list_media. One drop link takes up to 20 files. Accepted: JPEG, PNG, GIF, WebP, MP4, MOV, WebM, and PDF up to 50MB (a PDF is for LinkedIn document posts). HEIC is not accepted: export or convert it to JPG or PNG first. Plan video caps still apply: Starter 500MB, Pro 750MB, Power 1GB, Agency 4GB.
Why the 4MB number exists, and which tool to call on each runtime: Solving the 4MB MCP limit.
Local stdio MCP can read a local file path and automatically use signed upload for larger media. Use this when the agent is on the same machine as the file.
Hosted HTTP MCP has no binary channel. For larger media on a client that can PUT:
- Call
create_signed_uploadwithfilename,content_type, andsize, or withfiles(up to 20) to get one slot per file in a single call. - PUT the raw file bytes to the returned
upload_url(object storage). Do not PUT to aposter.lyAPI route. - Pass
public_urlintovalidate_post/create_post.
Do not pass a 500MB to 2GB Cloudflare R2, S3, or other remote URL straight to create_post. That fetch fails with remote_media_too_large. Download it (or PUT it) via signed upload instead.
Uploaded media is analyzed automatically in the background. If a video can never reach a selected platform (for example, it is longer than the platform allows, or too large for the platform's file size limit), create_post rejects that combination with an actionable message such as "This video is too large for Telegram (50 MB multipart limit). Export it under 50 MB to include Telegram." Relay the message to the user. Colour, geometry, and scan-mode conversions (and container remuxes) are handled automatically at publish, so media that only needs one of those is never rejected for that reason; duration and file size limits still apply.
Incomplete or non-standard colour tags do not reject create_post or validate_post. validate_post / dry_run: true may include a video_requires_color_safe_pipeline warning. Missing or non-square pixel geometry also does not reject create. validate_post / dry_run: true may include a video_requires_geometry_normalization warning when the file is known to use non-square pixels. An unverified scan tag (progressive versus interlaced) also does not reject create or publish. At publish time, posterly converts the video when the analysis allows, or publishes the original file. A converted file that is otherwise usable is not rejected only because its measured frame rate differs slightly from the planned output. You do not need to re-export Rec.709, a square-pixel file, or a tagged progressive MP4 before including Facebook or Instagram. Compatible originals, remuxes, and video-copy repairs still pass. See Video colour compatibility, Video pixel geometry, and Video scan mode and converted-file checks.
create_post and validate_post still reject media combinations that no platform call could satisfy: a video that is too long or below a platform minimum, a PDF sent anywhere other than LinkedIn, an .avi or .mkv video sent to Instagram, an Instagram feed photo (or still carousel slide) taller than 9:16 or wider than 1.91:1 when posterly knows the image's dimensions (publish-time preparation is the final check), a YouTube still photo (JPEG, PNG, WebP, GIF, and other image files; message: "YouTube needs a video file, not a photo. Upload a video and try again.", code youtube_still_image_unsupported), and an Instagram account that is missing its business account id (which needs reconnecting in posterly). Relay those messages rather than retrying. Stories, Reels, and Story Series stills are not held to those feed bounds.
The .mov, .webm and .m4v containers remain accepted at creation. Whether a repair is needed depends on the inspected input and destination; compatible originals can pass through unchanged.
Agent response style
MCP signup and connect tools return user-facing guidance by default. Agents should narrate progress in plain language, send the secure browser links, and avoid showing raw curl commands, HTTP payloads, or JSON unless the user asks for debugging.
Use debug: true only when you deliberately need the raw signup or connect response for troubleshooting. The tools that support this are start_signup, get_signup_session, create_connect_session, list_platforms with view: "connect_link", and list_accounts with view: "connect_session".
Post tools also return posterly dashboard links. After creating, listing, reading, or deleting posts, share the returned View in posterly link so the user lands in the right dashboard view. Current-month scheduled posts open in Calendar with the post selected; general/future post lists fall back to Table. Reading one post names its platform and account, and when a publish failed, the reason. The missing view lists each gap and how to fix it. A post that belongs to a group shows that group id, the same id a group update or delete already accepts. Listing posts also includes a link back to posterly, and the platform when the post has one. A team list includes each member's user id when the workspace API sends it, so it can be matched to the account that created a post.
Auto-discovery for agents
posterly publishes the standard .well-known discovery endpoints so agents can find everything programmatically:
| URL | Purpose |
|---|---|
/.well-known/mcp/server-card.json | MCP server card, describes both connection options + tools |
/.well-known/api-catalog | RFC 9727 linkset describing the REST API surface |
/.well-known/oauth-authorization-server | RFC 8414, authorize/token/register endpoints, refresh-token grant |
/.well-known/oauth-protected-resource | RFC 9728, bearer methods, scopes, where to mint tokens |
/.well-known/agent-skills/index.json | Cloudflare Agent Skills index, links to SKILL.md files |
/api/openapi | Full OpenAPI 3.1 spec for the REST API |
Public marketing pages also emit RFC 8288 Link headers pointing at all of the above, so agents that crawl https://www.poster.ly discover the API surface without any prior configuration.
ChatGPT Apps and the OpenAI plugin directory verify control of poster.ly by fetching /.well-known/openai-apps-challenge. That URL is a domain-verification check for review, not a public listing.
Auth & billing handoff (RFC 6750)
When an agent calls a tool with a missing/invalid token or no API add-on, posterly returns a WWW-Authenticate header that tells the agent exactly what to do, surface this to the user and they can subscribe inside the agent conversation.
- 401 invalid_token,
WWW-Authenticate: Bearer ... token_uri="https://www.poster.ly/dashboard/api" - 403 insufficient_subscription,
WWW-Authenticate: Bearer ... error_uri="https://www.poster.ly/dashboard/api?upgrade=api_addon" - 403 trial_feature_locked, the workspace owner is on the free trial and the tool needs batch posting, AI video generation, webhooks or OAuth clients. Starting the paid plan unlocks it; retrying does not help.
- 403 trial_post_cap_reached, the free trial's 25 posts created through the API and MCP are used up. Starting the paid plan lifts the cap.
- 403 api_access_not_granted, the token is bound to a workspace where the owner has not turned on API access for this teammate (or the owner's add-on lapsed). Ask the workspace owner to turn it on in Team settings.
- 400 workspace_id_required, the connection can act in more than one workspace and the call did not say which. Pass
workspace_id(fromwhoami).generate_image,generate_video,upload_media,create_signed_uploadandcreate_media_droptake an optionalworkspace_idfor this. - 403 insufficient_scope,
WWW-Authenticate: Bearer ... scope="posts:write" - 403 origin_not_allowed, browser caller from an Origin not on the trusted MCP host list (Claude, ChatGPT, Gemini, posterly, localhost, plus
MCP_TRUSTED_ORIGINS). - 429, body includes
retry_after,limit,remaining, andreset, plus aRetry-Afterheader. On the free trial the hourly limits are 20 write and 100 read requests.
Hosted MCP clients (Claude.ai, ChatGPT, and similar)
Browser-hosted MCP clients can complete a full OAuth connect flow without a human allowlisting the app first. Two paths are supported:
- Client ID Metadata Documents, for hosts that send an HTTPS
client_idpointing at a published metadata document. Claude.ai / Claude Connectors uses this (https://claude.ai/oauth/mcp-oauth-client-metadata, callbackhttps://claude.ai/api/mcp/auth_callback, token authnone). ChatGPT custom connectors publish a per-connector document (https://chatgpt.com/oauth/.../client.json, callbackhttps://chatgpt.com/connector/oauth/...) with aprivate_key_jwtpreference,token_endpoint_auth_methods_supportedofnoneandprivate_key_jwt, and ajwks_urion chatgpt.com. posterly fetches the document from a small allowlist of known connector hosts (Claude, ChatGPT, Cursor, Smithery, andaccountlinking.google.comfor Gemini Spark) and verifies a signed token request when present, or accepts PKCE-only when the document also listsnone. This is not Dynamic Client Registration. - RFC 7591 Dynamic Client Registration, for hosts that register at
POST /api/oauth/register. Send a JSON metadata document (client_name,redirect_uris,scope) and receive aclient_idimmediately. DCR clients stay public PKCE (none); they do not useprivate_key_jwt.
Gemini web sign-in and tool discovery are still being validated. The experimental setup uses the hosted URL https://www.poster.ly/api/mcp. Gemini may present a Client ID Metadata Document whose client_id is an HTTPS URL on accountlinking.google.com (for example https://accountlinking.google.com/clientidmetadata/...). The redirect URI in that document can sit on another Google host, including googleusercontent.com, and is matched exactly. The same apps can also register with Dynamic Client Registration, which already accepts those googleusercontent.com redirect URIs. The exact browser origins https://gemini.google.com and https://www.gemini.google.com are trusted. These allowlists do not establish a successful end-to-end connection. google.com is not opened as a suffix: when the document uses private_key_jwt, its jwks_uri must stay on accountlinking.google.com or a subdomain of it, the same host-family rule ChatGPT uses for chatgpt.com.
Both paths then use the standard authorization-code + PKCE flow at https://www.poster.ly/oauth/authorize.
- If you are new and still need a plan, posterly sends you to choose a plan and then returns you to the consent screen. The API add-on is still required before the access token activates.
- The consent screen flags self-registered (DCR) clients so the user can decide whether to trust the source.
- Access tokens issued via DCR or a CIMD client that authenticates with
private_key_jwtlive 1 hour, with a rotating refresh token (30 days; reuse revokes the chain). Claude CIMD (none), and ChatGPT when it usesnone, keep a long-lived access token and no refresh grant. grant_type=refresh_tokenat/api/oauth/tokento renew, using the method the client actually presented (signed assertion when present, otherwisenoneif the document supports it).
The discovery document at /.well-known/oauth-authorization-server advertises client_id_metadata_document_supported, registration_endpoint, token_endpoint, token_endpoint_auth_methods_supported (none and private_key_jwt), and the supported grants so MCP hosts can wire this up automatically. API keys still work for stdio MCP and scripts.
Available tools
The local stdio server exposes 73 tools covering 115 actions. The public setup tools work without POSTERLY_API_KEY; everything else needs a posterly API key. The HTTP MCP connection is authenticated and exposes 70 tools covering 112 actions (the same catalog minus the three signup tools).
Older tool names were merged into the tools below and keep working for now. See MCP tool changes for the full old-to-new table, the date the old names may stop working, and what to update in scripts and permission settings.
How merged tools work
Many tools pick what to do with one parameter:
viewon read tools, for examplelist_brandswithview: "profile".actionon write tools, for examplemanage_commentwithaction: "reply".typeonlist_jobs(imageorvideo).
A few tools pick their mode from which parameters you pass: update_post changes the status when you pass status, delete_post deletes a group when you pass group_id, upload_media copies a public file when you pass url and deletes one library file when you pass asset_id (preview first), and list_comments / list_conversations return one item when you pass its ID. Every tool description names all of its views and actions, so the AI knows what is inside.
Preview then confirm
Actions that post publicly or delete things work in two steps. The first call, without confirm, changes nothing: it returns a plain summary of what will happen and a preview_id. Show it to the user. Only after they approve, call again with the same fields plus confirm: true and that preview_id.
- A preview expires after 10 minutes and only works for exactly the same fields and the same user.
- Public posts (a comment reply, a DM, a Google review reply, new Google profile media) can be confirmed once, so a retry never posts twice.
- Other writes keep a single
confirm: trueafter explicit user confirmation.
Tool sets
Every tool belongs to one set: core, creative, inbox, google_business, admin, and billing, plus signup on the local npm package (always on). Every set is listed by default, so you do not need to do anything. To load fewer tools:
- Stdio (npm): set
POSTERLY_TOOLSETS=core,inboxin the server'senv(or pass--toolsets=core,inbox). - HTTP with an API key in the
Authorizationheader: usehttps://www.poster.ly/api/mcp?toolsets=core,inbox. - OAuth connectors (Claude.ai, ChatGPT, Gemini Spark) always get every set.
Sets only change which tools are listed. Any tool can still be called by name, and whoami mentions the active sets when a filter is on.
Tool reference
Every tool, grouped by set, with its views or actions.
Core (core)
Accounts, posting, media, schedule, analytics, and support. What most assistants need.
| Tool | What it does |
|---|---|
disconnect_account | Disconnect an account |
connect_account | Connect with credentials |
create_connect_session | Start a connect session |
trigger_platform_helper | Run a platform helper |
ask_support | Ask support |
find_available_slot | Find a free slot |
submit_agent_feedback | Agent feedback |
submit_product_feedback | Product feedback |
validate_post | Validate a post |
create_post | Create a post |
create_posts_batch | Create posts in bulk |
get_x_posting_quota | X posting quota |
create_signed_upload | Signed upload link |
create_media_drop | Media drop link |
list_media | Media library |
generate_captions | Generate captions |
list_activity | Activity feed |
get_credits | AI credits |
get_updates | Product updates |
posterly_status | Publishing status |
whoami: Who am I
| View | What it does |
|---|---|
identity (default) | You, your scopes, and your workspaces |
status | MCP server and connection status |
list_accounts: Connected accounts
| View | What it does |
|---|---|
accounts (default) | Connected accounts |
learned_voice | Learned voice of an account |
performance_profile | Performance profile of an account |
connect_session | Check a connect session |
list_platforms: Platforms
| View | What it does |
|---|---|
platforms (default) | Supported platforms |
schema | Platform or account schema |
connect_link | Connection links |
list_brands: Brands
| View | What it does |
|---|---|
brands (default) | All brands |
brand | One brand |
accounts | Brand accounts |
profile | Brand profile |
manage_brand: Create, update, or archive a brand
create and update need an admin, and confirm: true only after the user agrees. archive needs an admin: call it once without confirm, show the preview, then call again with confirm: true and that preview_id. Archiving takes the brand off the active list. Connected accounts stay connected, and scheduled posts are not cancelled: they still publish.
list_posts: Posts
| View | What it does |
|---|---|
list (default) | Posts, one page at a time |
counts | Post counts by day, status, account, and brand |
get_post: One post
| View | What it does |
|---|---|
post (default) | One post, including platform, account, a link back to posterly, and the failure reason when a publish failed |
missing | Each missing field and how to fix it |
update_post: Edit a post
| Mode (picked by params) | What it does |
|---|---|
edit (default) | Edit caption, media, schedule, or settings. If the post's status or pending publish changes while the update runs (for example during a video check), it answers post_changed; reload the post with get_post and retry |
status (pass status) | Pause, resume, schedule, or move to draft |
release_id (pass release_id) | Set a release or group ID |
approval (pass approval_action) | Request, approve, request changes, or reject client review (owner or admin only) |
delete_post: Delete posts
| Mode (picked by params) | What it does |
|---|---|
post (default) | Delete one post. Choose delete_mode: posterly keeps live content; platform also requires confirm_published |
group (pass group_id) | Delete a post group (preview then confirm). Never deletes published posts |
upload_media: Upload media
| Mode (picked by params) | What it does |
|---|---|
file (default) | Upload a file |
url (pass url) | Upload from a URL |
list_analytics: Analytics
| View | What it does |
|---|---|
accounts | Account analytics |
posts | Post analytics |
insights | Post insights |
Creative (creative)
AI image and video generation, jobs, and post suggestions.
| Tool | What it does |
|---|---|
list_post_suggestions | Post suggestions |
dismiss_suggestion | Dismiss a suggestion |
get_video_options | Video options |
run_video_function | Video helper |
generate_video | Generate a video |
generate_image | Generate an image |
list_jobs: AI jobs
| Type | What it does |
|---|---|
image | Image jobs |
video | Video jobs |
Inbox (inbox)
Social inbox comments and DMs.
list_conversations: Conversations
| Mode (picked by params) | What it does |
|---|---|
list (default) | List conversations |
conversation (pass conversation_id) | One conversation with its messages |
manage_conversation: Manage conversations
| Action | What it does |
|---|---|
send | Send a DM (preview then confirm) |
sync | Sync the inbox |
list_comments: Comments
| Mode (picked by params) | What it does |
|---|---|
list (default) | List comments |
comment (pass comment_id) | One comment with its replies |
manage_comment: Manage comments
| Action | What it does |
|---|---|
reply | Reply to a comment (preview then confirm) |
update | Hide or mark read |
delete | Delete a comment (preview then confirm) |
Google Business (google_business)
Google Business Profile reviews, media, and audits. Limits, example prompts, and connection notes are on the Google Business Profile MCP connector.
| Tool | What it does |
|---|---|
audit_google_business_profile | Audit a Google profile |
list_google_business_media | Google profile media |
list_google_business_service_areas | Google service areas |
manage_google_business_service_area | Update Google service areas |
list_google_business_service_areas: Google service areas
| View | What it does |
|---|---|
areas (default) | Towns and postcodes already set on one location |
places | Search for a town or postcode to add |
manage_google_business_service_area: Update Google service areas
| Action | What it does |
|---|---|
update | Replace the service area list (preview then confirm) |
list_google_business_reviews: Google reviews
| View | What it does |
|---|---|
reviews (default) | Google reviews, each with review_name for a reply |
review_link | Google review link |
manage_google_business_review: Manage Google reviews
| Action | What it does |
|---|---|
suggest_reply | Suggest a reply (never posts) |
reply | Reply to a review (preview then confirm) |
delete_reply | Delete a review reply (preview then confirm) |
Each review from list_google_business_reviews includes review_name (accounts/{account}/locations/{location}/reviews/{review}) plus account_id and location_id when known. Pass that review_name with account_id (or location_id) to manage_google_business_review reply or delete_reply. Do not pass the Place ID from view: "review_link".
manage_google_business_media: Manage Google profile media
| Action | What it does |
|---|---|
add | Add a photo or video (preview then confirm) |
delete | Delete a photo or video (preview then confirm) |
list_google_business_locations: Google location hours
Reads regular opening hours and attributes for one location. Stays off until location edits are switched on.
manage_google_business_location: Manage a Google location
| Action | What it does |
|---|---|
update_hours | Update regular hours (preview then confirm) |
update_attributes | Update attributes (preview then confirm) |
Admin (admin)
API keys, OAuth clients, webhooks, workspace members, and the publishing pause.
| Tool | What it does |
|---|---|
create_api_key | Create an API key |
delete_api_key | Revoke an API key |
list_workspace_members | Workspace members |
list_publishing_pauses | Publishing pause: whether the workspace or any brand is paused, and what you may do |
list_oauth_clients | OAuth clients |
list_webhooks | Webhooks |
create_webhook | Create a webhook |
list_webhooks: Webhooks
| View | What it does |
|---|---|
webhooks (default) | Webhook subscriptions |
deliveries | Recent delivery attempts for one webhook. Stays off until delivery history is switched on |
manage_workspace_member: Manage a workspace member
| Action | What it does |
|---|---|
invite | Invite a colleague (preview then confirm) |
update | Change role or brands, or turn a teammate's API and AI access on or off (preview then confirm) |
remove | Remove a member or invite (preview then confirm) |
manage_publishing_pause: Pause or resume publishing
| Action | What it does |
|---|---|
pause | Pause publishing for the workspace or one brand: call without confirm for a preview of what it holds, then confirm: true after the user agrees (publisher or higher) |
resume | Resume publishing: future posts are scheduled again, posts that missed their time stay paused and are listed (admin or higher) |
publish_missed | Publish missed posts now, with confirm: true after the user agrees (admin or higher) |
manage_oauth_client: Manage an OAuth client
| Action | What it does |
|---|---|
create | Create an OAuth client |
update | Update an OAuth client |
delete | Delete an OAuth client (preview then confirm) |
manage_webhook: Manage a webhook
| Action | What it does |
|---|---|
update | Update a webhook |
delete | Delete a webhook (preview then confirm) |
test | Send a test delivery |
Billing (billing)
Subscription changes and Agency extra accounts.
| Tool | What it does |
|---|---|
get_subscription | Subscription, plans above yours with prices, extra accounts (Agency owners) and the exact next steps |
cancel_subscription | Cancel subscription |
pause_subscription | Pause subscription |
resume_subscription | Resume subscription |
downgrade_subscription | Downgrade subscription |
upgrade_subscription: Upgrade subscription
| Action | What it does |
|---|---|
upgrade | Move to a higher plan: quote the exact charge, then upgrade after confirm: true with the preview_id (preview then confirm) |
manage_extra_account: Buy or remove extra accounts
| Action | What it does |
|---|---|
set | Set extra accounts: quote the exact charge, then buy, raise, lower, or remove them after confirm: true with the preview_id (preview then confirm) |
manage_x_posting_addon: Buy an X posting add-on
| Action | What it does |
|---|---|
buy | Quote the monthly price, then open Stripe Checkout after the user agrees. Nothing is charged until that page is paid. An add-on that is already on opens the billing page for the owner instead. |
Signup (signup)
Pre-auth signup for brand-new users. Local npm package only; always on.
| Tool | What it does |
|---|---|
get_agent_signup_info | Signup info for agents |
start_signup | Start a free trial |
get_signup_session | Check a signup session |
Tool notes
Setup and status
whoami(default view) shows the user, workspaces, and scopes your key can access.view: "status"shows the installed server version, latest npm version, MCP endpoint health, API auth health, and update guidance, and works beforePOSTERLY_API_KEYis set. It does not report posterly's publishing health; useposterly_statusfor that.get_agent_signup_infoexplains the safe agent-led signup flow.start_signupstarts the card-backed 7-day free trial and returns a poll URL, a browser Checkout handoff, and apaymentobject (trial length, whether anything is charged today, and agent-wallet instructions). Agent-card pay is not available during a trial.get_signup_sessionpolls checkout, card save, password, and agent-access status.
Accounts, connections, and keys
list_accountsshows connected social accounts (passaccount_idfor one). Account and post ids are plain numbers, with no thousands separators. A number copied with commas, such as1,961, is still accepted.view: "learned_voice"reads the voice posterly learned from one account's real published captions (the "learned captions" on the dashboard): a narrative summary, voice traits, style guidelines, and observed posting habits; read-only, it never overwrites the saved brand profile.view: "performance_profile"reads the profile posterly derives from the last 90 days of per-post analytics (top formats, timing, caption-length patterns, an engagement-rate trend, and a narrative summary; Pro plan or higher).view: "connect_session"polls connection progress while the user logs in, approves OAuth, or enters credentials.list_accountsshows connected social accounts (passaccount_idfor one).view: "learned_voice"reads the voice posterly learned from one account's real published captions (the "learned captions" on the dashboard): a narrative summary, voice traits, style guidelines, and observed posting habits; read-only, it never overwrites the saved brand profile.view: "performance_profile"reads the profile posterly derives from the last 90 days of per-post analytics (top formats, timing, caption-length patterns, an engagement-rate trend, and a narrative summary; Pro plan or higher).view: "connect_session"polls connection progress while the user logs in, approves OAuth, or enters credentials. Each account row also says whether the connection is fine or needs a reconnect, with a short reason and a date, and never a token. Passconnection: "needs_reconnect"to see only those accounts. The connect page in the dashboard already shows the same reconnect prompt.disconnect_accountdisconnects a connected social account after explicit confirmation. It preserves reconnect metadata, archives Instagram analytics, and emitsaccount.disconnectedwebhooks. Scheduled posts for that account are paused rather than left scheduled to fail at publish time.list_platformsinspects supported integrations, post types, media limits, analytics support, and planned providers.view: "schema"returns the settings fields for one connectedaccount_id(preferred, with connection-specific capabilities) or oneplatform.view: "connect_link"inspects dashboard connection links, provider readiness, required scopes, and connected account counts; passtargetfor one connection target.connect_accountconnects a credential-based account (telegram, bluesky, discord, wordpress, devto, hashnode, lemmy) directly, no browser session needed.create_connect_sessioncreates a guided browser handoff for connecting a social account.trigger_platform_helperruns helper discovery such aspinterest.boards,youtube.playlists,tiktok.creator_info,linkedin.recent_mentions, orx.quota.create_api_keycreates a new scoped API key after explicit confirmation. The calling key must be a dashboard-created key, and new scopes cannot exceed the calling key.delete_api_keyrevokes a user-created API key after explicit confirmation; it refuses to revoke the key currently authenticating the request.whoamiwithinclude: "api_keys"lists the keys on this account: name, the start of the key, what it can do, when it was created, and when it was last used. The secret is never returned. Managed assistant connections and OAuth connections are left off that list. A key that is locked to one workspace only sees keys for that workspace. The API keys page shows the same permissions, and asks you to confirm before a key is revoked.trigger_platform_helperruns helper discovery such aspinterest.boards,youtube.playlists,tiktok.creator_info,linkedin.recent_mentions,linkedin.company_lookup, orx.quota. YouTube playlists and LinkedIn company lookup stay off until they are switched on. Company lookup uses the organization name search the composer already uses.create_api_keycreates a new scoped API key after explicit confirmation. The calling key must be a dashboard-created key, and new scopes cannot exceed the calling key.delete_api_keyrevokes a user-created API key after explicit confirmation; it refuses to revoke the key currently authenticating the request.list_oauth_clientsandmanage_oauth_clientmanage self-serve public OAuth 2.1 + PKCE developer clients (create and update after confirmation; delete with preview then confirm).list_workspace_memberslists the people in a workspace: members with their role, status, brand access and API access, pending invites, and seats in use (owners and admins also see each member's key count, connected AI apps and last use).manage_workspace_memberinvites, updates, or removes a colleague (action: invite | update | remove);action: updatewithmember_idandapi_access(on its own) turns a teammate's API and AI access on or off. The first call always returns a preview and changes nothing. Both need the "Manage team" permission; see Managing your team.
Brands
list_brandsshows brands/clients in the current workspace context.view: "brand"inspects one brand,view: "accounts"shows the social accounts assigned to it, andview: "profile"reads its saved brand voice/profile, includinglearned_voicefrom each connected account's real published captions.manage_brandcreates or updates a brand (admin only, after confirmation) and archives one (admin only, preview then confirm). Archiving does not disconnect accounts or cancel scheduled posts.
Posts
list_postsandget_postbrowse scheduled content;get_postwithview: "missing"inspects missing content/settings before publish. To check a month, calllist_postswithscheduled_fromandscheduled_to(plain dates like2026-10-01and2026-10-31; the end date includes its whole day) andtimezone(for exampleEurope/London); with a range it lists oldest first, up tolimitposts (default 20, max 200) per call. Every answer says whether all matching posts are shown. If it says more are available, call again with theoffsetit gives until it says complete, before concluding a client is light or a day is empty. For "how many" questions,view: "counts"returns exact totals per day, status, account, and brand for the same filters (range required, up to 366 days).list_activity,list_media,list_post_suggestions,list_comments,list_conversations, andget_updatesalso say when there is more and takeoffset.list_postsstatusaccepts every stored status, includingpublishing,paused,paused_due_to_token, andpaused_due_to_billing. A post that missed its time while publishing was paused stays paused; missed is not its own status. Filterlist_postswithapproval_statusorapproval_waiting_on(clientorteam). Each post includesapproval.pending_client_approval, true only while the overall status ispending_client. Each post also shows when it was created (an ISO 8601 time in UTC) and who created it: the teammate's name and the channel, such as Dashboard, REST API, MCP, or Bulk Upload. Older posts made before the channel was recorded show it as unknown. These return posts in every workspace you belong to, teammates' posts included, per your role there (a brand-locked seat only sees its assigned brands); passworkspace_idto scope to one workspace. A draft any editor skipped in the Content Engine review queue never appears inlist_posts, andget_postreturns a not-found error for one; if it is ever scheduled by some other path, it is reverted to a draft at publish time rather than published. They do not return a recovery-action field. Forstatus=failedor paused-for-reconnect posts, inspect the post andlist_activity, then open it in posterly. The fail/paused banner leads with What to do. Do not republish reconnect, re-upload, or edit-and-retry failures (expired token, missing media, Google Business location not found, invalid YouTube keywords, X URL-cost skip) until the user has done that action. Temporary wait cases, such as Facebook Story/Reel/video ingest, may already be retrying.list_postsandget_postbrowse scheduled content;get_postwithview: "missing"inspects missing content/settings before publish. To check a month, calllist_postswithscheduled_fromandscheduled_to(plain dates like2026-10-01and2026-10-31; the end date includes its whole day) andtimezone(for exampleEurope/London); with a range it lists oldest first, up tolimitposts (default 20, max 200) per call. Every answer says whether all matching posts are shown. If it says more are available, call again with theoffsetit gives until it says complete, before concluding a client is light or a day is empty. For "how many" questions,view: "counts"returns exact totals per day, status, account, and brand for the same filters (range required, up to 366 days).list_activity,list_media,list_post_suggestions,list_comments,list_conversations, andget_updatesalso say when there is more and takeoffset. Filterlist_postswithapproval_statusorapproval_waiting_on(clientorteam). Passgroup_idfor one caller group, orrelease_idfor one release.status=missedlists posts that failed, posts still scheduled after their time, and posts a publishing pause held past their time (the onespublish_missedcan post). The calendar, list, and table have the same Missed filter. Each post includesapproval.pending_client_approval, true only while the overall status ispending_client. Each post also shows when it was created (an ISO 8601 time in UTC) and who created it: the teammate's name and the channel, such as Dashboard, REST API, MCP, or Bulk Upload. Older posts made before the channel was recorded show it as unknown. These return posts in every workspace you belong to, teammates' posts included, per your role there (a brand-locked seat only sees its assigned brands); passworkspace_idto scope to one workspace. A draft any editor skipped in the Content Engine review queue never appears inlist_posts, andget_postreturns a not-found error for one; if it is ever scheduled by some other path, it is reverted to a draft at publish time rather than published. They do not return a recovery-action field. Forstatus=failedor paused-for-reconnect posts, inspect the post andlist_activity, then open it in posterly. The fail/paused banner leads with What to do. Do not republish reconnect, re-upload, or edit-and-retry failures (expired token, missing media, Google Business location not found, invalid YouTube keywords, X URL-cost skip) until the user has done that action. Temporary wait cases, such as Facebook Story/Reel/video ingest, may already be retrying.ask_supportasks authenticated docs-backed support questions with read-only account/post diagnostics. If the user asks for a human, agent, real person, or an escalation, Support AI stops the docs answer and files one ticket for that conversation. A person replies by email to the signed-in account address, not an address in the message. Asking again in that conversation does not open another ticket, and at most three conversations a day are passed on. The same docs answer is not sent again in that conversation, and after two replies that do not settle the topic Support offers a person. Agent-initiated handoff still usesrequest_humanplusconfirm_escalation.create_postschedules or immediately publishes one post. Passthread_posts: string[](2+ entries) for X or Threads chains; whenaccount_idis set,platformis optional because the account already names the network. Passplatform_settingsfor platform-specific composer controls. For media, pass URLs returned by the media upload tools. A successful create can still come back with a non-blockingwarningsentry; the post was created either way. Today the only one is TikTok's pending-inbox cap: a post sent to the TikTok inbox (no direct-postprivacy_level) warns when the account already has around 5 pending shares due to land around the same time, since TikTok only holds about 5 at once. Relay the warning rather than treating the create as failed.validate_postvalidates the complete payload without creating a post, copying remote media, consuming post-item/storage quota, reserving X quota, emitting webhooks, or enqueueing publication. Resolve warnings, show the final preview, and ask for explicit confirmation before callingcreate_post.create_posts_batchcreates up to 25 confirmed posts in one API request. Each item accepts the same fields ascreate_post, and partial failures return the item index. Third-party media URLs are copied into posterly storage before each post is saved. Any item-levelwarnings(same shape ascreate_post) come back alongside that item.update_postedits a scheduled or draft post. It does not move the post onto another account, and it does not edit an X or Threads thread. Withstatusit pauses, resumes, schedules, or drafts it, or withrelease_idrepairs release/group metadata, always after confirmation.approval_action(request,approve,request_changes, orreject) changes client approval. Only a workspace owner or admin may do that, and the actor is the API key user, never a brand guest.requestemails the brand reviewers.approve,request_changes, andrejectare team-side decisions that reuse the same approval state as the client portal.request_changesneedsapproval_note. Optionalapproval_axisisassetorcaption; omit it for both. Passconfirm=trueonly after the user explicitly confirms, including forrequest.delete_postdeletes one post (post_id, after confirmation) or every unpublished post in a group (group_id, preview then confirm). A post that is currently publishing is never deleted. For a published post, explicitly choosedelete_mode: "posterly"to keep live content, ordelete_mode: "platform"withconfirm_published: trueafter confirming live removal. Eligible connected platforms need saved post IDs and deletion permissions; a refusal keeps the record. Threads requiresthreads_delete, which the current connection flow does not request. YouTube upload permission alone is insufficient. Instagram live deletion is disabled: Meta requiresinstagram_manage_contentsthrough Facebook Login and a Facebook user token, which our current deletion integration does not provide. Publishing permissions are insufficient. A group or bulk delete never requests live platform deletion. A published post without a saved platform target can only be removed with the explicit local-only choice; requesting platform deletion keeps the record and returns an error. A group delete never removes published posts. These act on a teammate's post in a shared workspace too, per your role there: editing a draft or deleting one needs Editor, anything already scheduled/paused/failed needs Publisher, and moving the scheduled time always needs Publisher. Published delete still follows that delete role check. A group delete only ever removes posts you created yourself. Updating a client-approved post reopens the changed review axis (caption edits reopen caption approval, media changes reopen asset approval) so it goes back to pending client review.update_postedits a scheduled or draft post, or withstatuspauses, resumes, schedules, or drafts it, or withrelease_idrepairs release/group metadata, always after confirmation.account_idmoves an unpublished post onto another account you can use in the same workspace and on the same brand, and the platform follows that account.thread_postsreplaces an X or Threads reply chain (at least two non-empty parts, and the first becomes the caption). A published post, or a post that is currently publishing, cannot be moved or rewritten.approval_action(request,approve,request_changes, orreject) changes client approval. Only a workspace owner or admin may do that, and the actor is the API key user, never a brand guest.requestemails the brand reviewers.approve,request_changes, andrejectare team-side decisions that reuse the same approval state as the client portal.request_changesneedsapproval_note. Optionalapproval_axisisassetorcaption; omit it for both. Passconfirm=trueonly after the user explicitly confirms, including forrequest.delete_postdeletes one post (post_id, after confirmation) or every unpublished post in a group (group_id, preview then confirm). A post that is currently publishing is never deleted. For a published post, explicitly choosedelete_mode: "posterly"to keep live content, ordelete_mode: "platform"withconfirm_published: trueafter confirming live removal. Eligible connected platforms need saved post IDs and deletion permissions; a refusal keeps the record. Threads requiresthreads_delete, which the current connection flow does not request. YouTube upload permission alone is insufficient. Instagram live deletion is disabled: Meta requiresinstagram_manage_contentsthrough Facebook Login and a Facebook user token, which our current deletion integration does not provide. Publishing permissions are insufficient. A group or bulk delete never requests live platform deletion. A published post without a saved platform target can only be removed with the explicit local-only choice; requesting platform deletion keeps the record and returns an error. A group delete never removes published posts. These act on a teammate's post in a shared workspace too, per your role there: editing a draft or deleting one needs Editor, anything already scheduled/paused/failed needs Publisher, and moving the scheduled time always needs Publisher. Published delete still follows that delete role check. A group delete only ever removes posts you created yourself. Updating a client-approved post reopens the changed review axis (caption edits reopen caption approval, media changes reopen asset approval) so it goes back to pending client review.list_publishing_pausesshows whether publishing is paused for the workspace or any brand you can see, and whether you may pause, resume, or publish missed posts.manage_publishing_pausepauses or resumes a whole workspace or onebrand_id, the same switches as the dashboard's Pause publishing cards. Only act when the user asks; never pause on your own initiative.action: "pause"(publisher or higher; a seat limited to some brands can only pause those brands) first returns a preview with the scope and how many scheduled posts it would hold; show it, then call again withconfirm: trueonce the user agrees.action: "resume"(admin or higher) returns how many posts are back on the schedule and the IDs of posts that missed their time while paused. Missed posts never publish on their own: ask the user, then eitheraction: "publish_missed"with thosepost_idsandconfirm: true, or leave them paused to reschedule. See Pause all publishing for a workspace or a brand.submit_agent_feedbacksubmits bounded private operational telemetry after a concrete workflow outcome. Never include secrets, prompts, captions, media URLs, personal data, or fabricated outcomes.submit_product_feedbackfiles a product bug, idea, or feedback on the public posterly feedback board after the user explicitly approves the title and category (confirm=true); do not use it for tool failures.
Media
upload_mediatakes small base64 files on hosted HTTP (Vercel ~4MB body), a localfile_pathon stdio (large files go through signed upload automatically), or a publicurlthat posterly fetches into storage with SSRF protections (small files; large R2/S3 URLs fail). Passasset_idfromlist_mediato delete that library file. The first call shows the file and deletes nothing. Call again withconfirmand thepreview_idonly after the person agrees. A file a post still uses is kept.create_signed_uploadmints object-storage PUT URLs (1 to 20 files per call) so large files never enter the Vercel body. The client must PUT the bytes.create_media_dropmints a no-loginhttps://www.poster.ly/drop/<token>page so a human can upload laptop files (up to 20 per link). Chat paperclips still never reach MCP.list_medialists newest media assets, or files from one drop session, then passpublic_urltovalidate_post/create_post. Each file includes its filename and the time it was added. There is no delete, and the list follows the key's workspace rather than a workspace filter.find_available_slotfinds the next open posting slot honoring the 1h gap. Each slot includes the UTC instant to pass asscheduled_at. The default zone staysAmerica/New_Yorkwhentimezoneis omitted, so pass the workspace zone. Passstrategy: "best_engagement"withaccount_idsto get the best times in the next 7 days instead, ranked by when those accounts get the most engagement, each with a Rating column (1 to 5 stars, confidence-capped by basis) and a short reason. See Suggested times.
AI generation
generate_captionsgenerates or adapts brand-aware caption suggestions without creating a post. Captions are checked against the brief and the workspace's business facts; unverifiable prices, dates, times, links, phone numbers and handles are removed, as is any never-say phrase set on a fact, so fewer variants than requested may come back.generate_imagequeues an AI image job (Nano Banana or Grok). Gemini quality is model, resolution (1K, 2K, or 4K; 512 is no longer available), and thinking_level (quality=high enables thinking; thinking does not change the credit price). Optional reference_image_urls for logo lock. Polllist_jobswithtype: "image"untilurlsare ready.get_video_optionsandrun_video_functioninspect video models, durations, input modes, and credit estimates, and validate a request, without spending credits.generate_videoqueues a cost-guarded video job after user confirmation; polllist_jobswithtype: "video"untilvideo_urlis ready.get_creditsreads the AI credit balance for the caller's workspace wallet. Read-only, spends nothing.
Analytics
list_analyticswithview: "accounts"returns follower growth, reach, views, engagement rate, and API-provided nativedisplay_metricssuch as Google Business Profile's Profile Views, Search Views, Maps Views, Customer Actions, Calls, Directions, Website clicks, and Posts.view: "posts"returns per-post likes, comments, reach, impressions, saves, shares, and plays. Google Business has location totals onview: "accounts"and no per-post rows, and the posts view says so. Both acceptpresentation: "compact" | "table" | "json"so Telegram can stay bullet-based while Markdown clients or custom renderers can choose tables/structured data. Supported: Instagram, X, Facebook Pages, LinkedIn, Google Business Profile, Pinterest, YouTube, and Threads.list_analyticswithview: "accounts"returns follower growth, reach, views, engagement rate, and API-provided nativedisplay_metricssuch as Google Business Profile's Profile Views, Search Views, Maps Views, Customer Actions, Calls, Directions, Website clicks, and Posts.view: "posts"returns per-post likes, comments, reach, impressions, saves, shares, and plays. Both acceptpresentation: "compact" | "table" | "json"so Telegram can stay bullet-based while Markdown clients or custom renderers can choose tables/structured data. Supported: Instagram, X, Facebook Pages, LinkedIn, Google Business Profile, Pinterest, YouTube, and Threads.include_extras: trueon accounts also asks for saved audience breakdowns, the last analytics sync, and entity snapshots. Those stay off until snapshot extras are switched on, and the call does not start a new sync.list_analyticswithview: "insights"lists per-post feedback-loop insights for recently published posts: the performance tier (great/good/mixed/poor), a diagnosis, a suggested next action, metrics, and the baseline each was compared against. Filter byaccount_id,post_id, andcheckpoint(1h, 6h, 24h, 72h, 7d). Requires a Pro plan or higher.list_post_suggestionslists evidence-based weekly post drafts written in each account's learned voice, each with arationaletying it back to what has performed well. The caption and rationale come back in full, with the account id. Filter byaccount_idandstatus(pending, scheduled, dismissed). Requires a Pro plan or higher.dismiss_suggestiondismisses one after user confirmation and never touches one already turned into a scheduled post; in a team workspace, dismissing requires the Editor role or above. There is no accept action that turns a suggestion into a draft.list_post_suggestionslists evidence-based weekly post drafts written in each account's learned voice, each with arationaletying it back to what has performed well. Filter byaccount_idandstatus(pending, scheduled, dismissed). Requires a Pro plan or higher.dismiss_suggestiondismisses one after user confirmation and never touches one already turned into a scheduled post. Passsave_as_draft: trueto keep that suggestion as an unpublished draft instead: nothing is scheduled and nothing is published. In a team workspace, dismissing or saving a draft requires the Editor role or above.
Social inbox (Pro plan or higher)
list_conversationslists Instagram and Facebook Page inbox DMs (Threads has no DMs, soplatformis onlyinstagramorfacebook); passconversation_idfor one conversation and its messages. Addsinceand/oruntil(an ISO date or datetime, inclusive) to list only conversations whose last message falls in that range. Each row shows when the last message arrived (in UTC on the hosted endpoint, in your local time in the npm package), the account and workspace,you:when you sent the last DM, and[media]or[unsupported]when the last message had no text.manage_conversationwithaction: "send"sends a DM reply with preview then confirm and honors Meta 24-hour messaging windows;action: "sync"pulls the latest inbox data for one Instagram, Facebook, Threads, or LinkedIn account, with a 30-second cooldown (60 seconds for LinkedIn). Threads and LinkedIn are comments-only.list_commentslists Instagram, Facebook Page, Threads, and LinkedIn Page inbox comments; passcomment_idfor one comment and its replies. When the inbox stored them, the row includes the account id and the parent post caption and link. A comment has no posterly post id. Addsinceand/oruntil(an ISO date or datetime, inclusive) to list only comments posted in that range. Each row shows when it was posted (in UTC on the hosted endpoint, in your local time in the npm package), the account and workspace, andyoufor the business's own comments.manage_commentwithaction: "reply"replies with preview then confirm (Facebook has no private comment replies; Threads and LinkedIn are public-only).action: "update"hides/unhides a comment or marks it read; hide is reversible and does not delete, and LinkedIn comments cannot be hidden.action: "delete"deletes an Instagram or Facebook Page comment with preview then confirm; it is irreversible and admin only. Threads replies cannot be deleted (hide them instead), and LinkedIn comments cannot be deleted.list_conversationslists Instagram and Facebook Page inbox DMs (Threads has no DMs); passconversation_idfor one conversation and its messages. Addsinceand/oruntil(an ISO date or datetime, inclusive) to list only conversations whose last message falls in that range. Each row shows when the last message arrived (ISO 8601 UTC, such as2026-10-21T15:09:05Z, on both the hosted endpoint and the npm package), the account and workspace,you:when you sent the last DM, and[media]or[unsupported]when the last message had no text.manage_conversationwithaction: "send"sends a DM reply with preview then confirm and honors Meta 24-hour messaging windows;action: "sync"pulls the latest inbox data for one Instagram, Facebook, Threads, or LinkedIn account, with a 30-second cooldown (60 seconds for LinkedIn). Threads and LinkedIn are comments-only.- A single post, a review, a comment, and a conversation show their time in UTC, as
2026-10-16T06:00:00Z. A post list still uses thetimezoneyou pass, and a free slot's local label stays in that zone. list_commentslists Instagram, Facebook Page, Threads, and LinkedIn Page inbox comments; passcomment_idfor one comment and its replies. Addsinceand/oruntil(an ISO date or datetime, inclusive) to list only comments posted in that range. Each row shows when it was posted (ISO 8601 UTC, such as2026-10-21T15:09:05Z, on both the hosted endpoint and the npm package), the account and workspace, andyoufor the business's own comments.manage_commentwithaction: "reply"replies with preview then confirm (Facebook has no private comment replies; Threads and LinkedIn are public-only).action: "update"hides/unhides a comment or marks it read; hide is reversible and does not delete, and LinkedIn comments cannot be hidden.action: "delete"deletes an Instagram or Facebook Page comment with preview then confirm; it is irreversible and admin only. Threads replies cannot be deleted (hide them instead), and LinkedIn comments cannot be deleted.list_conversationslists Instagram and Facebook Page inbox DMs (Threads has no DMs); passconversation_idfor one conversation and its messages. Addsinceand/oruntil(an ISO date or datetime, inclusive) to list only conversations whose last message falls in that range. Each row shows when the last message arrived (in UTC on the hosted endpoint, in your local time in the npm package), the account and workspace,you:when you sent the last DM, and[media]or[unsupported]when the last message had no text. Once an inbox sync has stored it, the row also says whether the 24-hour reply window is still open, and until when, in UTC. That time comes from the customer's last message. A reply does not extend it, and it is not guessed from the messages loaded in the thread.manage_conversationwithaction: "send"sends a DM reply with preview then confirm and refuses a send after that window has closed;action: "sync"pulls the latest inbox data for one Instagram, Facebook, Threads, or LinkedIn account, with a 30-second cooldown (60 seconds for LinkedIn). Threads and LinkedIn are comments-only.list_commentslists Instagram, Facebook Page, Threads, and LinkedIn Page inbox comments; passcomment_idfor one comment and its replies. Addsinceand/oruntil(an ISO date or datetime, inclusive) to list only comments posted in that range. Each row shows when it was posted (in UTC on the hosted endpoint, in your local time in the npm package), the account and workspace, andyoufor the business's own comments.manage_commentwithaction: "reply"replies with preview then confirm (Facebook has no private comment replies; Threads and LinkedIn are public-only).action: "update"hides/unhides a comment or marks it read; hide is reversible and does not delete, and LinkedIn comments cannot be hidden.action: "delete"deletes an Instagram or Facebook Page comment with preview then confirm; it is irreversible and admin only. Threads replies cannot be deleted (hide them instead), and LinkedIn comments cannot be deleted.
Every inbox tool takes an optional
workspace_id. Pass one fromwhoami(or use a key/token bound to a workspace) to scope a call to exactly that workspace, gated on that workspace's owner's plan, matching the dashboard. Omit it onlist_conversations,list_comments,manage_comment, ormanage_conversationwithaction: "send"and the tool searches every workspace you belong to, returning matches from the ones where your role and the workspace owner's plan both qualify; the list calls note any skipped workspaces (and why) instead of returning a silent empty result.manage_conversationwithaction: "sync"is different: it always acts on the connected account's own workspace, so an omittedworkspace_idthere does not search anything, it just skips requiring a specific workspace.
Google Business Profile
list_google_business_reviewslists reviews for one location or every accessible location. It returns every review Google holds (it pages past Google's own 50-per-page cap), with the full untruncated review text and its date. Filter byratingandunanswered, and page withlimit(default 200, max 1000) andoffset;has_moretells you when more remain. Each location also reports itstotal_review_countandaverage_ratingfrom Google, plus anerrorfield, so a location with no reviews is distinguishable from one that failed to sync. Every review includesreview_name(accounts/{account}/locations/{location}/reviews/{review}) plusaccount_idandlocation_idwhen they are known. Pass thatreview_namewithaccount_id(orlocation_id) tomanage_google_business_reviewreplyordelete_reply. Do not invent a review name, and do not pass the Place ID fromview: "review_link".view: "review_link"returns the public review request link.audit_google_business_profileruns a local-profile audit. The text result includes the 0 to 100 score, the letter grade (Afrom 90,Bfrom 80,Cfrom 70,Dfrom 60, otherwiseF), one line per section, then the top recommendations. A section short of full marks includes at least one recommendation. Sections and maximum points: Profile basics 20, Hours 15, Categories 15, Description 10, Photos 15, Attributes 5, Review health 20. Those points are the score. Recent posts are not scored. Name, address, and phone sit inside Profile basics. The audit does not compare them with the website. The dashboard auditor can show a different number for the same location.audit_google_business_profileruns a local-profile audit. The text result includes the 0 to 100 score, the letter grade (Afrom 90,Bfrom 80,Cfrom 70,Dfrom 60, otherwiseF), one line per section, then the top recommendations. Sections and maximum points: Profile basics 20, Hours 15, Categories 15, Description 10, Photos 15, Attributes 5, Review health 20. Those points are the score. Service areas are a penalty on that 100, not extra points: a shop with no service area is unchanged, and a service listing that is otherwise perfect drops to 85 (a B) when areas are missing or any area is more than 80 miles from the business in a straight line. Recent posts are not scored. Name, address, and phone sit inside Profile basics. The audit does not compare them with the website. The dashboard auditor can show a different number for the same location.list_google_business_service_areasreads the towns and postcodes on a location (view: "areas") or searches for one to add (view: "places",qrequired).manage_google_business_service_areawithaction: "update"replaces the list (1 to 20 places) with preview then confirm; the preview shows the current areas next to the new list. An editor or above is required. Customer-only listings that still show a street address needclear_storefront_address: true, which deletes the address from the listing rather than hiding it.manage_google_business_reviewwithaction: "suggest_reply"generates brand-aware reply options and never posts.action: "reply"andaction: "delete_reply"manage the public owner reply with preview then confirm.list_google_business_medialists the photos and videos on a profile gallery (the media shown on Maps and Search).manage_google_business_mediaadds one from a public URL (action: "add") or removes one (action: "delete"), both with preview then confirm. Photos must be JPG or PNG between 10 KB and 5 MB.list_google_business_locationsreads regular opening hours and attributes for one location.manage_google_business_locationreplaces regular hours (update_hours) or a named set of attributes (update_attributes), both with preview then confirm. Both stay off until location edits are switched on (GBP_LOCATION_WRITES_ENABLED). A confirm while that is off changes nothing and does not call Google. This uses the same business management connection as posting and does not change the business name, address, phone, or website.
Google Business tip: pass
account_id(the integeridfromlist_accounts) to every Google Business tool.list_accountsprintslocation_idon Google Business rows, andaccount_typewhen the account has one (for example a LinkedIn profile or organisation page). If you uselocation_idinstead ofaccount_id, it is that numeric location id, not theChIJ...Place ID thatlist_google_business_reviewswithview: "review_link"returns. Passing the Place ID resolves to no account and returns "Google Business Profile account not found". Google Business tip: passaccount_id(the integeridfromlist_accounts) to every Google Business tool. If you uselocation_idinstead, it is the numericlocation_idfromlist_accounts(the GBP location id), not theplace_id(ChIJ...) that the review link view returns asreview_linkandplace_id. Passing the Place ID resolves to no account and returns "Google Business Profile account not found". A review list includes the owner reply text when one exists. A reply or delete-reply preview repeats the reviewer, the star rating, the review text, and the current reply. Profile photos include the image URL, and the gallery pages in sets of 50.
Activity, updates, and webhooks
list_activityreads the agent notifications feed of post activity, publish attempts, failures, and retries.get_updatesgets the latest posterly product updates and news from the updates feed. Requires an active posterly subscription.posterly_statuschecks posterly's own publishing health: the overall state from the last 4 hours of publishing success, any active incident (for example X being unavailable), and per-platform state with 7-day success rate and publish counts. Call it before a time-critical post, or when someone asks whether posterly or a platform is down. It is read-only, takes no arguments and returns aggregates only (no post or user data). When fewer than 10 posts were counted in the last 4 hours and no incident is active, the state isunknown(not enough recent activity to judge), which is not an outage and not a green light. Failures caused by content or account problems, such as an expired connection or a content limit, are excluded from the rates and shown separately as customer-side failures. It is notwhoamiwithview: "status", which only reports the MCP server and npm package version. Needs an API key with theaccounts:readscope; the same data is behindGET /api/v1/status(API reference).list_webhooksinspects webhook subscriptions and, withdeliveries, recent delivery attempts. Delivery history stays off unlessENABLE_API_WEBHOOK_DELIVERY_HISTORYis true, and it never returns the signing secret or the request body.create_webhookcreates a signed subscription after explicit confirmation and returns the signing secret once.manage_webhookupdates one (action: "update") or sends a signed test delivery (action: "test") after explicit confirmation, or deletes one with preview then confirm (action: "delete").list_webhooksinspects webhook subscriptions and delivery status.create_webhookcreates a signed subscription after explicit confirmation and returns the signing secret once.manage_webhookupdates one (action: "update") or sends a signed test delivery (action: "test") after explicit confirmation, or deletes one with preview then confirm (action: "delete"). Subscriptions can includeaccount.needs_reconnectandaccount.reconnected: one delivery when a connected account starts needing a reconnect, and one when it is healthy again. The payload matchesconnection_statusfromlist_accounts(account id, platform, brand, reason, time) and does not include tokens or the provider's error text.get_x_posting_quotainspects workspace X posting allowance and URL-block status.
Billing
-
get_subscriptionreads the user's posterly subscription status, tier, cancel/pause state, period end, and connected accounts in use against the limit. It is also the first call for "upgrade my plan", "change plan", "add accounts" and "how many accounts": it lists the plans above the user's with real prices, account limits and included credits, and the next steps for the user's status. For an owner on an active or trialing plan it namesupgrade_subscriptionas the way to move up; it namesresume_subscriptionfor a paused plan and the billing page for a past due, canceled or cancel-pending plan. For an Agency workspace owner it also shows the extra connected-account state (included, paid, in use, the limit, the price of $0.50 per extra account per month or $4.70 per year, the 20-account minimum, and any payment waiting on the card) and the exactmanage_extra_accountcall to make. A teammate sees the numbers and is told only the owner can change them. Requires thebilling:readscope. Claude, ChatGPT, Cursor, Slack, the posterly CLI, and the other connectors posterly lists include that permission on the next consent screen. A connection you already approved keeps its old permissions until you reconnect. Nothing signs you out on its own. Reconnect from the assistant's connector settings when you want it to read your plan. An OAuth app that registered itself cannot get this permission; use an API key with Read billing instead. -
cancel_subscriptioncancels after explicit confirmation. The agent must ask the user for a cancellationreasonfirst (a fixed catalog value) and passconfirm: true;immediatedefaults to cancel-at-period-end. Requires thebilling:writescope. -
pause_subscriptionpauses for 30 days (one pause per 90-day cooldown) afterconfirm: true.resume_subscriptionresumes a paused subscription.downgrade_subscriptionmoves down one tier (or to an explicit lowertier) afterconfirm: true: the lower limits and credits apply right away, the lower price starts at the next renewal, and the rest of the current period is not refunded. All require thebilling:writescope. -
upgrade_subscriptionwith atiermoves the plan to a strictly higher one (never down; usedowngrade_subscriptionfor that), for the workspace owner. Call it withoutconfirmto get the exact quote (what is charged today, the new recurring cost and interval, and the new account limit and credits) and apreview_id; if the change cannot be made you get the reason and nopreview_id. The saved card is charged the quoted amount only after the user agrees and you call again withconfirm: true, thatpreview_id, and theexpected_current_tierandexpected_intervalvalues the preview lists, so a quote that went stale is refused rather than charged. If the card needs 3D Secure or is declined, nothing changes and you get a payment link for the owner; the plan changes automatically once it is paid. A trial keeps its trial: the price changes and nothing is charged today. The plan keeps its billing interval; Agency is monthly or yearly only, so from a weekly plan passintervalasmonthoryear(any other interval change is a billing page change). If the subscription includes the API & MCP add-on, carries a discount other than a permanent percent-off below 100, or there is no card subscription on posterly, the tool says so and points to the billing page. If a standalone add-on would stop working on the new plan (for example Agency needs the Agency add-on), it points to the API page instead. Requires thebilling:writescope. -
manage_extra_accountwithaction: "set"andextra_accounts(the desired total, read the current total fromget_subscription) buys, raises, lowers, or removes extra accounts for the workspace owner, on the same rules as Billing in the dashboard: every increase adds at least 20, there is no maximum, and you cannot go below the accounts connected in any workspace you own. Call it withoutconfirmto get the exact quote (charge today and new recurring cost) and apreview_id; if the change cannot be made you get the reason and nopreview_id. The saved card is charged only after the user agrees and you call again withconfirm: true, thatpreview_id, and theexpected_current_extra_accountsandexpected_intervalvalues the preview lists, so a quote that went stale is refused rather than charged. If the card needs 3D Secure or is declined, nothing is added and you get a payment link for the owner; the accounts apply automatically once it is paid. Requires thebilling:writescope.
Subscription management runs on the same API key but does not require the paid API add-on, so a paused or cancel-pending user can still resume or manage their plan. The destructive actions (
cancel_subscription,pause_subscription,downgrade_subscription) requireconfirm: trueafter explicit user confirmation, andcancel_subscriptionalso requires areason. Reactivating a pending cancellation, restarting a lapsed plan, and retention offers stay in the dashboard.
Managing your team
With a key that has the Manage team permission (tick it when you create the key in /dashboard/api), list_workspace_members shows who is in a workspace and manage_workspace_member invites, updates, or removes a colleague. You must be an owner or admin of the workspace to make changes. In ChatGPT, Claude, and other clients connected with OAuth, both tools work without a key, but only when you are an owner or admin of the workspace (listing included); existing connections do not need to reconnect.
Owners and admins can also turn on API and AI access for a teammate (manage_workspace_member, action: update, member_id, api_access: true). That teammate can then connect their own ChatGPT, Claude or other AI app, or use their own keys, in your workspace with their usual role and brand limits, billed to your workspace plan. Viewers get read-only access: AI generation and media upload tools answer with a permissions error for them. It is off by default, nobody can change their own, and turning it off stops their connections in your workspace on the next call. A teammate whose only API access comes from one workspace gets a connection bound to it; whoami shows api_access and api_access_source for each workspace. Details: Teammates and API access.
Every change is previewed first. The agent's first call changes nothing and returns a summary to show you; it only acts when you approve and it calls again with confirm: true and the preview_id. In this version admin seats are dashboard-only, invites are always sent by email (never an instant add), the email names the person who sent it by name and email address, and the workspace owner is emailed about every change, whether it came from a key or an OAuth connection. Full rules and limits: Team management.
Usage examples
In Claude, ChatGPT, or any MCP client:
- "Schedule a LinkedIn post about our Q1 results for tomorrow at 10am"
- "What accounts do I have connected to posterly?"
- "Disconnect the old Instagram account after I confirm the exact account ID"
- "Pause post 971 after I confirm it is the right scheduled post"
- "Upload this image and create an Instagram post with it"
- "Schedule this as an Instagram Reel, add @partner as a collaborator, and use this image as the Reel cover"
- "Schedule this YouTube video as unlisted, add these tags, and put it in our launch playlist"
- "Post this TikTok with comments on, duet off, stitch off, and public privacy"
- "Turn this Google Business update into an event post with a Learn more CTA"
- "How did my Instagram perform over the last 14 days?"
- "Which of my recent LinkedIn posts got the most engagement?"
- "Post this 5-tweet thread on my X account at 3pm tomorrow" (uses
thread_postsfor X / Threads chains)
platform_settings covers the same scheduling controls exposed by the composer: Instagram feed/story/reel/carousel options plus parent-container is_ai_generated, licensed Reel audio_id, and caption add-ons (a poll or a comment prompt; needs a Meta (Facebook Login) connection for that Instagram account in this workspace, so Instagram Login-only accounts cannot use them; not Stories), Facebook stories/reels/backgrounds, YouTube thumbnails/privacy plus notify_subscribers, add_shorts_hashtag, and optional brand_partner, LinkedIn document, mention, poll, and content_call_to_action_label settings (including BUY_NOW and SHOP_NOW), TikTok video and photo slideshow controls (including video_cover_timestamp_ms to pick the cover frame on direct-post videos), Pinterest board/link/title/product_tags plus a required stored JPEG/PNG cover_image_url for video Pins (20 MiB maximum; registered upload, not a public video_url fetch), Google Business event/offer/CTA/recurrence fields, X polls, reply settings (incl. subscribers/verified), paid_partnership, and Articles (article: { title, cover }, with the caption as the Markdown body; needs an X Premium account), Threads reply controls, polls, topic tags, text attachments, ghost posts, spoilers, reply approvals, GIPHY, and share_to_instagram, Telegram polls, inline CTA buttons, video cover, and live photo, Slack markdown/blocks, Mastodon visibility/quote/poll (media plus poll allowed on 4.6+; text, media, and alt-text limits follow the instance; ambiguous final creates stop automatic retries), Dev.to title, tags, canonical URL, and images (the cover and any extra photos are uploaded to Dev.to, up to 25 MB each, with extra photos placed in the article using their descriptions; Dev.to allows 10 image uploads an hour by default, and a cover or extra photo that cannot be uploaded keeps its original image address, with a warning shown on the post), and Bluesky language, alt-text, content warnings, hidden tags, quote posts, and disable-quotes settings. Pass ai_generated: true to label a post as AI-generated on TikTok, X, YouTube, Pinterest, and Instagram.
An Instagram Story or Story Series can include an optional caption, with the same 2,200 character limit and up to 30 hashtags as a feed post. A Story Series sends the caption with the first slide only. Leave it empty for a media-only Story. A Facebook Story does not take a caption. Polls and comment prompts are still not available on Stories.
For media descriptions, prefer media_accessibility: [{ index, asset_id?, source_url?, alt_text }]. The legacy media_alt_texts URL map remains accepted. The ordered format keeps alt text with the original media item through carousel reordering and platform-specific image preparation. Updates merge entries by index and preserve omitted descriptions. An empty string clears that occurrence, while an empty array (or empty legacy map) clears all descriptions. Stable entries take precedence when both forms are supplied.
For TikTok you do not need to set a post type for images. posterly auto-detects image media and schedules it as a photo slideshow of 1 to 35 images (sending every image), so "Schedule these 5 photos as a TikTok" just works. A single video schedules as a standard TikTok video. On that video, the post text is the TikTok caption. A title in platform settings is placed on the first line when it and the caption both fit in 2,200 characters. Photo slideshows keep that title separate from the caption.
See the MCP marketing page for client-specific setup screenshots.
Claude Code plugin alternative
If you use Claude Code, you can install the official posterly plugin instead of editing MCP config by hand. The plugin bundles this MCP server plus the agent skill and a guided /posterly:setup flow.
/plugin marketplace add awpthorp/posterly-agent
/plugin install posterly@posterly-agent
Full steps: Claude Code plugin.