xpost

Schedule posts to 9 social networks from Claude, ChatGPT or Cursor.

Community: Submitted by a user or imported; check the owner before granting accessOnlineNo sign-inGlobalFreeCan modify data

What it can do

  • Get Project: The project's settings, read before writing: `timezone` (the clock every bare time is on), `queue` (its posting schedule and next free slots — `scheduled_at: "next_slot"` takes one), `app
  • List Accounts: The connected accounts and what each will publish. `ref` ("x:someone") is what create_post `accounts` takes. `limits` carries `caption_chars_available` (room for words once the signatur
  • Get Posting Rules: Every `platform_configurations` key each account accepts, with kind, accepted values, ceilings and placement gates — the catalog to read before setting anything beyond a caption. A

What data it sees

Do you need an account

No: the server works without sign-in

Schedule posts to 9 social networks from Claude, ChatGPT or Cursor.

How to connect

How to connect xpost to Claude

The server address to paste into Claude settings:

https://xpost--xpost-to.run.tools

  1. Open Claude (claude.ai or the desktop app).
  2. Go to Settings → Connectors.
  3. Click Add custom connector.
  4. Paste the server address copied below into Remote MCP server URL and click Add.
  5. In a chat, click + → Connectors and switch the new connector on.

Custom connectors are available on Free, Pro, Max, Team and Enterprise plans (Free is limited to one). On Team and Enterprise an organization Owner adds the connector first under Organization settings → Connectors.

Authorization

After you click Add, a sign-in window for the service opens. Sign in with your own account and approve access. Claude never sees your password.

How to connect xpost to ChatGPT

The server address to paste into ChatGPT settings:

https://xpost--xpost-to.run.tools

  1. Open ChatGPT in a browser (chatgpt.com). A Plus, Pro, Business, Enterprise or Edu plan is required.
  2. Turn on developer mode once: Settings → Apps → Advanced settings → Developer mode.
  3. Open Settings → Connectors and click Create.
  4. Fill in the form: Name (anything), Description (one line about what the service does), MCP server URL (copy it below).
  5. Under Authentication choose OAuth if the service requires sign-in, otherwise None. Click Create.
  6. In a new chat open + → Apps/Connectors and enable the connector.

OpenAI has renamed this section before (Connectors → Apps/Plugins). If the label differs, search settings for "developer mode". On Business/Enterprise workspaces an admin must allow custom connectors first.

Authorization

On first use ChatGPT opens the service's sign-in window. Sign in and approve access.

How to connect xpost to Cursor

The server address to paste into Cursor settings:

https://xpost--xpost-to.run.tools

Fastest: click Open in Cursor below and confirm the prompt.

Manually:

  1. In Cursor open Settings → Cursor Settings → MCP and click Add new global MCP server.
  2. Paste the JSON copied below into ~/.cursor/mcp.json (per project: .cursor/mcp.json in the repo root).
  3. Save the file. The server appears in the MCP list; authorize it there if asked.

Authorization

If the service needs sign-in, an authorize button appears next to the server in the MCP list.

Server tool list (18)

Raw names from tools/list. Only developers need these.

get_projectThe project's settings, read before writing: `timezone` (the clock every bare time is on), `queue` (its posting schedule and next free slots — `scheduled_at: "next_slot"` takes one), `approval` (whether agent posts wait for a person), `signature` (a footer xpost adds to every post itself), `guardrails` (the rules a post is checked against), `posts_today` (this key's remaining daily allowance) and `publishing` (whether anything written here can go out at all — read it before writing, not after).
list_accountsThe connected accounts and what each will publish. `ref` ("x:someone") is what create_post `accounts` takes. `limits` carries `caption_chars_available` (room for words once the signature is added), `max_media`, `media_required` and `video_seconds`; `can` carries placements, first comment, people tags, documents and mixed media. These describe the connection, not the platform's brochure. `connect_url` is the page where an account is connected — hand it over whenever a platform they asked for is missing. An empty list adds `connect_message`; a project that has never published adds `never_posted_message`, which says what to offer them next.
get_posting_rulesEvery `platform_configurations` key each account accepts, with kind, accepted values, ceilings and placement gates — the catalog to read before setting anything beyond a caption. A key that is absent cannot be published through that connection: sent anyway it is refused or loses the delivery. Pinterest accounts also list `boards`, each with `eligible`. ONE POST CARRIES EVERY ACCOUNT: list them all in create_post's `accounts` and put a platform's own words in `platform_configurations.<platform>.caption`, its own options beside them. One post per platform is not how this works — it spends the free first post on a single network, walls the rest, and hands the person one card per network to read instead of one.
upload_mediaAttach an image, video or PDF and get a `media_id` for create_post. Sources: `file` (an attachment from this conversation, as the host provides it), a public https `url`, base64 `data` with `mime_type`. Instagram, TikTok, YouTube and Pinterest need media; a PDF becomes a LinkedIn document post. When an attached file cannot be provided from here, create the post with `media_pending: true` instead and the person adds it in the approval card. Formats and caps: https://xpost.to/docs/api#media.
create_postCreate a post to connected accounts — X/Twitter, Instagram, LinkedIn, Facebook, TikTok, YouTube, Threads, Bluesky, Pinterest. CREATING IT SENDS IT: no `scheduled_at` publishes now, one publishes then; a project can hold agent posts instead, and `status` says which. The answer carries `message` and a link: `approval_link` when it waits, `preview_link` when not. `accounts` takes each account's `ref`. Media is `media_ids`, `files` (attachments from this conversation) or `media_pending: true`, which holds the post until the picture arrives — the reply's `upload_url` takes a POST of the file (`upload_curl`), or the person adds it in the card; then it goes out on its own unless the project holds agent posts. "next_slot" takes the queue; `is_draft` saves without sending.
list_postsRecent posts with `status`, `publishes`, `mediaIds` and, on a rejected post, `rejectionReason` — the person's own words on what to change with update_post (often empty after a one-tap rejection). Filter with `status` (one or several), `limit`, and `from`/`to` on the scheduled time. A post still waiting carries `approval_link`. `filter` echoes what applied. An empty list with nothing filtered adds `never_posted_message`, which says what to offer them next.
delete_postRemove a post this key created that has not gone out. A draft, a post waiting for approval, a rejected or a failed one is deleted with its delivery records. A post already holding a time is taken off the schedule instead, and `unscheduled` with `message` says so. Posts a person approved are refused, and so is one that has gone out — removing THAT from the platform is `take_down_post`.
update_postChange a post that has not gone out — caption, media, time, per-platform options; anything left out is kept. The reply is a NEW post with a new id and a new `approval_link`; `replaced` names the old one, which is gone. `add_media_ids` and `files` append to what the post holds; `media_ids` replaces it. A picture the person added in the approval card is already on the post. Editing an approved or rejected post puts it back in the approval queue, and `message` says which of the two happened. A post already tried is not editable: retry_delivery handles the delivery that failed. Send a draft with `is_draft: false` — creating it again instead posts the words twice.
retry_deliverySend one failed delivery again, by its `id` from get_delivery_receipt. A delivery that succeeded is refused. A refusal carries `error_code` — `already_succeeded` (with `post_url`, or `taken_down`), `in_flight`, `already_claimed`, `not_found` — and `retriable`, false when asking again cannot change the answer.
take_down_postDelete a published delivery from its platform, by its `id` from get_delivery_receipt. There is no undo; reposting is a new post with a new URL. This is the person's own decision about their live post, not a cleanup step. `error_code` `never_went_out`, `account_gone` or `unsupported` means the person removes it on the platform themselves; only `platform_refused` is `retriable`.
list_connection_issuesAccounts that cannot publish right now — an expired token, a platform out of reach — each with what happened. The fix is the person reconnecting that account: `connect_url` is where they do it. An empty list means every account is healthy.
get_delivery_receiptPer-account delivery receipt for a post: `status`, the live URL, `plain_reason` on failure, and `note` where less was published than was attached. Also how a post is shown again: in a host that draws cards the result is the post itself, with Approve and Reject while it waits; `approval_link` is the same post as a page.
check_guardrailsDry-run a caption against the project's guardrails without creating anything. `allowed` with an empty `rules_checked` means the project has no rules, not that the text was cleared. `rules_skipped` lists rules that could not answer; a verdict listing any is incomplete.
bulk_postCreate up to 100 DIFFERENT posts in one call. Each row runs the full single-post path — guardrails, allowance, approval — and reports on its own, so some rows can land while others refuse. A row's media is `media_ids` (from upload_media) or `media_urls`. A held row carries its own `approval_link`. An `idempotency_key` per row makes a resend after a timeout answer `repeated: true` instead of a second post. NOT for one post going to several accounts: that is ONE create_post with every account in `accounts`, with any per-platform wording in `platform_configurations.<platform>.caption`.
get_post_metricsPer-platform engagement for one published post: views, likes, comments, shares, reach, saves, engagement, and the live URL. A null metric is one the platform does not report, not zero; empty `data` means the numbers have not synced yet (roughly every 6 hours).
get_insightsEngagement over a window: totals, per platform, per format. `coverage` says how much of the window the totals rest on: `with_metrics` + `unreportable` + `awaiting` = `deliveries`. Stories are never reported on by Instagram or Facebook, so `format: "story"` totals are zero however many went out. `ever_delivered` separates an empty window from an empty history.
get_top_postsBest-performing deliveries ranked by a metric, with caption, platform, username, metrics and live URL — what worked for this audience, as a study aid rather than a template.
get_best_timesPosting slots (weekday × hour, UTC) ranked by this workspace's own past engagement. `signal` says what the order is worth: `none` means no engagement is recorded and the order is arbitrary; `thin` means some slots rest on one or two posts (`samples`); `ok` means three or more each.