xpost
Server Details
Post all your social media with your AI agent — 9 networks, from Claude, ChatGPT or Cursor.
- Status
- Healthy
- Uptime
- 75.6% over 41 days
- Last Tested
- Transport
- Streamable HTTP · MCP 2025-11-25
- URL
- Repository
- xpost-to/xpost-agent
- GitHub Stars
- 0
- ChatGPT
- xpost
- Claude
- –
TDQS
Scored across 17 tools
The lifecycle tools are cleanly separated (create_post vs bulk_post vs update_post vs delete_post vs take_down_post), and the descriptions explicitly draw the boundaries. The only mild overlap is among the read-side tools — get_delivery_receipt, get_post_metrics, get_top_posts, get_insights and list_posts all return post performance data, though each is scoped to a different grain (delivery status, single post numbers, rankings, window totals, list).
Nearly all names are snake_case verb_noun (create_post, update_post, delete_post, get_post_metrics, list_accounts, upload_media), which is highly predictable. The deviations are minor: 'bulk_post' uses a qualifier instead of a verb, and 'take_down_post' is a phrasal verb, but both remain readable and unambiguous.
Seventeen tools is slightly heavy but each one covers a genuinely distinct capability across publishing, media, accounts, health, scheduling and analytics. There is no obvious filler — even narrower tools like get_best_times and list_connection_issues serve a specific job an agent would otherwise have to guess at.
The surface covers the full post lifecycle — upload media, create (single and bulk), edit, delete drafts, retry failed deliveries, take down live posts — plus accounts, connection health, platform rules, project settings and a full analytics tier. There are no dead ends; even failure paths (retry_delivery, list_connection_issues, approval links) have dedicated tools.
Available Tools
17 toolsbulk_postCreate several posts at onceADestructiveInspect
Create AND SEND up to 100 DIFFERENT posts in one call: each row goes out at its scheduled_at, or now, unless the project holds agent posts. Each row runs the full single-post path — 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.
| Name | Required | Description | Default |
|---|---|---|---|
| rows | No | The posts to create, one object per post. `posts` is accepted as the same thing. | |
| posts | No | Alias for `rows` — send one or the other. |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | Present and false only on a refusal. |
| error | No | What was refused, in a sentence, when `ok` is false. |
| failed | No | |
| created | No | |
| message | No | About the whole batch, written to be passed on — today, accounts it puts past a day's worth of posts. |
| results | No | One row per row you sent, in order. Rows are independent — some can land while others refuse. |
| retriable | No | False when asking again cannot change the answer. |
| error_code | No | Machine reason for a refusal. |
| replaced_by | No | The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on. |
| pace_warnings | No | Accounts getting more posts in one day than the network likes — it may treat that as spam. Nothing is held. Mention it to the person once and offer to spread the rest out; don't stop to ask on every post. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: rows are independently evaluated through the full single-post path (allowance, approval) and can partially succeed ("some rows can land while others refuse"), held rows return their own approval_link, and a per-row idempotency_key converts a timeout resend into `repeated: true` rather than a duplicate — useful nuance given idempotentHint=false applies to the call, not the row. This is exactly the failure/idempotency context an agent needs before firing 100 writes.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the create-and-send scope plus the batch limit, then the row-level mechanics, then the exclusion rule — a sensible order with no filler. It is dense (long sentences, heavy backtick usage) but every clause carries operational information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a high-blast-radius bulk write with an output schema present, it covers the essentials: partial success, approval holds, idempotent resends, and the sibling alternative. It stops short of stating whether schema-invalid rows fail the whole batch or just that row, and says nothing about rate limits or batch ordering on real-time sends.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the nested row fields are already documented (accounts refs, media_ids vs media_urls ordering, scheduled_at "next_slot", idempotency_key). The description largely restates those facts rather than adding new meaning — e.g. the media precedence rule already appears in the schema — so the baseline 3 holds.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb + resource + scale: "Create AND SEND up to 100 DIFFERENT posts in one call." It immediately distinguishes the bulk case from the single-post case, and the closing sentence names the sibling create_post for the opposite pattern (one post, many accounts).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit negative rule with the alternative: "NOT for one post going to several accounts: that is ONE create_post with every account in `accounts`." It also routes media preparation to upload_media, and states the scheduling default ("or now") and the held-project exception, so the agent knows when this tool applies and when it does not.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_postCreate a postADestructiveInspect
Create 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 may hold it instead (status says). The answer carries message and approval_link or preview_link. 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. Undo: update_post or delete_post before it goes out; take_down_post after, where networks allow.
| Name | Required | Description | Default |
|---|---|---|---|
| files | No | Files the user attached to this conversation, as the host hands them over, in post order. They are attached after `media_ids`. | |
| caption | No | The post text. Optional only where no destination prints one: a story, or X/Instagram/LinkedIn publishing media alone. WRITE IT TO FIT EVERY TARGET: one destination over its own limit refuses the WHOLE post and nothing goes out anywhere — X is 280 as X counts it, and list_accounts gives each account its `caption_chars_available`. Words the person wrote are theirs: where they do not fit, say so and ask, never quietly shorten them. | |
| accounts | No | Where it posts: each account's `ref` from list_accounts ("x:someone"). LIST EVERY ACCOUNT THIS POST GOES TO — one post, many accounts; a platform that needs different words gets them in platform_configurations.<platform>.caption, never a post of its own. A person reads this request before approving it, and the ref is what they can check. A ref matching nothing refuses the whole post. | |
| is_draft | No | Save as a draft: visible in xpost, publishing nowhere until a person sends it. | |
| media_ids | No | Media ids from upload_media; first is the carousel lead. | |
| scheduled_at | No | ISO 8601 with Z or an offset, or "next_slot" for the project's own posting schedule (get_project shows `queue`). Omit to publish now — or, on a project that holds agent posts, as soon as it is approved. | |
| media_pending | No | The picture is still to come: the person adds it in the approval card. Lets a post for Instagram, TikTok, YouTube or Pinterest be created without media; it goes out once the media is on it (or, on a project that holds agent posts, can be approved then). | |
| idempotency_key | No | Your own id for THIS request, unique to it (not to the subject). A retry with the same key returns the post the first call made, as `repeated: true`, instead of a second post. | |
| social_account_ids | No | Deprecated name for `accounts`. | |
| platform_configurations | No | Per-platform options keyed by platform: `caption` is that platform's own text (so one post can say it differently on X and on Instagram), `placement` picks "reels"/"stories" where offered. Which keys each account takes is what get_posting_rules answers. Example: {"instagram": {"placement": "stories"}, "x": {"caption": "the short one"}} |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| ok | No | Present and false only on a refusal. |
| error | No | What was refused, in a sentence, when `ok` is false. |
| shown | No | Where this post is already on screen, and that a receipt call now would show it a second time. |
| status | No | pending_approval | scheduled | processing | draft |
| caption | No | |
| message | No | About this post, written to be passed on: why it is held, or that a draft goes nowhere until someone sends it. |
| missing | No | What the post still lacks before it can go out. |
| repeated | No | This idempotency_key was already used — `id` is that earlier post, nothing new was written. |
| replaced | No | update_post: the id of the post this one replaced. That post and its approval link are gone; this post's link stands in for them. |
| timezone | No | |
| plans_url | No | Public page explaining what the plans include. Sent with free_first_post, with publishing_needs_plan, and on a refusal with error_code needs_plan. |
| publishes | No | What has to happen before it goes out. Null on a draft or a rejected post. |
| retriable | No | False when asking again cannot change the answer. |
| attach_now | No | This host cannot send the file: the person adds it in the card, which offers its drop zone straight away. |
| created_at | No | |
| error_code | No | Machine reason for a refusal. |
| plans_link | No | The same page as a ready-made Markdown link. On a refusal with error_code needs_plan, include it in the reply as-is — it is where the person activates a plan. |
| upload_url | No | On a held post: where a picture is POSTed as multipart form-data with a `file` field, no key needed. An environment that holds the file can run `upload_curl`; the person's card uses the same door. |
| connect_url | No | Where an account is connected. On a refusal about an account that is not there. |
| needs_media | No | A draft with no picture or video for a destination that needs one; `missing` names them. It cannot be sent as it stands — attach media with update_post, or the person adds it in xpost. |
| release_url | No | After POSTing every file to upload_url, POST this once and the post goes out. In the card the person presses it instead. |
| replaced_by | No | The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on. |
| upload_curl | No | The upload as one shell command, YOUR_FILE replaced by the path. |
| preview_link | No | A post nobody has to approve, as a ready-made Markdown link to it — the post as each network will draw it, its slot if it has one, and the receipt per account once it has gone. A DRAFT gets one too: it has no slot and nothing is waiting, and the link is the only way the person can see what was written without going to look for it. Give it to the person. |
| queued_posts | No | How many posts are scheduled, none of them going anywhere beyond the free first one. Sent with publishing_needs_plan on a scheduled post. |
| scheduled_at | No | The slot it got. NULL when it waits on approval — never a stand-in time. |
| approval_link | No | A ready-made Markdown link to the post as a page, with Approve and Reject on it. |
| free_post_now | No | Refused only because it was scheduled. The same call with no scheduled_at publishes now, free. |
| pace_warnings | No | Accounts getting more posts in one day than the network likes — it may treat that as spam. Nothing is held. Mention it to the person once and offer to spread the rest out; don't stop to ask on every post. |
| awaiting_media | No | Created without its picture (media_pending). It cannot be approved until one is on it. |
| drafts_waiting | No | How many drafts are now waiting, none of them on its way anywhere. Sent with publishing_needs_plan. |
| free_post_ride | No | With free_first_post: this post reached another of their accounts as part of the same free first post, sent in the same reply. One free delivery per account, within a few minutes of the first. |
| replaced_draft | No | This post FINISHED a draft that held the same words for the same accounts: that draft is gone and this post stands in for it. Say there is one copy. |
| connect_message | No | |
| free_first_post | No | This post is the user's one free post — no plan was needed for it. |
| upload_max_bytes | No | The most `upload_url` takes in one request; bigger files go through the card. |
| releases_on_media | No | Held for its picture only: it goes out on its own once every picture is on it. Nothing to approve. |
| first_post_message | No | About that, written to be passed on; it carries the next step. |
| x_trial_link_limit | No | X will not receive this post: the trial's posts with a link on X are used up. Every other account still gets it. Without the link, X gets it as usual. |
| x_monthly_link_limit | No | X will not receive this post: this month's posts with a link on X are used up on their plan. Every other account still gets it. Without the link, X gets it as usual. |
| publishing_needs_plan | No | Nothing here can publish beyond the one free post: sending needs an xpost subscription. Nothing REFUSES a draft or a scheduled post any more — a queue may be filled without one — so this is the only warning, and it is worth passing on as it is written rather than discovered one slot at a time. |
| free_post_awaiting_approval | No | Refused because their free first post is already waiting for their approval; approval_link opens it. Nothing needs buying. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say destructiveHint=true and openWorldHint=true; the description adds the critical context of WHAT gets destroyed and WHEN — 'CREATING IT SENDS IT', plus the project-holds-agent-posts exception and the approval/preview flow. The idempotency discussion is consistent with idempotentHint=false: retries only dedupe when the caller supplies its own `idempotency_key`, which the description makes explicit rather than contradicting the annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The single most important fact ('CREATING IT SENDS IT') is front-loaded in caps, and nearly every clause carries operational information. It is dense and telegraphic to the point of occasional ambiguity ('one publishes then'), which costs it the top score, but there is no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 10-parameter, nested-object, open-world mutation tool, the description covers side effects, approval gating, scheduling modes, media staging, partial-caption risk across platforms, and recovery paths. The output schema already documents return shape, so the brief mention of `message`/`approval_link` is sufficient rather than redundant.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents every field; the description's added value is relational — `accounts` takes refs from list_accounts, per-platform wording belongs in platform_configurations.<platform>.caption, files attach after media_ids, and the media_pending upload_url POST flow. It stops short of explaining `social_account_ids` (deprecated) or the placement key set, leaving those to the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (create a post) and enumerates the exact destinations it reaches, so the agent knows the blast radius before reading a single parameter. It also carves out the boundary against making multiple posts: 'one post, many accounts; a platform that needs different words gets them in platform_configurations.<platform>.caption, never a post of its own.'
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when/when-not guidance across the major modes: omit `scheduled_at` to publish now, `next_slot` to take the queue, `is_draft` to save without sending, `media_pending` to hold until media arrives. It also names the correct undo path per timing (update_post/delete_post before it goes out, take_down_post after), which is exactly the alternative-routing an agent needs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_postDelete a postADestructiveIdempotentInspect
Remove 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.
| Name | Required | Description | Default |
|---|---|---|---|
| post_id | Yes | The post id from create_post |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| ok | No | Present and false only on a refusal. |
| error | No | What was refused, in a sentence, when `ok` is false. |
| status | No | |
| deleted | No | Gone permanently, with its delivery records. |
| message | No | |
| retriable | No | False when asking again cannot change the answer. |
| error_code | No | Machine reason for a refusal. |
| replaced_by | No | The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on. |
| unscheduled | No | Taken off the schedule and handed back to the user instead of deleted. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructive/idempotent, but the description goes well beyond them: it discloses cascading deletion of delivery records, the non-obvious branch where a scheduled post is unscheduled instead of deleted, and the return signal (`unscheduled` with `message`). It also spells out which posts are refused and why, which an agent cannot infer from the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Highly information-dense with the primary constraint front-loaded and no filler. Some clauses are telegraphic ("a rejected or a failed one is deleted with its delivery records"), which costs a little readability but every sentence carries distinct behavioral information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return shape needn't be explained, yet the description still flags the `unscheduled`/`message` response case. For a single-parameter destructive tool, the destructive scope, cascade effects, refusals, and the alternative path are all covered.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter, `post_id`, and schema coverage is 100% with a usable description ("The post id from create_post"). The prose adds no additional meaning about the identifier beyond that, so this sits at the baseline where the schema does all the work.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Remove a post") plus a precise scope: posts this key created that have not gone out. It explicitly distinguishes itself from the sibling take_down_post for posts that have already published, so an agent can route without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Enumerates the eligible states (draft, awaiting approval, rejected, failed) and the two refusal cases (human-approved, already published), naming the alternative tool for the latter. The when-not guidance is explicit and actionable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_best_timesBest times to postARead-onlyIdempotentInspect
Posting 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.
| Name | Required | Description | Default |
|---|---|---|---|
| format | No | Filter to one format (feed post / reel / story) | |
| platform | No | Filter to one platform, e.g. instagram | |
| since_days | No | Window in days (default 90) |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | Present and false only on a refusal. |
| error | No | What was refused, in a sentence, when `ok` is false. |
| slots | No | Best first. Empty when there is not enough history to rank anything. |
| signal | No | How much the ORDER is worth. "none": no engagement recorded, so the order is arbitrary. "thin": some slots rest on one or two posts. "ok": every slot has 3+. |
| retriable | No | False when asking again cannot change the answer. |
| error_code | No | Machine reason for a refusal. |
| since_days | No | |
| replaced_by | No | The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed-world), so the description's added value is the trust model: it explains that `none` means the order is arbitrary, `thin` means one or two underlying posts (`samples`), and `ok` means three or more. That is exactly the kind of behavioral context an agent needs before presenting the ranking as advice.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with what the tool returns, then the interpretation key for `signal`. Dense but every clause earns its place; the only slight redundancy is that `signal` may also be documented in the output schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need not be spelled out, the three optional filters are fully documented in schema, and the description closes the main remaining gap by warning when the ranking is meaningless. Nothing an agent needs in order to call or interpret this tool is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, including the enum for `format` and the 1–365 bounds and default for `since_days`, so the schema carries the parameter burden. The description adds only the UTC timezone qualifier, which pertains to the output rather than to any filter parameter, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a concrete resource (posting slots at weekday × hour granularity in UTC) and the ranking basis (this workspace's own past engagement), which an agent can grasp immediately. It stops short of naming how it differs from overlapping siblings such as get_insights or get_top_posts, so it is clear but not fully differentiated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: an agent must infer that this is for scheduling/planning rather than analytics review. There is no explicit when-to-use or when-not guidance, and no alternative sibling is named, though the `signal` explanation implicitly tells the agent when the ranking is trustworthy enough to act on.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_delivery_receiptDelivery receipt for a postARead-onlyIdempotentInspect
Per-account delivery receipt for a post: status, the live URL, plain_reason on failure, and note where less was published than was attached. approval_link is the post as a page. Not needed straight after create_post or update_post: their card already follows the delivery live. Not needed before take_down_post either: it takes the post id and draws the post once it is down.
| Name | Required | Description | Default |
|---|---|---|---|
| post_id | Yes | The post id from create_post |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | Present and false only on a refusal. |
| data | No | One row per destination account. |
| error | No | What was refused, in a sentence, when `ok` is false. |
| post_id | No | |
| retriable | No | False when asking again cannot change the answer. |
| error_code | No | Machine reason for a refusal. |
| post_status | No | |
| release_url | No | POST once, after every picture is on the post, and it goes out on its own. |
| replaced_by | No | The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on. |
| approval_link | No | The post as a page; the card draws the same thing. |
| picture_on_it | No | The picture has landed; only the release call is missing. |
| held_for_picture | No | Created with media_pending and not released yet. |
| made_by_you_just_now | No | You created this post minutes ago; its card is already on screen. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only, idempotent, non-destructive, closed-world, so the safety profile is done. The description adds real behavioral context beyond that: it discloses that failures surface as plain_reason, that partial publishing is signalled via note, and that approval_link renders the post as a page — useful signals about outcome states the agent would otherwise have to guess.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded in the first clause, followed by return-field enumeration and then two tight exclusion sentences. The heavy use of backticked field names is dense but each sentence earns its place; no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description needn't explain return structure, yet it still summarizes the key fields and their failure/partial-publish meaning. Combined with annotations and full schema coverage, an agent has enough to call this correctly; only the positive 'use when' trigger is left implicit.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single required post_id parameter at 100% schema description coverage, which already documents it as 'the post id from create_post'. The description text adds nothing about the parameter, so the baseline of 3 applies — correct behavior, no added value.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific resource (per-account delivery receipt for a post) and enumerates the exact fields it returns (status, live URL, plain_reason, note, approval_link), which lets an agent tell it apart from get_post_metrics or get_insights. It never states an explicit verb like 'fetch', but the receipt framing is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives unusually specific negative routing: don't call it straight after create_post or update_post because their card already follows delivery, and don't call it before take_down_post because that tool draws the post itself. The positive trigger (call it when you need delivery state later) is only implied, so it falls short of a full when/when-not/alternative triad.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_insightsAccount insightsARead-onlyIdempotentInspect
Engagement 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.
| Name | Required | Description | Default |
|---|---|---|---|
| format | No | Filter to one format (feed post / reel / story) | |
| platform | No | Filter to one platform, e.g. instagram | |
| since_days | No | Window in days (default 30) |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | Present and false only on a refusal. |
| error | No | What was refused, in a sentence, when `ok` is false. |
| posts | No | |
| totals | No | |
| coverage | No | How much of the window the totals actually cover. with_metrics + unreportable + awaiting === deliveries. |
| by_format | No | |
| retriable | No | False when asking again cannot change the answer. |
| deliveries | No | |
| error_code | No | Machine reason for a refusal. |
| since_days | No | |
| by_platform | No | |
| replaced_by | No | The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on. |
| median_sample | No | How many deliveries the median came from. Under a handful it is a coin toss. |
| median_engagement | No | The baseline one post has to be read against — a raw total says nothing on its own. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnly/idempotent annotations: it defines the coverage equation (with_metrics + unreportable + awaiting = deliveries) and warns that story formats always yield zero totals because Instagram/Facebook don't report them. It also explains ever_delivered as the signal separating an empty window from an empty account history — exactly the context needed to interpret results correctly.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four sentences, each carrying a distinct load — scope first, then the coverage definition, then the story-format trap, then the empty-vs-history distinction. Dense but front-loaded and waste-free, despite the backtick-heavy notation.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values needn't be spelled out, and the description still adds the interpretive keys (coverage, ever_delivered) an agent needs. The remaining gap is competitive positioning among 16 siblings — nothing says when this beats get_post_metrics or get_top_posts.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds genuine meaning beyond the schema: it tells the agent that format: "story" will produce zero totals regardless of volume, which prevents a misread of the parameter's effect. Window semantics for since_days are only lightly reinforced.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource with scope: engagement aggregated over a window, broken out as totals, per platform and per format. That distinguishes it in spirit from get_post_metrics/get_top_posts, but it never names a sibling or says explicitly that it is the aggregate endpoint.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the window/filter framing and the caveats about story formats, but there is no explicit when-to-use or when-not guidance, and no routing to alternatives like get_post_metrics for per-post detail or get_best_times for timing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_posting_rulesPosting rules per accountARead-onlyIdempotentInspect
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 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.
| Name | Required | Description | Default |
|---|---|---|---|
| social_account_ids | No | Narrow to these accounts (ids from list_accounts); omit for all |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | Present and false only on a refusal. |
| data | No | |
| error | No | What was refused, in a sentence, when `ok` is false. |
| retriable | No | False when asking again cannot change the answer. |
| error_code | No | Machine reason for a refusal. |
| replaced_by | No | The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint/idempotentHint/destructiveHint=false, so the safety profile is covered. The description adds genuine behavioral context beyond them: absent keys are refused or silently lose the delivery if sent anyway, and Pinterest returns nested `boards` with `eligible`. It does not discuss pagination or rate limits, but for a read-only catalog that gap is minor.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The first sentence front-loads the resource content well, but roughly half the text is a lecture about how create_post should be called ("ONE POST CARRIES EVERY ACCOUNT", per-platform caption placement). That guidance serves create_post more than this tool and crowds out detail about this tool's own behavior.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be spelled out, yet the description usefully characterizes the payload shape (keys, accepted values, ceilings, gates, boards). With full schema coverage and a documented single optional filter, an agent has what it needs to call this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single `social_account_ids` parameter is fully documented inline, so the baseline is 3. The description never mentions this parameter, and its "list them all" instruction refers to create_post's `accounts`, not this tool's filter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states precisely what is returned: every `platform_configurations` key accepted per account, with kind, accepted values, ceilings and placement gates, plus Pinterest `boards` with `eligible`. It distinguishes itself from create_post by framing itself as the catalog to read first, though it opens with a noun phrase rather than a verb, making the read action slightly implicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"the catalog to read before setting anything beyond a caption" gives a clear trigger condition, and the note that absent keys cannot be published establishes a consequence for skipping it. It does not enumerate other alternatives (e.g., list_accounts for ids is only referenced in the schema), so the routing is clear but not exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_post_metricsMetrics for a postARead-onlyIdempotentInspect
Per-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).
| Name | Required | Description | Default |
|---|---|---|---|
| post_id | Yes | The post id from create_post |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | Present and false only on a refusal. |
| data | No | One row per platform. EMPTY means the numbers haven't synced yet, not that nobody saw it. |
| error | No | What was refused, in a sentence, when `ok` is false. |
| post_id | No | |
| retriable | No | False when asking again cannot change the answer. |
| error_code | No | Machine reason for a refusal. |
| replaced_by | No | The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so the description is free to spend its words elsewhere — and it does: null vs zero semantics, empty `data` meaning unsynced, and a ~6-hour refresh cadence are exactly the interpretive context an agent needs and cannot get from structured fields. It does not cover rate limits or per-platform keying details, keeping it at 4.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, both front-loaded with the highest-value information: what comes back first, then how to read ambiguous results. No filler, no restatement of the title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return-value structure need not be explained, yet the description still supplies the semantics that a schema cannot express (null meaning, empty-data meaning, sync cadence). The remaining gap is sibling differentiation against get_insights/get_top_posts.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is one required parameter at 100% schema coverage, and the schema already documents it as 'The post id from create_post' including UUID format and pattern. The description adds nothing about the parameter, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the resource precisely ('per-platform engagement for one published post') and enumerates the returned metrics, so an agent knows exactly what it yields. It does not distinguish itself from plausible siblings such as get_insights or get_top_posts, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied by the phrase 'for one published post' — the agent can infer this is the single-post lookup, but there is no explicit when-to-use statement and no routing away from get_insights, get_top_posts, or list_posts. No prerequisites or exclusions are stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_projectProject rules and settingsARead-onlyIdempotentInspect
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), approval (whether agent posts wait for a person), 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).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | Present and false only on a refusal. |
| name | No | |
| error | No | What was refused, in a sentence, when `ok` is false. |
| queue | No | |
| approval | No | |
| timezone | No | Every bare timestamp is read in this zone. |
| retriable | No | False when asking again cannot change the answer. |
| signature | No | |
| error_code | No | Machine reason for a refusal. |
| guardrails | No | |
| publishing | No | |
| posts_today | No | |
| replaced_by | No | The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds meaningful behavioral context beyond annotations: it describes how settings gate writes ('whether agent posts wait for a person', 'whether anything written here can go out at all') and clarifies the operational consequence of each field.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The definition is front-loaded with the core purpose and then organizes details field-by-field with useful parentheticals. It is dense but not wasteful, though the single long sentence is slightly harder to scan than a more structured list would be.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no parameters, rich read-only annotations, and an output schema present, the description supplies everything an agent needs: what the settings mean, why they matter before writing, and how to interpret key values like queue.next_slot. Nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4. The description does not need to explain parameter semantics, and it correctly focuses on the returned settings instead.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the resource as 'the project's settings' and enumerates the specific fields returned: timezone, queue, approval, posts_today, and publishing. It is distinguishable by content from sibling tools, but does not explicitly contrast itself with closely related tools like get_posting_rules, so it falls just short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides strong usage guidance with 'read before writing' and the emphatic 'read it before writing, not after', telling the agent exactly when this tool is needed. It lacks explicit exclusions or named alternatives, which prevents a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_top_postsTop postsARead-onlyIdempotentInspect
Best-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.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max results (default 10) | |
| format | No | Filter to one format (feed post / reel / story) | |
| metric | No | Ranking metric (default engagement) | |
| platform | No | Filter to one platform, e.g. instagram | |
| since_days | No | Window in days (default 30) |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | Present and false only on a refusal. |
| data | No | |
| error | No | What was refused, in a sentence, when `ok` is false. |
| metric | No | |
| retriable | No | False when asking again cannot change the answer. |
| error_code | No | Machine reason for a refusal. |
| since_days | No | |
| replaced_by | No | The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true and destructiveHint=false, so safety is covered by structured data. The description adds useful behavioral context — that results are ranked by a chosen metric and include a live URL — but does not mention defaults (limit 10, 30-day window), pagination, or whose posts are in scope.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence that leads with the core operation and return payload. The trailing 'study aid rather than a template' clause is interpretive but short and arguably aids intent; only mildly ornamental.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values needn't be spelled out, and the annotations plus full schema coverage handle safety and parameters. The only real gap is scope — it is unclear whether this ranks the caller's own accounts' posts or broader data ('this audience' is vague).
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all five parameters (limit, format, metric, platform, since_days) are already documented including defaults and enums. The description only reiterates that a metric drives ranking, adding little beyond the schema; baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific operation — ranking deliveries by a metric — and enumerates the returned fields (caption, platform, username, metrics, live URL). This distinguishes it from list_posts (unranked) and get_post_metrics (a single post), though it never names those siblings explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'what worked for this audience, as a study aid rather than a template' implies an exploratory/analytical use case, giving some context on intent. But it offers no explicit when-to-use versus alternatives such as get_post_metrics, get_insights, or get_best_times, leaving routing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_accountsList connected accountsARead-onlyIdempotentInspect
The connected accounts and what each will publish. ref ("x:someone") is what create_post accounts takes. limits carries caption_chars_available (room for your words), 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. posts_left_today (where present) is how many more posts that account can publish before resets_at (midnight UTC) — schedule past it, not into a full day, which is refused. 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.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | Present and false only on a refusal. |
| data | No | |
| error | No | What was refused, in a sentence, when `ok` is false. |
| retriable | No | False when asking again cannot change the answer. |
| error_code | No | Machine reason for a refusal. |
| connect_url | No | |
| replaced_by | No | The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on. |
| connect_message | No | |
| never_posted_message | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/idempotent annotations, it discloses real behavioral detail: empty results append `connect_message`, brand-new projects append `never_posted_message`, and scheduling into a full day is refused with a UTC-midnight reset. It notably warns that limits reflect the actual connection, not the platform's advertised capability. It doesn't describe ordering or pagination, but with zero parameters the payload is presumably a single list.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded, but the bulk is an enumerated tour of return fields (`limits`, `can`, `posts_left_today`, `connect_url`) that an output schema already covers. The 'not the platform's brochure' clarification earns its place; the field inventory is partially redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With zero parameters, closed-world read-only annotations and an output schema, the definition needs only to route the agent and flag behavioral edge cases. It does both, including the missing-platform handoff and never-posted case. Nothing required for correct invocation is absent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes no parameters, which is the documented baseline for full marks. The description spends its space on return-field semantics instead, which is not what this dimension measures but also not harmful.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening fragment 'The connected accounts and what each will publish' identifies the resource and scope, and the title supplies the verb. It also differentiates itself by naming create_post's `accounts` parameter as the downstream consumer, which no sibling does. It stops short of an explicit 'list/read' verb and doesn't contrast with list_connection_issues.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides concrete usage conditions: use `ref` to fill create_post's `accounts`, hand over `connect_url` when a requested platform is missing, and schedule around `posts_left_today` rather than into a refused full day. These are operating instructions rather than explicit when-to-call-this-vs-alternative guidance, so no exclusion clause is given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_connection_issuesList account connection problemsARead-onlyIdempotentInspect
Accounts 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.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | Present and false only on a refusal. |
| data | No | Open issues only. Empty means every account is healthy. |
| error | No | What was refused, in a sentence, when `ok` is false. |
| retriable | No | False when asking again cannot change the answer. |
| error_code | No | Machine reason for a refusal. |
| connect_url | No | Where the person reconnects an account. |
| replaced_by | No | The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on. |
| connect_message | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive, so the safety profile is covered. The description adds genuine behavior the agent would otherwise guess at: what an empty list means (all accounts healthy) and that the remedy lives at connect_url. It omits pagination/volume expectations, keeping it below a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the definition, then the remediation path, then the empty-list edge case. No filler or repetition of the title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present the description needn't explain return values, so covering the definition, the empty-result case, and the remediation pointer is sufficient for an agent to call and act on this no-parameter read tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, which is the baseline-4 case: there is no parameter meaning to convey and the description correctly spends no words on inputs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
It names the resource (accounts that cannot publish) and enumerates the failure modes (expired token, unreachable platform), which implicitly distinguishes it from list_accounts. It stops short of explicitly contrasting with that sibling, but an agent can tell what the tool returns.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description supplies downstream guidance ('the fix is the person reconnecting that account; connect_url is where they do it'), which is useful remediation context. It never states the triggering condition for calling this versus list_accounts or when to skip it, so usage is only implied by the tool's name and scope.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_postsList postsARead-onlyIdempotentInspect
Recent 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.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | Only posts whose scheduled time is at or before this instant. | |
| from | No | Only posts whose scheduled time is at or after this instant (ISO 8601, Z or offset). With `from` or `to` the list runs soonest first and leaves out posts that have no time yet. | |
| limit | No | How many, newest first (default 50, max 100) | |
| status | No | Only posts in this state (or any of these). Omit for all of them. |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | Present and false only on a refusal. |
| data | No | Newest first, camelCase here unlike the rest of this server. Up to `limit` (50 by default). |
| error | No | What was refused, in a sentence, when `ok` is false. |
| filter | No | What actually applied — null status means nothing was filtered. |
| retriable | No | False when asking again cannot change the answer. |
| error_code | No | Machine reason for a refusal. |
| replaced_by | No | The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on. |
| never_posted_message | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: discloses that from/to flips ordering to soonest-first and drops untimed posts, that limit is newest-first, that `filter` echoes applied filters, that an unfiltered empty result adds never_posted_message, and that rejectionReason is often empty after a one-tap rejection. These are non-obvious response behaviors an agent could not infer.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense single paragraph, front-loaded with the returned shape before filters and edge cases. Backtick-heavy phrasing makes it slightly hard to scan but every clause carries real information; no filler sentences.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so explaining individual return fields is partly redundant, but the conditional fields (approval_link, never_posted_message, filter echo) and the empty-result semantics are exactly the kind of conditional behavior a schema alone wouldn't surface. Nothing essential for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema already documents status-as-single-or-array, the from/to ordering side effect, and limit defaults. The description largely restates those same semantics rather than adding new meaning, so it sits at the baseline for high coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Concrete: lists recent posts, names the exact fields returned (status, publishes, mediaIds, rejectionReason) and the filters available. It's clearly a post-listing read, distinct from get_top_posts or get_post_metrics by virtue of being unfiltered-by-performance, though no sibling is named explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied through the data: a rejected post's rejectionReason is what to change 'with update_post', and never_posted_message 'says what to offer them next' — so the agent gets workflow cues. But there is no explicit statement of when to choose this over get_top_posts or get_insights.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retry_deliveryRetry a failed deliveryAInspect
Send one failed delivery again, by its id from get_delivery_receipt — a delivery id, not a post id. Skip it when the receipt says retry_helps: false: the same failure comes back. 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, or is_post_id (a post id was passed; its deliveries are in the answer, pick the failed one) — and retriable, false when asking again cannot change the answer.
| Name | Required | Description | Default |
|---|---|---|---|
| delivery_id | Yes | `id` of the failed row in get_delivery_receipt |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| ok | No | Present and false only on a refusal. |
| error | No | What was refused, in a sentence, when `ok` is false. |
| retried | No | |
| post_url | No | On `already_succeeded`: the live post. It did land. |
| retriable | No | False when asking again cannot change the answer. |
| error_code | No | Machine reason for a refusal. |
| taken_down | No | With no post_url: it went out and was removed; no live link exists. |
| replaced_by | No | The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare it is a non-read-only, non-idempotent, open-world write. The description goes well beyond that by enumerating the refusal taxonomy (already_succeeded, in_flight, already_claimed, not_found, is_post_id) and the retriable flag that tells the agent whether re-asking can change the answer. That is exactly the behavioral context an agent needs before calling a non-idempotent mutation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action and the critical skip condition, with zero filler. The long parenthetical enumerating every error_code is dense and slightly harder to scan than a short list, but each item earns its place by telling the agent how to react.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need not be explained, and the description still covers the input source, the skip rule, refusal handling, and retriability. Nothing needed to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real disambiguation beyond the schema text: the id is a delivery id and specifically not a post id, and the is_post_id refusal explains how to recover when the wrong kind of id is supplied. That extra meaning justifies a 4.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Send one failed delivery again') and immediately pins the identifier to a delivery id from get_delivery_receipt, explicitly excluding a post id. That single clause distinguishes it from get_delivery_receipt and from post-level siblings without needing the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use (a failed delivery whose receipt does not say retry_helps: false) and when-not (succeeded deliveries are refused), plus an alternative path when a post id is passed: pick the failed row out of the returned deliveries. The preconditions are concrete and actionable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
take_down_postTake a live post downADestructiveIdempotentInspect
Delete a published post from its platforms, by its post_id — every platform it is live on, or only platform. There is no need to call get_delivery_receipt first. 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. Each delivery answers in deliveries: error_code never_went_out, account_gone or unsupported means the person removes it on the platform themselves; only platform_refused is retriable. delivery_id still takes down one delivery; a post id passed there answers is_post_id with the post's deliveries.
| Name | Required | Description | Default |
|---|---|---|---|
| post_id | No | The post id from create_post or list_posts | |
| platform | No | Only take it down here, e.g. `x`. Omit for every platform it is live on. | |
| delivery_id | No | One delivery's `id` from get_delivery_receipt, instead of post_id |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| ok | No | Present and false only on a refusal. |
| data | No | The receipt after the take-down. |
| error | No | What was refused, in a sentence, when `ok` is false. |
| post_id | No | |
| retriable | No | False when asking again cannot change the answer. |
| deliveries | No | Each live delivery's own answer; one platform refusing does not stop the others. |
| error_code | No | Machine reason for a refusal. |
| taken_down | No | Gone from the platform — true, or how many deliveries came down. No undo. |
| post_status | No | |
| replaced_by | No | The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on. |
| preview_link | No | |
| approval_link | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes far beyond basic documentation by detailing the operational semantics of error codes (e.g., distinguishing between 'user removed it' vs. 'platform refused'). This is highly valuable behavioral context not found in the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense and covers many complex operational facets, making it effective, though it is quite lengthy. Every sentence, however, adds critical functional information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the high complexity (multi-platform, multiple ID options, irreversible nature, detailed failure logic), the description is extremely complete, leaving very little for the agent to infer about the tool's constraints and operational flow.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although schema coverage is 100%, the description adds crucial semantic context explaining the functional relationship between `post_id` and `delivery_id`, which helps the agent choose the correct identifier based on its available data.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The purpose is explicitly clear: to delete a live post. It specifies the action and the resource, and uses 'take down' which clearly differentiates it from update or create siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides vital workflow guidance, stating there is 'no need to call get_delivery_receipt first' (direct contrast to a sibling tool) and clearly outlines the irreversible nature of the action ('no undo').
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_postEdit a postADestructiveInspect
Change 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 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.
| Name | Required | Description | Default |
|---|---|---|---|
| files | No | Files the user attached to this conversation, appended after what the post holds. | |
| caption | No | The new text. It must still fit every target's own limit — X is 280 as X counts it — or the edit is refused and the post keeps its old words. | |
| post_id | Yes | The post to change — an id list_posts returned, never one built from memory. Every edit gives the post a NEW id (the answer's `id`); use that one next time. An id an edit retired is refused with `error_code: replaced` and `replaced_by`, the current id. An id this project does not hold is refused with `error_code: not_found`; read the list again rather than trying another id. | |
| is_draft | No | `false` sends a draft: it leaves the drawer and goes out at its time, or now, or to the approval queue — whichever the project does. This is how a draft is finished; creating the post again instead leaves the draft behind and publishes the words twice. `true` puts a post that has not gone out back into the drawer. Omit to keep it as it is. | |
| media_ids | No | Replaces the attachments; omit to keep them. | |
| scheduled_at | No | New time (Z or an offset); "next_slot" hands it to the project's queue; null clears it, and it goes out now — or once approved, on a project that holds agent posts. | |
| add_media_ids | No | Appended after what the post already holds. | |
| platform_configurations | No | Replaces the per-platform options; omit to keep them. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| ok | No | Present and false only on a refusal. |
| error | No | What was refused, in a sentence, when `ok` is false. |
| shown | No | Where this post is already on screen, and that a receipt call now would show it a second time. |
| status | No | pending_approval | scheduled | processing | draft |
| caption | No | |
| message | No | About this post, written to be passed on: why it is held, or that a draft goes nowhere until someone sends it. |
| missing | No | What the post still lacks before it can go out. |
| repeated | No | This idempotency_key was already used — `id` is that earlier post, nothing new was written. |
| replaced | No | update_post: the id of the post this one replaced. That post and its approval link are gone; this post's link stands in for them. |
| timezone | No | |
| plans_url | No | Public page explaining what the plans include. Sent with free_first_post, with publishing_needs_plan, and on a refusal with error_code needs_plan. |
| publishes | No | What has to happen before it goes out. Null on a draft or a rejected post. |
| retriable | No | False when asking again cannot change the answer. |
| attach_now | No | This host cannot send the file: the person adds it in the card, which offers its drop zone straight away. |
| created_at | No | |
| error_code | No | Machine reason for a refusal. |
| plans_link | No | The same page as a ready-made Markdown link. On a refusal with error_code needs_plan, include it in the reply as-is — it is where the person activates a plan. |
| upload_url | No | On a held post: where a picture is POSTed as multipart form-data with a `file` field, no key needed. An environment that holds the file can run `upload_curl`; the person's card uses the same door. |
| connect_url | No | Where an account is connected. On a refusal about an account that is not there. |
| needs_media | No | A draft with no picture or video for a destination that needs one; `missing` names them. It cannot be sent as it stands — attach media with update_post, or the person adds it in xpost. |
| release_url | No | After POSTing every file to upload_url, POST this once and the post goes out. In the card the person presses it instead. |
| replaced_by | No | The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on. |
| upload_curl | No | The upload as one shell command, YOUR_FILE replaced by the path. |
| preview_link | No | A post nobody has to approve, as a ready-made Markdown link to it — the post as each network will draw it, its slot if it has one, and the receipt per account once it has gone. A DRAFT gets one too: it has no slot and nothing is waiting, and the link is the only way the person can see what was written without going to look for it. Give it to the person. |
| queued_posts | No | How many posts are scheduled, none of them going anywhere beyond the free first one. Sent with publishing_needs_plan on a scheduled post. |
| scheduled_at | No | The slot it got. NULL when it waits on approval — never a stand-in time. |
| approval_link | No | A ready-made Markdown link to the post as a page, with Approve and Reject on it. |
| free_post_now | No | Refused only because it was scheduled. The same call with no scheduled_at publishes now, free. |
| pace_warnings | No | Accounts getting more posts in one day than the network likes — it may treat that as spam. Nothing is held. Mention it to the person once and offer to spread the rest out; don't stop to ask on every post. |
| awaiting_media | No | Created without its picture (media_pending). It cannot be approved until one is on it. |
| drafts_waiting | No | How many drafts are now waiting, none of them on its way anywhere. Sent with publishing_needs_plan. |
| free_post_ride | No | With free_first_post: this post reached another of their accounts as part of the same free first post, sent in the same reply. One free delivery per account, within a few minutes of the first. |
| replaced_draft | No | This post FINISHED a draft that held the same words for the same accounts: that draft is gone and this post stands in for it. Say there is one copy. |
| connect_message | No | |
| free_first_post | No | This post is the user's one free post — no plan was needed for it. |
| upload_max_bytes | No | The most `upload_url` takes in one request; bigger files go through the card. |
| releases_on_media | No | Held for its picture only: it goes out on its own once every picture is on it. Nothing to approve. |
| first_post_message | No | About that, written to be passed on; it carries the next step. |
| x_trial_link_limit | No | X will not receive this post: the trial's posts with a link on X are used up. Every other account still gets it. Without the link, X gets it as usual. |
| x_monthly_link_limit | No | X will not receive this post: this month's posts with a link on X are used up on their plan. Every other account still gets it. Without the link, X gets it as usual. |
| publishing_needs_plan | No | Nothing here can publish beyond the one free post: sending needs an xpost subscription. Nothing REFUSES a draft or a scheduled post any more — a queue may be filled without one — so this is the only warning, and it is worth passing on as it is written rather than discovered one slot at a time. |
| free_post_awaiting_approval | No | Refused because their free first post is already waiting for their approval; approval_link opens it. Nothing needs buying. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: it discloses that the response is a NEW post with a new id, that the old id is retired (`replaced`, error_code: replaced / not_found), that editing an approved or rejected post re-enters the approval queue with `message` reporting which, and that an over-limit caption is refused while keeping the old words. These are exactly the consequences destructiveHint=true and idempotentHint=false imply but do not spell out.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the purpose and the id-replacement consequence, and most sentences carry non-obvious information. However, the draft double-post warning appears nearly verbatim twice, and the description is long enough that some density could be trimmed without losing meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need not be explained, and the description nonetheless previews the meaningful response fields (`replaced`, `id`, `message`) and the error codes an agent must handle. For a destructive, non-idempotent, nested-parameter edit tool, nothing needed for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3; the description still adds real semantics by contrasting the three media paths (`add_media_ids`/`files` append, `media_ids` replaces) and by noting that a picture added in the approval card is already on the post. `scheduled_at` and `platform_configurations` are only gestured at, so it stops short of full parameter coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Change a post") plus the crucial qualifier "that has not gone out", and enumerates the editable facets (caption, media, time, per-platform options). It also implies the boundary against create_post and retry_delivery so an agent can tell it apart without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes away from this tool in two cases and names the sibling to use instead: a failed post goes to retry_delivery, and finishing a draft must be done with `is_draft: false` rather than calling create_post again ("posts the words twice"). Both the when and the when-not are stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
upload_mediaAttach a picture, video or PDFAInspect
Attach 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.
| Name | Required | Description | Default |
|---|---|---|---|
| url | No | Public https URL | |
| data | No | The bytes of a small image, video or PDF generated here, base64-encoded, with `mime_type`. A file the user attached travels as `file`, or through the post's `upload_url`, not here. | |
| file | No | A file the user attached to this conversation, as the host hands it over. Absent when the host has no such object. | |
| alt_text | No | Images: accessibility alt text (max 1000 chars). Applied natively on X and Bluesky | |
| mime_type | No | MIME type for `data`, e.g. image/png, video/mp4 | |
| thumbnail_timestamp_ms | No | Videos: cover-frame time in ms into the video |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | Pass in create_post's media_ids. |
| ok | No | Present and false only on a refusal. |
| kind | No | |
| error | No | What was refused, in a sentence, when `ok` is false. |
| retriable | No | False when asking again cannot change the answer. |
| error_code | No | Machine reason for a refusal. |
| people_tags | No | |
| replaced_by | No | The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare the mutation/safety profile (readOnly=false, destructive=false, idempotent=false, openWorld=true), so the description needn't restate that; it adds real context instead — the media_id return, per-platform media requirements, and the graceful degradation path. Only gap is that format/size caps are offloaded to an external URL rather than summarized.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core action and return value are front-loaded in the first sentence, with source details, platform rules and the fallback ordered by decision relevance. Every clause carries information; nothing is restated from the title or schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite six parameters, a nested file object and an output schema, the description covers what an agent needs: which source to pick, what platforms require media, what comes back, and what to do when the file is unreachable. Return-value detail is correctly delegated to the output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, so the baseline is 3; the description goes further by explaining source selection semantics — that host attachments travel as `file` (or the post's upload_url), and that base64 `data` requires a matching `mime_type`. It doesn't explain alt_text or thumbnail_timestamp_ms, but those are self-documenting in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Attach an image, video or PDF') and names the payoff ('get a media_id for create_post'), which also anchors it to the sibling it feeds. An agent can distinguish this from create_post or bulk_post without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly enumerates the three input sources (`file`, https `url`, base64 `data` + `mime_type`), states platform conditions (Instagram/TikTok/YouTube/Pinterest need media; PDF becomes a LinkedIn document), and gives the fallback alternative (`media_pending: true` on the post) when a file cannot travel from here.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
17 tool updates
- Changed
bulk_post1 field changed- changed
Output schema / properties / replaced_by / descriptionPrevious value: -"With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one."New value: +"The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on."
- Changed
create_post1 field changed- changed
Output schema / properties / replaced_by / descriptionPrevious value: -"With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one."New value: +"The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on."
- Changed
delete_post1 field changed- changed
Output schema / properties / replaced_by / descriptionPrevious value: -"With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one."New value: +"The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on."
- Changed
get_best_times1 field changed- changed
Output schema / properties / replaced_by / descriptionPrevious value: -"With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one."New value: +"The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on."
- Changed
get_delivery_receipt1 field changed- changed
Output schema / properties / replaced_by / descriptionPrevious value: -"With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one."New value: +"The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on."
- Changed
get_insights1 field changed- changed
Output schema / properties / replaced_by / descriptionPrevious value: -"With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one."New value: +"The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on."
- Changed
get_post_metrics1 field changed- changed
Output schema / properties / replaced_by / descriptionPrevious value: -"With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one."New value: +"The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on."
- Changed
get_posting_rules1 field changed- changed
Output schema / properties / replaced_by / descriptionPrevious value: -"With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one."New value: +"The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on."
- Changed
get_project1 field changed- changed
Output schema / properties / replaced_by / descriptionPrevious value: -"With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one."New value: +"The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on."
- Changed
get_top_posts1 field changed- changed
Output schema / properties / replaced_by / descriptionPrevious value: -"With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one."New value: +"The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on."
- Changed
list_accounts1 field changed- changed
Output schema / properties / replaced_by / descriptionPrevious value: -"With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one."New value: +"The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on."
- Changed
list_connection_issues1 field changed- changed
Output schema / properties / replaced_by / descriptionPrevious value: -"With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one."New value: +"The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on."
- Changed
list_posts1 field changed- changed
Output schema / properties / replaced_by / descriptionPrevious value: -"With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one."New value: +"The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on."
- Changed
retry_delivery1 field changed- changed
Output schema / properties / replaced_by / descriptionPrevious value: -"With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one."New value: +"The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on."
- Changed
take_down_post1 field changed- changed
Output schema / properties / replaced_by / descriptionPrevious value: -"With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one."New value: +"The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on."
- Changed
update_post1 field changed- changed
Output schema / properties / replaced_by / descriptionPrevious value: -"With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one."New value: +"The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on."
- Changed
upload_media1 field changed- changed
Output schema / properties / replaced_by / descriptionPrevious value: -"With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one."New value: +"The id the post has now, when you asked with one an edit retired. An edit gives a post a new id: get_delivery_receipt and get_post_metrics answer for this current version (and `asked_for` is the id you sent); update_post and delete_post refuse with error_code `replaced`. Use this id from here on."
2 tool updates
- Changed
create_post1 field changed- added
Output schema / properties / x_monthly_link_limitAdded value: +{ + "description": "X will not receive this post: this month's posts with a link on X are used up on their plan. Every other account still gets it. Without the link, X gets it as usual.", + "type": "boolean" +}
- Changed
update_post1 field changed- added
Output schema / properties / x_monthly_link_limitAdded value: +{ + "description": "X will not receive this post: this month's posts with a link on X are used up on their plan. Every other account still gets it. Without the link, X gets it as usual.", + "type": "boolean" +}
2 tool updates
- Changed
get_delivery_receipt1 field changed- added
Output schema / properties / data / items / properties / retry_helpsAdded value: +{ + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "description": "On a failure: false means retry_delivery fails the same way — do what `plain_reason` says instead." +}
- Changed
take_down_post1 field changed- added
Output schema / properties / data / items / properties / retry_helpsAdded value: +{ + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "description": "On a failure: false means retry_delivery fails the same way — do what `plain_reason` says instead." +}
3 tool updates
- Changed
bulk_post2 fields changed- added
Output schema / properties / messageAdded value: +{ + "description": "About the whole batch, written to be passed on — today, accounts it puts past a day's worth of posts.", + "type": "string" +} - added
Output schema / properties / pace_warningsAdded value: +{ + "description": "Accounts getting more posts in one day than the network likes — it may treat that as spam. Nothing is held. Mention it to the person once and offer to spread the rest out; don't stop to ask on every post.", + "items": { + "additionalProperties": {}, + "properties": { + "account_id": { + "type": "string" + }, + "new_account": { + "type": "boolean" + }, + "platform": { + "type": "string" + }, + "posts_within_a_day": { + "type": "number" + }, + "same_site": { + "additionalProperties": {}, + "properties": { + "domain": { + "type": "string" + }, + "posts": { + "type": "number" + } + }, + "type": "object" + }, + "suggested_per_day": { + "type": "number" + }, + "username": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" +}
- Changed
create_post1 field changed- added
Output schema / properties / pace_warningsAdded value: +{ + "description": "Accounts getting more posts in one day than the network likes — it may treat that as spam. Nothing is held. Mention it to the person once and offer to spread the rest out; don't stop to ask on every post.", + "items": { + "additionalProperties": {}, + "properties": { + "account_id": { + "type": "string" + }, + "new_account": { + "type": "boolean" + }, + "platform": { + "type": "string" + }, + "posts_within_a_day": { + "type": "number" + }, + "same_site": { + "additionalProperties": {}, + "properties": { + "domain": { + "type": "string" + }, + "posts": { + "type": "number" + } + }, + "type": "object" + }, + "suggested_per_day": { + "type": "number" + }, + "username": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" +}
- Changed
update_post1 field changed- added
Output schema / properties / pace_warningsAdded value: +{ + "description": "Accounts getting more posts in one day than the network likes — it may treat that as spam. Nothing is held. Mention it to the person once and offer to spread the rest out; don't stop to ask on every post.", + "items": { + "additionalProperties": {}, + "properties": { + "account_id": { + "type": "string" + }, + "new_account": { + "type": "boolean" + }, + "platform": { + "type": "string" + }, + "posts_within_a_day": { + "type": "number" + }, + "same_site": { + "additionalProperties": {}, + "properties": { + "domain": { + "type": "string" + }, + "posts": { + "type": "number" + } + }, + "type": "object" + }, + "suggested_per_day": { + "type": "number" + }, + "username": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" +}
1 tool update
- Changed
get_delivery_receipt3 fields changed- added
Output schema / properties / held_for_pictureAdded value: +{ + "description": "Created with media_pending and not released yet.", + "type": "boolean" +} - added
Output schema / properties / picture_on_itAdded value: +{ + "description": "The picture has landed; only the release call is missing.", + "type": "boolean" +} - added
Output schema / properties / release_urlAdded value: +{ + "description": "POST once, after every picture is on the post, and it goes out on its own.", + "type": "string" +}
1 tool update
- Removed
check_guardrails
3 tool updates
- Changed
create_post1 field changed- removed
Input schema / properties / skip_signatureRemoved value: -{ - "description": "Leave the project's signature off this post. Only when the user asked for that in words.", - "type": "boolean" -}
- Changed
get_posting_rules2 fields changed- changed
Output schema / properties / data / items / properties / limits / properties / caption_chars_available / descriptionPrevious value: -"Caption room left once the project's signature is added."New value: +"Caption room left for your words." - added
Output schema / properties / data / items / properties / posts_left_todayAdded value: +{ + "additionalProperties": {}, + "description": "Absent where the account has no such daily allowance.", + "properties": { + "limit": { + "type": "number" + }, + "remaining": { + "type": "number" + }, + "resets_at": { + "type": "string" + } + }, + "type": "object" +}
- Changed
list_accounts2 fields changed- changed
Output schema / properties / data / items / properties / limits / properties / caption_chars_available / descriptionPrevious value: -"Caption room left once the project's signature is added."New value: +"Caption room left for your words." - added
Output schema / properties / data / items / properties / posts_left_todayAdded value: +{ + "additionalProperties": {}, + "description": "Absent where the account has no such daily allowance.", + "properties": { + "limit": { + "type": "number" + }, + "remaining": { + "type": "number" + }, + "resets_at": { + "type": "string" + } + }, + "type": "object" +}
2 tool updates
- Changed
create_post1 field changed- changed
Output schema / properties / free_post_ride / descriptionPrevious value: -"With free_first_post: this post reached another of their accounts as part of the same free first post, written minutes earlier. One free delivery per account, within half an hour of the first."New value: +"With free_first_post: this post reached another of their accounts as part of the same free first post, sent in the same reply. One free delivery per account, within a few minutes of the first."
- Changed
update_post1 field changed- changed
Output schema / properties / free_post_ride / descriptionPrevious value: -"With free_first_post: this post reached another of their accounts as part of the same free first post, written minutes earlier. One free delivery per account, within half an hour of the first."New value: +"With free_first_post: this post reached another of their accounts as part of the same free first post, sent in the same reply. One free delivery per account, within a few minutes of the first."
18 tool updates
- Changed
bulk_post1 field changed- added
Output schema / properties / replaced_byAdded value: +{ + "description": "With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one.", + "type": "string" +}
- Changed
check_guardrails1 field changed- added
Output schema / properties / replaced_byAdded value: +{ + "description": "With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one.", + "type": "string" +}
- Changed
create_post1 field changed- added
Output schema / properties / replaced_byAdded value: +{ + "description": "With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one.", + "type": "string" +}
- Changed
delete_post1 field changed- added
Output schema / properties / replaced_byAdded value: +{ + "description": "With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one.", + "type": "string" +}
- Changed
get_best_times1 field changed- added
Output schema / properties / replaced_byAdded value: +{ + "description": "With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one.", + "type": "string" +}
- Changed
get_delivery_receipt1 field changed- added
Output schema / properties / replaced_byAdded value: +{ + "description": "With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one.", + "type": "string" +}
- Changed
get_insights1 field changed- added
Output schema / properties / replaced_byAdded value: +{ + "description": "With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one.", + "type": "string" +}
- Changed
get_post_metrics1 field changed- added
Output schema / properties / replaced_byAdded value: +{ + "description": "With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one.", + "type": "string" +}
- Changed
get_posting_rules1 field changed- added
Output schema / properties / replaced_byAdded value: +{ + "description": "With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one.", + "type": "string" +}
- Changed
get_project1 field changed- added
Output schema / properties / replaced_byAdded value: +{ + "description": "With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one.", + "type": "string" +}
- Changed
get_top_posts1 field changed- added
Output schema / properties / replaced_byAdded value: +{ + "description": "With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one.", + "type": "string" +}
- Changed
list_accounts1 field changed- added
Output schema / properties / replaced_byAdded value: +{ + "description": "With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one.", + "type": "string" +}
- Changed
list_connection_issues1 field changed- added
Output schema / properties / replaced_byAdded value: +{ + "description": "With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one.", + "type": "string" +}
- Changed
list_posts1 field changed- added
Output schema / properties / replaced_byAdded value: +{ + "description": "With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one.", + "type": "string" +}
- Changed
retry_delivery1 field changed- added
Output schema / properties / replaced_byAdded value: +{ + "description": "With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one.", + "type": "string" +}
- Changed
take_down_post1 field changed- added
Output schema / properties / replaced_byAdded value: +{ + "description": "With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one.", + "type": "string" +}
- Changed
update_post2 fields changed- changed
Input schema / properties / post_id / descriptionPrevious value: -"The post to change — an id list_posts returned, never one built from memory. An id this project does not hold is refused with `error_code: not_found`; read the list again rather than trying another id."New value: +"The post to change — an id list_posts returned, never one built from memory. Every edit gives the post a NEW id (the answer's `id`); use that one next time. An id an edit retired is refused with `error_code: replaced` and `replaced_by`, the current id. An id this project does not hold is refused with `error_code: not_found`; read the list again rather than trying another id." - added
Output schema / properties / replaced_byAdded value: +{ + "description": "With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one.", + "type": "string" +}
- Changed
upload_media1 field changed- added
Output schema / properties / replaced_byAdded value: +{ + "description": "With error_code `replaced`: the id the post has now. An edit gives a post a new id; use this one.", + "type": "string" +}
2 tool updates
- Changed
create_post3 fields changed- changed
Output schema / properties / drafts_waiting / descriptionPrevious value: -"How many drafts this project now holds, none of them on its way anywhere. Sent with publishing_needs_plan."New value: +"How many drafts are now waiting, none of them on its way anywhere. Sent with publishing_needs_plan." - changed
Output schema / properties / publishing_needs_plan / descriptionPrevious value: -"Nothing on this project can publish beyond its one free post: sending needs a plan. Nothing REFUSES a draft or a scheduled post any more — a queue may be filled without one — so this is the only warning, and it is worth passing on as it is written rather than discovered one slot at a time."New value: +"Nothing here can publish beyond the one free post: sending needs an xpost subscription. Nothing REFUSES a draft or a scheduled post any more — a queue may be filled without one — so this is the only warning, and it is worth passing on as it is written rather than discovered one slot at a time." - changed
Output schema / properties / queued_posts / descriptionPrevious value: -"How many posts are scheduled on this project, none of them going anywhere beyond the free first one. Sent with publishing_needs_plan on a scheduled post."New value: +"How many posts are scheduled, none of them going anywhere beyond the free first one. Sent with publishing_needs_plan on a scheduled post."
- Changed
update_post3 fields changed- changed
Output schema / properties / drafts_waiting / descriptionPrevious value: -"How many drafts this project now holds, none of them on its way anywhere. Sent with publishing_needs_plan."New value: +"How many drafts are now waiting, none of them on its way anywhere. Sent with publishing_needs_plan." - changed
Output schema / properties / publishing_needs_plan / descriptionPrevious value: -"Nothing on this project can publish beyond its one free post: sending needs a plan. Nothing REFUSES a draft or a scheduled post any more — a queue may be filled without one — so this is the only warning, and it is worth passing on as it is written rather than discovered one slot at a time."New value: +"Nothing here can publish beyond the one free post: sending needs an xpost subscription. Nothing REFUSES a draft or a scheduled post any more — a queue may be filled without one — so this is the only warning, and it is worth passing on as it is written rather than discovered one slot at a time." - changed
Output schema / properties / queued_posts / descriptionPrevious value: -"How many posts are scheduled on this project, none of them going anywhere beyond the free first one. Sent with publishing_needs_plan on a scheduled post."New value: +"How many posts are scheduled, none of them going anywhere beyond the free first one. Sent with publishing_needs_plan on a scheduled post."
3 tool updates
- Changed
create_post1 field changed- added
Output schema / properties / plans_linkAdded value: +{ + "description": "The same page as a ready-made Markdown link. On a refusal with error_code needs_plan, include it in the reply as-is — it is where the person activates a plan.", + "type": "string" +}
- Changed
get_project1 field changed- added
Output schema / properties / publishing / properties / plans_linkAdded value: +{ + "description": "The plans page as a ready-made Markdown link. Where `needs_plan` is true, include it as-is.", + "type": "string" +}
- Changed
update_post1 field changed- added
Output schema / properties / plans_linkAdded value: +{ + "description": "The same page as a ready-made Markdown link. On a refusal with error_code needs_plan, include it in the reply as-is — it is where the person activates a plan.", + "type": "string" +}
3 tool updates
- Changed
create_post2 fields changed- changed
Input schema / properties / media_pending / descriptionPrevious value: -"The picture is still to come: the person adds it in the approval card. Lets a post for Instagram, TikTok, YouTube or Pinterest be created without media; it cannot be approved until the media is on it."New value: +"The picture is still to come: the person adds it in the approval card. Lets a post for Instagram, TikTok, YouTube or Pinterest be created without media; it goes out once the media is on it (or, on a project that holds agent posts, can be approved then)." - changed
Input schema / properties / scheduled_at / descriptionPrevious value: -"ISO 8601 with Z or an offset, or \"next_slot\" for the project's own posting schedule (get_project shows `queue`). Omit to go out on approval."New value: +"ISO 8601 with Z or an offset, or \"next_slot\" for the project's own posting schedule (get_project shows `queue`). Omit to publish now — or, on a project that holds agent posts, as soon as it is approved."
- Changed
get_delivery_receipt1 field changed- added
Output schema / properties / made_by_you_just_nowAdded value: +{ + "description": "You created this post minutes ago; its card is already on screen.", + "type": "boolean" +}
- Changed
update_post1 field changed- changed
Input schema / properties / scheduled_at / descriptionPrevious value: -"New time (Z or an offset); \"next_slot\" hands it to the project's queue; null clears it so it goes out once approved."New value: +"New time (Z or an offset); \"next_slot\" hands it to the project's queue; null clears it, and it goes out now — or once approved, on a project that holds agent posts."
2 tool updates
- Changed
create_post1 field changed- added
Output schema / properties / shownAdded value: +{ + "description": "Where this post is already on screen, and that a receipt call now would show it a second time.", + "type": "string" +}
- Changed
update_post1 field changed- added
Output schema / properties / shownAdded value: +{ + "description": "Where this post is already on screen, and that a receipt call now would show it a second time.", + "type": "string" +}
18 tool updates
- First observed
bulk_post - First observed
check_guardrails - First observed
create_post - First observed
delete_post - First observed
get_best_times - First observed
get_delivery_receipt - First observed
get_insights - First observed
get_post_metrics - First observed
get_posting_rules - First observed
get_project - First observed
get_top_posts - First observed
list_accounts - First observed
list_connection_issues - First observed
list_posts - First observed
retry_delivery - First observed
take_down_post - First observed
update_post - First observed
upload_media
Publisher details
- Operator
- xpost (Digital Abstracts SL, Barcelona) · Publisher source
- Operator website
- https://xpost.to · Publisher source
- Vendor relationship
- First-party · Publisher source
- Documentation
- https://xpost.to/docs/mcp · Publisher source
- Trust center
- https://xpost.to/security · Publisher source
- Restrictions
- Needs an xpost account: sign in with OAuth when your client asks, or use an API key from Settings. Every plan includes the MCP server and API; 7-day free trial, then from $12/month. No admin approval, no regional limits, no custom OAuth app needed. · Publisher source
Related MCP Connectors
Draft, approve and schedule social media posts from Claude, ChatGPT, Cursor and other AI apps.
Draft, schedule and publish social posts to nine platforms from any AI agent.
Post, schedule, and track social posts on X, Bluesky, LinkedIn, Instagram and more from AI agents.
The agentic social media scheduler. Write, schedule and publish to all top social platforms.
Related MCP Servers
- AlicenseAqualityBmaintenanceOne prompt, a native post per network, published or scheduled by your agent: TikTok, Instagram, Facebook, YouTube, LinkedIn, Bluesky, Mastodon, Telegram, Discord, Slack, Nostr, X, WordPress, Dev.to, Hashnode. 22 tools incl. plan_week, bulk_schedule, analytics and TikTok video quality check. Priced per brand, not per channel; API + MCP on the free plan. Hosted: postwire.io/api/mcp22414 npmMIT
- AlicenseAqualityCmaintenanceGive any AI agent — Claude, Cursor, Windsurf, or any MCP-compatible client — full control over your social media through natural language.2110 npmMIT
- AlicenseNot gradedqualityBmaintenanceSocial media scheduling and publishing for AI agents. 17 validation-first tools to post to X, LinkedIn, Instagram, TikTok, YouTube, Reddit, Discord, Telegram, and more through one connected workspace.175 npm103MIT
- AlicenseAqualityDmaintenanceAI-powered social media posting across 14 platforms. Post to Twitter, Instagram, TikTok, Facebook, LinkedIn, YouTube and more with one command. AI adapts content per platform, schedules posts, and generates 30-day content calendars.6MIT
Glama MCP Gateway
Add one secure layer between your agents and this server.