Postproxy
About
Publish to multiple social networks with only one MCP
Details
- Author
- postproxy
- Categories
- Communication, Other, Productivity
Jump to
Setup
Install Postproxy in your MCP client (Claude Desktop, Cursor, Windsurf, and others).
Repository: https://github.com/postproxy/postproxy-mcp
Follow the installation instructions in the repository README, then restart your MCP client.
MCP (Model Context Protocol) server for integratingPostproxyAPI with Claude Code. This server provides tools for publishing posts, checking statuses, and managing social media profiles through Claude Code.
Claude Code stores MCP server configuration under~/.claude/plugins/. After installing postproxy-mcp, Claude will automatically detect the server on restart.
After installing postproxy-mcp, register it with Claude Code using theclaude mcp addcommand:
claude mcp add --transport stdio postproxy-mcp --env POSTPROXY_API_KEY=your-api-key --env POSTPROXY_BASE_URL=https://api.postproxy.dev/api -- postproxy-mcp
Replaceyour-api-keywith your actual Postproxy API key.
The configuration will be automatically saved to~/.claude/plugins/. After running this command:
- Restart your Claude Code session
- Test the connection by asking Claude: "Check my Postproxy authentication status"
- If tools are available, Claude will be able to use them automatically
For non-technical users, you can use the interactive setup command:
This will guide you through the setup process step by step and register the server usingclaude mcp addautomatically.
Check authentication status, API configuration, and workspace information.
{ "authenticated": true, "base_url": "https://api.postproxy.dev/api", "profile_groups_count": 2 }
Answer "what's the status?" in one call — an activity snapshot for a time window instead of separatehistory_list/comments_list/dm_chats_listround trips.
- window(string, optional):24h(default),7d, or30d
- from(string, optional): ISO 8601 timestamp or bare date starting an explicit range. Overrideswindow, and the*_previouscounts come backnull
- to(string, optional): End of the explicit range. Defaults to now when onlyfromis given
- profile_group_id(string, optional): Report on a single group. Omit to cover every group the key can reach
{ "window": { "label": "24h", "from": "2026-08-17T09:00:00Z", "to": "2026-08-18T09:00:00Z", "previous_from": "2026-08-16T09:00:00Z", "backlog_from": "2026-07-19T09:00:00Z" }, "posts": { "published": 4, "published_previous": 3, "failed": 1, "scheduled_ahead": 6, "next_scheduled_at": "2026-08-18T14:00:00Z", "by_platform": { "instagram": { "published": 4, "failed": 0 } } }, "engagement": { "total": { "impressions": 48210, "likes": 1204 }, "by_platform": { "instagram": { "impressions": 31002, "likes": 900 } }, "posts_with_insights": 14 }, "comments": { "received": 96, "received_previous": 71, "awaiting_reply": 12, "by_platform": { "instagram": 61 } }, "reviews": { "received": 7, "received_previous": 4, "awaiting_reply": 3 }, "dms": { "inbound": 41, "outbound": 33, "chats_awaiting_reply": 5, "reply_window_closing": 2 }, "api": { "calls": 812, "calls_previous": 640 } }
- Post counts are posts, so a post sent to three networks counts once and a thread counts once.by_platformcounts per-network deliveries, so a 3-item X thread is 3 undertwitter.
- engagementis lifetime-to-date for posts published in the window, not engagement earned during it — it sums each post's newest stats snapshot. A post published minutes ago may have no snapshot yet and won't be inposts_with_insights. Keys are the normalized metrics listed inStats Fields by Platform.
- Theawaiting_replycounts describe current state, not the window — they don't change when you changewindow. They look back 30 days, returned aswindow.backlog_from. A comment counts as replied only when the reply came from you (via Postproxy or the profile itself);chats_awaiting_replyis derived from message timestamps, since Postproxy has no read/unread state.
- reply_window_closingcounts chats with under 6 hours of their 24h messaging window left. Networks without a window (Telegram, Bluesky) are excluded.
- engagementisnullwhen insights are off for the account;dmsisnullwhen DMs are off.
- Scoped like every other tool: a group-scoped key reports only its group.
List all profile groups accessible with your API key. Profile groups are organizational containers (e.g. per brand or client) that hold related profiles. Use a group'sidto filterprofiles_listbyprofile_group_id.
{ "profile_groups": [ { "id": "grp123abc", "name": "Main Brand", "profiles_count": 4 } ] }
List all available social media profiles for posting.
- profile_group_id(string, optional): If provided, only profiles in this group are returned (useprofile_groups_listto find group IDs)
{ "profiles": [ { "id": "profile-123", "name": "My Twitter Account", "platform": "twitter", "profile_group_id": "group-abc" } ] }
List available placements for a profile. For Facebook profiles, placements are business pages. For LinkedIn profiles, placements include the personal profile and organizations. For Pinterest profiles, placements are boards. For Telegram profiles, placements are channels the bot can post to. Available forfacebook,linkedin,pinterest, andtelegramprofiles.
- profile_id(string, required): Profile hashid
{ "placements": [ { "id": null, "name": "Personal Profile" }, { "id": "108520199", "name": "Acme Marketing" } ] }
- If no placement is specified when creating a post:
- LinkedIn: defaults to the personal profile
- Facebook: defaults to a random connected page (if only one page is connected, no need to set a placement ID)
- Pinterest: it fails
- Telegram: it fails —chat_idis required on every post
Get the follower/engagement timeseries for a profile. Snapshots are captured roughly every 23 hours, so you can plot follower growth and other trends over time. Thestatsfields are platform-native (not normalized) — seeStats Fields by Platformin thepost_statssection for shape and add-on profile-level keys (followers_count,followersCount, etc.) per network.
- profile_id(string, required): Profile hashid
- placement_id(string, conditional):Requiredforfacebook,linkedin, andtelegramprofiles. Get it fromprofiles_placements. Omit forinstagram,threads,youtube,twitter,tiktok,pinterest, andbluesky.
- from(string, optional): ISO 8601 timestamp — only include snapshots recorded at or after this time
- to(string, optional): ISO 8601 timestamp — only include snapshots recorded at or before this time
{ "data": { "profile_id": "prof_li_001", "platform": "linkedin", "placement_id": "108520199", "records": [ { "stats": { "followerCount": 4500, "shareCount": 8, "likeCount": 80 }, "recorded_at": "2026-05-09T08:00:00Z" }, { "stats": { "followerCount": 4520, "shareCount": 9, "likeCount": 90 }, "recorded_at": "2026-05-10T08:00:00Z" } ] } }
For non-placement networks (e.g. Bluesky), omitplacement_id:
{ "data": { "profile_id": "prof_bsky_001", "platform": "bluesky", "placement_id": null, "records": [ { "stats": { "followersCount": 8800, "postsCount": 40 }, "recorded_at": "2026-05-09T08:00:00Z" } ] } }
Publish a post to specified social media profiles.
-
content(string, required): Post content text
profiles(string[], required): Array of profile IDs (hashids) or platform names (e.g.,"linkedin","instagram","twitter"). When using platform names, posts to the first connected profile for that platform.
schedule(string, optional): ISO 8601 scheduled time
media(string[], optional): Array of media URLs or local file paths
idempotency_key(string, optional): Idempotency key for deduplication
require_confirmation(boolean, optional): If true, return summary without publishing
draft(boolean, optional): If true, creates a draft post that won't publish automatically
queue_id(string, optional): Queue ID to add the post to. The queue will automatically assign a timeslot. Do not use together withschedule.
queue_priority(string, optional): Priority when adding to a queue:high,medium(default), orlow
platforms(object, optional): Platform-specific parameters. Key is platform name (e.g., "instagram", "youtube", "tiktok"), value is object with platform-specific options. SeePlatform Parameters Referencefor full documentation.
{ "instagram": { "format": "reel", "collaborators": ["username1", "username2"], "first_comment": "Link in bio!" }, "youtube": { "title": "My Video Title", "privacy_status": "public" }, "tiktok": { "privacy_status": "PUBLIC_TO_EVERYONE", "auto_add_music": true } }
{ "post_id": "job-123", "accepted_at": "2024-01-01T12:00:00Z", "status": "pending", "draft": true }
Note on draft posts: If you request a draft post (draft: true) but the API returnsdraft: false, awarningfield will be included in the response indicating that the API may have ignored the draft parameter. This can happen if the API does not support drafts with certain parameters (e.g., media attachments) or under specific conditions. Check thewarningfield in the response for details.
Get status of a published post by job ID.
- post_id(string, required): Post ID from post.publish response
{ "post_id": "job-123", "overall_status": "complete", "draft": false, "status": "processed", "content": "Full post body as submitted...", "scheduled_at": "2024-01-02T09:00:00Z", "created_at": "2024-01-01T12:00:00Z", "source": "postproxy", "queue_id": null, "platforms": [ { "platform": "twitter", "status": "published", "url": "https://twitter.com/status/123", "post_id": "123", "error": null, "attempted_at": "2024-01-01T12:00:00Z" } ] }
scheduled_atisnullfor posts published immediately. Platformurlis the published permalink (null until published).
- overall_status:"draft","pending","processing","complete","failed"
- Platformstatus:"pending","processing","published","failed","deleted"
- Platformerror: Error message if publishing failed (null if successful)
Publish a draft post. Only posts withdraft: truestatus can be published using this endpoint.
- post_id(string, required): Post ID of the draft post to publish
{ "post_id": "job-123", "status": "processed", "draft": false, "scheduled_at": null, "created_at": "2024-01-01T12:00:00Z", "message": "Draft post published successfully" }
- post_id(string, required): Post ID to delete
{ "post_id": "job-123", "deleted": true }
Get stats snapshots for one or more posts. Returns all matching snapshots so you can see trends over time. Supports filtering by profiles/networks and timespan.
- post_ids(string[], required): Array of post hashids (max 50)
- profiles(string, optional): Comma-separated list of profile hashids or network names (e.g.instagram,twitterorabc123,def456or mixed)
- from(string, optional): ISO 8601 timestamp — only include snapshots recorded at or after this time
- to(string, optional): ISO 8601 timestamp — only include snapshots recorded at or before this time
{ "data": { "abc123": { "platforms": [ { "profile_id": "prof_abc", "platform": "instagram", "records": [ { "stats": { "impressions": 1200, "likes": 85, "comments": 12, "saved": 8 }, "recorded_at": "2026-02-20T12:00:00Z" } ] } ] } } }
Notes: Instagram stories do not return stats. TikTok stats require the post to have a public ID.
List all posting queues. Queues automatically schedule posts into recurring weekly timeslots with priority-based ordering.
- profile_group_id(string, optional): Filter queues by profile group
{ "queues": [ { "id": "q1abc", "name": "Morning Posts", "description": "Daily morning content", "timezone": "America/New_York", "enabled": true, "jitter": 10, "profile_group_id": "pg123", "timeslots": ["Monday at 09:00 (id: 1)", "Wednesday at 09:00 (id: 2)"], "posts_count": 5 } ] }
Get details of a single posting queue including its timeslots and post count.
Create a new posting queue with weekly timeslots.
- profile_group_id(string, required): Profile group ID to connect the queue to (useprofiles_listto find this)
- name(string, required): Queue name
- description(string, optional): Optional description
- timezone(string, optional): IANA timezone name (e.g.America/New_York). Default:UTC
- jitter(number, optional): Random offset in minutes (0–60) applied to scheduled times for natural posting patterns. Default:0
- timeslots(array, optional): Initial weekly timeslots. Each object hasday(0=Sunday through 6=Saturday) andtime(24-hourHH:MMformat)
{ "profile_group_id": "pg123", "name": "Weekday Mornings", "timezone": "America/New_York", "jitter": 10, "timeslots": [ { "day": 1, "time": "09:00" }, { "day": 2, "time": "09:00" }, { "day": 3, "time": "09:00" }, { "day": 4, "time": "09:00" }, { "day": 5, "time": "09:00" } ] }
Update a queue's settings, timeslots, or pause/unpause it. Changes to timezone or timeslots trigger rearrangement of all queued posts.
- queue_id(string, required): Queue ID to update
- name(string, optional): New queue name
- description(string, optional): New description
- timezone(string, optional): IANA timezone name
- enabled(boolean, optional): Set tofalseto pause the queue,trueto unpause
- jitter(number, optional): Random offset in minutes (0–60)
- timeslots(array, optional): Timeslots to add or remove. To add:{ "day": 1, "time": "09:00" }. To remove:{ "id": 42, "_destroy": true }.
Delete a posting queue. Posts in the queue will have their queue reference removed but will not be deleted.
- queue_id(string, required): Queue ID to delete
Get the next available timeslot for a queue.
{ "next_slot": "2026-03-11T14:00:00Z" }
When publishing a post withpost_publish, you can add it to a queue instead of scheduling it manually:
- queue_id(string, optional): Queue ID to add the post to. The queue will automatically assign a timeslot. Do not use together withschedule.
- queue_priority(string, optional): Priority level:high,medium(default), orlow. Higher priority posts get earlier timeslots.
{ "content": "Queued post content", "profiles": ["twitter", "linkedin"], "queue_id": "q1abc", "queue_priority": "high" }
List comments on a published post. Returns paginated top-level comments with nested replies.
- post_id(string, required): Post ID
- profile_id(string, required): Profile ID to identify which platform's comments to retrieve
- page(number, optional): Page number, zero-indexed (default: 0)
- per_page(number, optional): Number of top-level comments per page (default: 20)
- from(string, optional): ISO 8601 date/time — only comments received at or after this point
- to(string, optional): ISO 8601 date/time — only comments received at or before this point
from/tofilter on when Postproxy received the comment, not the platform'sposted_at(which isn't always populated). A bare date such as2026-03-25means that date's start of day. The filter applies to top-level comments only — a comment in range still returns its fullrepliesarray.
{ "total": 42, "page": 0, "per_page": 20, "data": [ { "id": "cmt_abc123", "external_id": "17858893269123456", "body": "Great post!", "status": "synced", "author_username": "someuser", "like_count": 3, "is_hidden": false, "posted_at": "2026-03-25T10:00:00.000Z", "replies": [ { "id": "cmt_def456", "body": "Thanks!", "author_username": "author", "parent_external_id": "17858893269123456" } ] } ] }
Comment objects may also include anattachmentsarray (media on the comment —image,video,audio,gif,external,file), each withid,type,url,status, andexternal_id. Populated for Facebook, Threads, and Bluesky; Instagram, YouTube, and LinkedIn comments are text-only. The array is empty when there is no media.
- post_id(string, required): Post ID
- comment_id(string, required): Comment ID (Postproxy ID or platform external ID)
- profile_id(string, required): Profile ID
Sign in to leave a review
Use Google, GitHub, or an email account so ratings stay tied to real people.
No reviews posted yet.





