← The evidence ledger
Evidence row 309296
Observed , by probe.mcp/1.
- Kind
- mcp.tools
- About
- endpoint 95fb964d-0d0c-48aa-842d-523ff8495d5e
- Recorded
- Previous row
- None: the first of its kind about this subject
- Body SHA-256
- 4656f7beb116b8da7d0e7c493b0d4a36f3c0f4b069379039f85284e7a0e34823
- Leaf
- 0x032017a13797b058c138a3531c03c323bdaaa03c5e78e0e436f19afac4559a3b
What was observed
{
"count": 23,
"tools": [
{
"description": "Connect a social account. Opens the platform in the person's browser so they can sign in and approve access — that part cannot happen here, because it needs their session and their consent. Call it again after they finish and it reports the connected account.\n\nWith `invite`, the link is for someone else instead — a friend or family member who will create a brand-new account and connect it, with no login of their own here. They get a page showing the profile to set up (picture, username, name, bio) with copy buttons, the steps to switch Instagram to a Creator account, and a Connect button. Give the person the `url`. Calling again with the same platform and username returns the same invite, updated with whatever profile fields are given, and its status — so that is also how to check whether they have finished. Upload the profile picture first with media_upload, and pass its id once the PUT succeeds.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"invite": {
"description": "Set to make a link for someone without a login here, who will create the account. Leave out to connect an account yourself.",
"properties": {
"avatar_media_id": {
"description": "An image uploaded with media_upload to use as the profile picture. The invite goes into the same workspace as the image.",
"type": "string"
},
"bio": {
"description": "The profile bio. Instagram caps it at 150 characters.",
"maxLength": 150,
"type": "string"
},
"display_name": {
"description": "The profile name shown above the bio.",
"maxLength": 64,
"type": "string"
},
"username": {
"description": "The handle they should register, without the @. Also what identifies this invite on a repeat call. Instagram allows letters, numbers, periods and underscores, up to 30.",
"maxLength": 31,
"minLength": 1,
"type": "string"
}
},
"required": [
"username"
],
"type": "object"
},
"platform": {
"description": "Which platform to connect.",
"enum": [
"tiktok",
"instagram",
"facebook",
"youtube",
"x"
],
"type": "string"
}
},
"required": [
"platform"
],
"type": "object"
},
"name": "accounts_connect"
},
{
"description": "List every social account you can post to, across all your workspaces. Each account includes the workspace it belongs to and any groups it is in. Use the returned ids to name post destinations explicitly, or a group name to name several at once.\n\nmetrics true adds how each account is performing — followers, posts, total likes and following, each with how far it moved over the period — and orders by followers, largest first. Numbers are as of the last sweep rather than live; every account carries the time it was measured, and one nobody has measured yet has no metrics at all rather than zeroes.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"metrics": {
"description": "Include followers and how they moved. Defaults to false.",
"type": "boolean"
},
"period": {
"description": "With metrics: the window every change is measured over. Defaults to 24h. A change is the difference against the last observation before the window opened, so it is null when there was none.",
"enum": [
"24h",
"7d"
],
"type": "string"
}
},
"type": "object"
},
"name": "accounts_list"
},
{
"description": "Comments on your Facebook and Instagram posts, newest first, replies included. Pass target_id — the id of one destination in a posts_list post's targets — for that delivery's thread, or account_id for everything on one account.\n\nThreads: externalParentId names the externalCommentId of the comment it answers; null is top-level.\n\nauthorKind says who wrote it, as far as the platform would say: \"account\" is the connected account itself (your own reply), \"person\" a named member of the public, and \"withheld\" means the platform would not say — Facebook withholds commenters for now. Withheld is not anonymous; do not report it as such.\n\nRead hourly for a post's first day, daily to a week, weekly to thirty days; lastSeenAt is when each was last confirmed. A comment its author deleted has goneAt set and is left out unless include_gone is true.\n\nWhen nextCursor is not null there are more: pass it as cursor with the same arguments for the next page.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"account_id": {
"description": "One connected account, from accounts_list.",
"type": "string"
},
"comment_id": {
"description": "One comment by its id from an earlier comments_list row. Every other argument is ignored.",
"type": "string"
},
"cursor": {
"description": "nextCursor from the previous page, for the page after it.",
"type": "string"
},
"include_gone": {
"description": "Include comments deleted since they were read.",
"type": "boolean"
},
"limit": {
"description": "How many to return. Defaults to 50.",
"maximum": 200,
"minimum": 1,
"type": "integer"
},
"target_id": {
"description": "One delivery: the id of a destination in a posts_list post's targets.",
"type": "string"
}
},
"type": "object"
},
"name": "comments_list"
},
{
"description": "Reply to a comment on one of your posts. The reply is posted publicly, immediately, in that account's name, and cannot be unsent from here.\n\ncomment_id is a comments_list row's id, not the platform's. The reply is threaded under that comment.\n\nIt returns status \"sent\" only when the platform gave the reply an id. \"pending\" means the platform did not answer and the outcome is unknown: it is confirmed within the hour, and retrying with the same idempotency_key is safe and will not post twice.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"comment_id": {
"description": "The comment to answer, from comments_list.",
"type": "string"
},
"idempotency_key": {
"description": "Reuse on retry to avoid replying twice; returns the original reply. Reusing it with different words is refused.",
"type": "string"
},
"message": {
"description": "What to say, as written.",
"minLength": 1,
"type": "string"
}
},
"required": [
"comment_id",
"message"
],
"type": "object"
},
"name": "comments_reply"
},
{
"description": "Remove a group. The accounts in it are not touched and stay connected — only the name and its membership go. Posts already scheduled through it are unaffected, because a post records the accounts rather than the group.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"name": {
"description": "The group to remove, from groups_list.",
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"name": "groups_delete"
},
{
"description": "Your named sets of accounts. Each group lists its members with the state of each, and how many of them need reconnecting — a post naming a group is refused outright if any member cannot publish, so check here before composing one. Use a group name with posts_save instead of listing account ids.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {},
"type": "object"
},
"name": "groups_list"
},
{
"description": "Create a group or change one. A group is a name for a set of accounts, so posts_save can take the name instead of every id. Found by name without regard to case: an existing group is updated (new_name renames it), and a new name creates one, which needs account_ids. account_ids is always the full membership afterwards, not a list to add. All the accounts must be in one workspace.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"account_ids": {
"description": "The complete membership, from accounts_list — whatever is sent replaces what was there. Required to create a group; omit it to leave an existing group’s members alone.",
"items": {
"type": "string"
},
"type": "array"
},
"description": {
"description": "What it is for, so it can be chosen without reading it.",
"type": "string"
},
"name": {
"description": "The group, matched without regard to case. Created when there is none by this name.",
"type": "string"
},
"new_name": {
"description": "Rename an existing group to this.",
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"name": "groups_save"
},
{
"description": "Remove a file and its stored bytes. This cannot be undone. A file a post still uses cannot be removed, and neither can raw material kept with purpose source: switch it to library with media_save first.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
"name": "media_delete"
},
{
"description": "Files in your workspaces, newest first, 50 at a time. Use these ids when attaching media to a post. By default these are the files to post; purpose: source lists the raw material kept to reuse instead. Narrow with kind, tags (files carrying every one) or search (words in the description or tags), or pass media_id for one file of either purpose. Each file has a url to download it from. When nextCursor is not null, pass it as cursor for the next page.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"cursor": {
"description": "nextCursor from the previous page, for the page after it.",
"type": "string"
},
"kind": {
"description": "Only this kind of file.",
"enum": [
"image",
"video",
"audio"
],
"type": "string"
},
"limit": {
"description": "How many to return. Defaults to 50.",
"maximum": 200,
"minimum": 1,
"type": "integer"
},
"media_id": {
"description": "One file by id. Every other argument is ignored.",
"type": "string"
},
"purpose": {
"description": "library, the default: files to post. source: raw material kept to reuse — generated takes, recordings, sound effects, saved memes.",
"enum": [
"library",
"source"
],
"type": "string"
},
"search": {
"description": "Words in the description or the tags, ignoring case.",
"type": "string"
},
"tags": {
"description": "Only files carrying every one of these tags.",
"items": {
"maxLength": 40,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"minItems": 1,
"type": "array"
}
},
"type": "object"
},
"name": "media_list"
},
{
"description": "Say what a file is, in your own words. description is what it shows: on a base image, who is on camera — \"a woman in her early twenties, blonde hair in a loose bun\" — and a campaign reads it so the same person appears in every render instead of changing between them. tags are labels to filter by, like sound-effect; metadata is how it was made — provider, model, prompt, jobId, costUsd, sourceUrl, ref, inputs. Each replaces what is there: null clears a description or metadata, [] clears tags. purpose switches a file between library, to post, and source, raw material kept to reuse. For several files at once, items, up to 50: a file not recorded yet comes back in not_found, to save once media_list shows it. Nothing else about a file can be changed here; what it is was read from the file itself.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "What the file shows, in your own words, or null to remove the words already there."
},
"id": {
"description": "The file to change. For several, use items instead.",
"type": "string"
},
"items": {
"description": "Several files at once, each an id and what to change. Only files that have arrived are changed; the rest come back in not_found.",
"items": {
"properties": {
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "What the file shows, in your own words, or null to remove the words already there."
},
"id": {
"type": "string"
},
"metadata": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"costUsd": {
"description": "What the job cost or was quoted, in US dollars.",
"minimum": 0,
"type": "number"
},
"inputs": {
"description": "Ids of the files it was made from, such as a starting still.",
"items": {
"maxLength": 64,
"minLength": 1,
"type": "string"
},
"maxItems": 10,
"type": "array"
},
"jobId": {
"description": "The provider's id for the job, to find it again there.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"model": {
"description": "The model, as the provider names it.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"prompt": {
"description": "The prompt it was made from, exactly as sent.",
"maxLength": 8000,
"minLength": 1,
"type": "string"
},
"provider": {
"description": "Who made it: higgsfield, fal, memelord, a phone.",
"maxLength": 40,
"minLength": 1,
"type": "string"
},
"ref": {
"description": "The creative it was made for, e.g. PB-CR07.",
"maxLength": 60,
"minLength": 1,
"type": "string"
},
"sourceUrl": {
"description": "Where a file saved from the web was found.",
"format": "uri",
"maxLength": 2000,
"type": "string"
}
},
"type": "object"
},
{
"type": "null"
}
],
"description": "How it was made, replacing what is there, or null to remove it."
},
"purpose": {
"description": "library, the default: a file to post. source: raw material kept to find and reuse — a generated take, a recording, a sound effect, a saved meme. A source file is listed only when asked for, and is never posted or picked up by a campaign as it is.",
"enum": [
"library",
"source"
],
"type": "string"
},
"tags": {
"description": "Labels to filter by, replacing those there. [] removes them all.",
"items": {
"maxLength": 40,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array"
}
},
"required": [
"id"
],
"type": "object"
},
"maxItems": 50,
"minItems": 1,
"type": "array"
},
"metadata": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"costUsd": {
"description": "What the job cost or was quoted, in US dollars.",
"minimum": 0,
"type": "number"
},
"inputs": {
"description": "Ids of the files it was made from, such as a starting still.",
"items": {
"maxLength": 64,
"minLength": 1,
"type": "string"
},
"maxItems": 10,
"type": "array"
},
"jobId": {
"description": "The provider's id for the job, to find it again there.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"model": {
"description": "The model, as the provider names it.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"prompt": {
"description": "The prompt it was made from, exactly as sent.",
"maxLength": 8000,
"minLength": 1,
"type": "string"
},
"provider": {
"description": "Who made it: higgsfield, fal, memelord, a phone.",
"maxLength": 40,
"minLength": 1,
"type": "string"
},
"ref": {
"description": "The creative it was made for, e.g. PB-CR07.",
"maxLength": 60,
"minLength": 1,
"type": "string"
},
"sourceUrl": {
"description": "Where a file saved from the web was found.",
"format": "uri",
"maxLength": 2000,
"type": "string"
}
},
"type": "object"
},
{
"type": "null"
}
],
"description": "How it was made, replacing what is there, or null to remove it."
},
"purpose": {
"description": "library, the default: a file to post. source: raw material kept to find and reuse — a generated take, a recording, a sound effect, a saved meme. A source file is listed only when asked for, and is never posted or picked up by a campaign as it is.",
"enum": [
"library",
"source"
],
"type": "string"
},
"tags": {
"description": "Labels to filter by, replacing those there. [] removes them all.",
"items": {
"maxLength": 40,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array"
}
},
"type": "object"
},
"name": "media_save"
},
{
"description": "Get a file into ViewPrinter, under an id you can pass to posts_save, media_save or anything else that takes a media id.\n\nIf the person attached the file in this chat, or has it on their phone or computer, call this with no arguments, as an ordinary tool call — not from code, and without trying to send the file yourself. Apps that show widgets put an upload box under the call, which sends the file to ViewPrinter directly even when you have no network access: tell the person to use it. It takes one video or up to ten photos and posts their media ids to the chat, in order, when they are in. Where no box appears, give the person `upload_page`: any device, no sign-in, lasts an hour.\n\nOnly if you hold the file yourself and can make HTTP requests (a terminal agent, a server), pass kind and mime_type and PUT the bytes to `url` with exactly the `headers` returned. Apps that show widgets never get `url`: the upload box is the way there. Add sha256 (hex) and a file this workspace already has comes back as existing: true, with nothing to upload.\n\nIf the file is already on the web — a model’s output link, a meme’s direct link — pass from_url instead, with any description, tags and metadata: ViewPrinter fetches it itself and answers fetching: true straight away. It is recorded within minutes; check with media_list and media_id, and if it never appears the link could not be fetched.\n\npurpose: source keeps raw material — a generated take, a recording, a sound effect, a saved meme — to find and reuse later. media_list shows it only when asked for purpose source, and it is never posted or used by a campaign as it is.\n\nSeveral files at once: items, up to 50, each as you would pass one; the answers come back in items, in order.\n\nEither way the file lands under `id` and is recorded as soon as it arrives. With the box or the page, wait for the person before using it.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"description": {
"description": "With from_url: what the file shows, in your own words.",
"maxLength": 8000,
"minLength": 1,
"type": "string"
},
"from_url": {
"description": "A file already on the web — a model’s output link, a meme’s direct link. ViewPrinter fetches it itself; there is nothing to PUT.",
"format": "uri",
"type": "string"
},
"items": {
"description": "Several files at once, each as you would pass one. The answers come back in items, in the same order.",
"items": {
"properties": {
"description": {
"description": "With from_url: what the file shows, in your own words.",
"maxLength": 8000,
"minLength": 1,
"type": "string"
},
"from_url": {
"description": "A file already on the web — a model’s output link, a meme’s direct link. ViewPrinter fetches it itself; there is nothing to PUT.",
"format": "uri",
"type": "string"
},
"kind": {
"description": "What the file is. With mime_type when you hold the file. With from_url it is optional, and checked against what the link serves.",
"enum": [
"image",
"video",
"audio"
],
"type": "string"
},
"metadata": {
"additionalProperties": false,
"description": "With from_url: how it was made — model, prompt, cost and so on.",
"properties": {
"costUsd": {
"description": "What the job cost or was quoted, in US dollars.",
"minimum": 0,
"type": "number"
},
"inputs": {
"description": "Ids of the files it was made from, such as a starting still.",
"items": {
"maxLength": 64,
"minLength": 1,
"type": "string"
},
"maxItems": 10,
"type": "array"
},
"jobId": {
"description": "The provider's id for the job, to find it again there.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"model": {
"description": "The model, as the provider names it.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"prompt": {
"description": "The prompt it was made from, exactly as sent.",
"maxLength": 8000,
"minLength": 1,
"type": "string"
},
"provider": {
"description": "Who made it: higgsfield, fal, memelord, a phone.",
"maxLength": 40,
"minLength": 1,
"type": "string"
},
"ref": {
"description": "The creative it was made for, e.g. PB-CR07.",
"maxLength": 60,
"minLength": 1,
"type": "string"
},
"sourceUrl": {
"description": "Where a file saved from the web was found.",
"format": "uri",
"maxLength": 2000,
"type": "string"
}
},
"type": "object"
},
"mime_type": {
"description": "The exact Content-Type your PUT will send, e.g. video/mp4. Only with kind, when you hold the file.",
"type": "string"
},
"purpose": {
"description": "library, the default: a file to post. source: raw material kept to find and reuse — a generated take, a recording, a sound effect, a saved meme. A source file is listed only when asked for, and is never posted or picked up by a campaign as it is.",
"enum": [
"library",
"source"
],
"type": "string"
},
"sha256": {
"description": "When you hold the file: its SHA-256, as hex. If this workspace already has the file, the answer is its id with existing: true and nothing to upload. Otherwise the PUT must carry the headers the answer gives, and storage refuses bytes that do not match.",
"pattern": "^[0-9a-f]{64}$",
"type": "string"
},
"tags": {
"description": "With from_url: labels to filter by, e.g. sound-effect.",
"items": {
"maxLength": 40,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array"
}
},
"type": "object"
},
"maxItems": 50,
"minItems": 1,
"type": "array"
},
"kind": {
"description": "What the file is. With mime_type when you hold the file. With from_url it is optional, and checked against what the link serves.",
"enum": [
"image",
"video",
"audio"
],
"type": "string"
},
"metadata": {
"additionalProperties": false,
"description": "With from_url: how it was made — model, prompt, cost and so on.",
"properties": {
"costUsd": {
"description": "What the job cost or was quoted, in US dollars.",
"minimum": 0,
"type": "number"
},
"inputs": {
"description": "Ids of the files it was made from, such as a starting still.",
"items": {
"maxLength": 64,
"minLength": 1,
"type": "string"
},
"maxItems": 10,
"type": "array"
},
"jobId": {
"description": "The provider's id for the job, to find it again there.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"model": {
"description": "The model, as the provider names it.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"prompt": {
"description": "The prompt it was made from, exactly as sent.",
"maxLength": 8000,
"minLength": 1,
"type": "string"
},
"provider": {
"description": "Who made it: higgsfield, fal, memelord, a phone.",
"maxLength": 40,
"minLength": 1,
"type": "string"
},
"ref": {
"description": "The creative it was made for, e.g. PB-CR07.",
"maxLength": 60,
"minLength": 1,
"type": "string"
},
"sourceUrl": {
"description": "Where a file saved from the web was found.",
"format": "uri",
"maxLength": 2000,
"type": "string"
}
},
"type": "object"
},
"mime_type": {
"description": "The exact Content-Type your PUT will send, e.g. video/mp4. Only with kind, when you hold the file.",
"type": "string"
},
"purpose": {
"description": "library, the default: a file to post. source: raw material kept to find and reuse — a generated take, a recording, a sound effect, a saved meme. A source file is listed only when asked for, and is never posted or picked up by a campaign as it is.",
"enum": [
"library",
"source"
],
"type": "string"
},
"sha256": {
"description": "When you hold the file: its SHA-256, as hex. If this workspace already has the file, the answer is its id with existing: true and nothing to upload. Otherwise the PUT must carry the headers the answer gives, and storage refuses bytes that do not match.",
"pattern": "^[0-9a-f]{64}$",
"type": "string"
},
"tags": {
"description": "With from_url: labels to filter by, e.g. sound-effect.",
"items": {
"maxLength": 40,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array"
}
},
"type": "object"
},
"name": "media_upload"
},
{
"description": "Direct messages sent to your Instagram and Facebook accounts, newest conversation first. Call with no argument for the inbox, account_id for one account, or conversation_id for one thread and its messages.\n\nOne conversation is one person on one of your accounts: the platforms carry no thread id, so the person is the thread.\n\nreplyUntil is the deadline for answering and it is the point of this tool. Meta allows a reply within 24 hours of their last message and refuses after it, so a null replyUntil means a reply will be rejected however good it is — say so rather than drafting one. closesInSeconds counts down to the same moment.\n\nparticipant may be null. The webhook carries ids and no names, so an unnamed person is the platform not saying, not an anonymous one — do not report them as anonymous.\n\nfromUs marks our own messages, which include replies sent from the platform's own app. A message the sender unsent has gone set and keeps its place, so a reply still reads in order.\n\nThe inbox comes 50 conversations at a time; when nextCursor is not null, pass it as cursor with the same arguments for more.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"account_id": {
"description": "One connected account, from accounts_list.",
"type": "string"
},
"conversation_id": {
"description": "One thread, from a previous messages_list row. Returns its messages oldest first.",
"type": "string"
},
"cursor": {
"description": "nextCursor from the previous page, for the page after it.",
"type": "string"
},
"limit": {
"description": "How many conversations to return. Defaults to 50.",
"maximum": 200,
"minimum": 1,
"type": "integer"
},
"unread_only": {
"description": "Only conversations where they wrote last.",
"type": "boolean"
}
},
"type": "object"
},
"name": "messages_list"
},
{
"description": "Send a direct message, privately, in the account's name. Name exactly one of conversation_id or comment_id.\n\nconversation_id answers a thread from messages_list, and only while its replyUntil has not passed — Meta allows a reply within 24 hours of their last message and refuses after it.\n\ncomment_id opens a thread from a comment in comments_list: somebody who comments on your post can be messaged once, within 7 days. One message, not a conversation — they have to answer before you may send another. Use it when a comment needs an answer that does not belong in public.\n\nYou can never message someone first. If they have neither written nor commented, there is no way to reach them and no permission that grants one.\n\nThis is private and comments_reply is public. Answering in the wrong one either exposes something meant for one person or hides an answer everyone was waiting for.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"comment_id": {
"description": "A comment from comments_list. Sends its author one private message.",
"type": "string"
},
"conversation_id": {
"description": "A thread from messages_list. Answers it.",
"type": "string"
},
"message": {
"description": "What to say.",
"minLength": 1,
"type": "string"
}
},
"required": [
"message"
],
"type": "object"
},
"name": "messages_reply"
},
{
"description": "What each platform accepts. Called with nothing, it lists every platform with the media kinds and counts it takes and its caption limit — enough to decide where a post can go. Name platforms to add their recommended sizes and durations, their options with what each one does, and the quirks that decide how a post is treated. Read this before scheduling rather than discovering the rules by being rejected.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"platforms": {
"description": "Which platforms to describe in full. Omit for a short answer covering all of them. Naming only the platforms you are posting to keeps the reply small — full detail for all of them is several times the size.",
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"name": "platforms_list"
},
{
"description": "Posts in your workspaces, newest first, one page at a time, each with the state of every destination it was sent to and the numbers it has earned so far. Call it to find one post (post_id), to check whether something published, and before changing or cancelling anything — posts_save takes a post_id from here.\n\nNumbers are as of the last sweep, and every destination carries the time it was measured — one nobody has measured yet has no metrics at all rather than zeroes.\n\n`trial` names an Instagram trial reel's graduation strategy, and is null for anything that is not one. A trial is shown to non-followers first, so its numbers come from a colder audience than an ordinary post's: compare trials with trials.\n\nEach row also carries `insights`: what the platform's own analytics said on that delivery, never summed across deliveries. reach (distinct accounts), totalWatchMs and avgWatchMs, replays, follows (gained from the post), completionRate and skipRate as fractions 0..1, `retention` — the full audience-retention curve as Facebook sends it, `points[i]` being the share still watching at i twentieths of the video and `bucketMs` one twentieth in milliseconds — and `breakdowns` such as clicks by type. retentionAt3s and retentionAtHalf are read off that curve, interpolated between buckets, so hooks can be ranked by how many viewers they held; null without a curve or a known video length. Null means the platform does not report it; a name listed in `unavailable` means it would have and refused this time. Compare watch time across platforms as totalWatchMs / views: Facebook averages per play and Instagram per viewer, so avgWatchMs is not comparable between them.\n\nEvery filter is optional and they combine: a date range, statuses, platforms, accounts, groups and products by name, where the post came from, and a caption search. Pass nextCursor back as cursor for the next page; null means there is no more.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"account_id": {
"description": "Accounts by id, from accounts_list.",
"items": {
"type": "string"
},
"type": "array"
},
"by": {
"description": "With rank_by: the running total, or how much it moved over the period. Defaults to the total. Insights rank by value only.",
"enum": [
"value",
"change"
],
"type": "string"
},
"cursor": {
"description": "nextCursor from the previous page.",
"type": "string"
},
"from": {
"description": "ISO date or date-time. Only posts that went out, or are due to, at or after this.",
"type": "string"
},
"group": {
"description": "Groups by name, from groups_list: posts to any of their accounts.",
"items": {
"type": "string"
},
"type": "array"
},
"limit": {
"description": "Posts per page. Defaults to 25.",
"maximum": 100,
"minimum": 1,
"type": "integer"
},
"order": {
"description": "Defaults to desc.",
"enum": [
"asc",
"desc"
],
"type": "string"
},
"period": {
"description": "The window each figure's change is measured over. Defaults to 24h.",
"enum": [
"24h",
"7d"
],
"type": "string"
},
"platform": {
"items": {
"enum": [
"tiktok",
"instagram",
"facebook",
"x",
"youtube",
"linkedin"
],
"type": "string"
},
"type": "array"
},
"post_id": {
"description": "One post by id. The other filters are ignored.",
"type": "string"
},
"product": {
"description": "Products by name or id: posts to accounts linked to them.",
"items": {
"type": "string"
},
"type": "array"
},
"rank_by": {
"description": "Rank the matching posts by one figure of their best destination instead: any counter (views, likes, …) or insight (reach, avgWatchMs, completionRate, retentionAt3s, retentionAtHalf, …). Answers \"which hooks held viewers\" or \"what is moving now\". Ranks up to 500 matching posts; no cursor.",
"enum": [
"views",
"likes",
"comments",
"shares",
"saves",
"reach",
"totalWatchMs",
"avgWatchMs",
"replays",
"follows",
"completionRate",
"retentionAt3s",
"retentionAtHalf"
],
"type": "string"
},
"search": {
"description": "Text the caption contains, ignoring case.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"sort_by": {
"description": "A counter or insight (views, likes, …), \"when\", \"updated\" or \"account\". Defaults to newest first.",
"enum": [
"views",
"likes",
"comments",
"shares",
"saves",
"reach",
"totalWatchMs",
"replays",
"follows",
"when",
"updated",
"account"
],
"type": "string"
},
"source": {
"description": "Where a post came from. external is one made on the platform itself and found afterwards.",
"items": {
"enum": [
"web",
"mcp",
"api",
"campaign",
"external"
],
"type": "string"
},
"type": "array"
},
"status": {
"description": "published, scheduled, draft, failed or cancelled. A post matches when any of its destinations is in one of these states.",
"items": {
"enum": [
"published",
"scheduled",
"draft",
"failed",
"cancelled"
],
"type": "string"
},
"type": "array"
},
"to": {
"description": "ISO date or date-time. Only posts before this.",
"type": "string"
}
},
"type": "object"
},
"name": "posts_list"
},
{
"description": "Create, change or cancel a post. This publishes: a new post is queued for every account named and goes out at scheduled_at, or as soon as possible without one. Do not tell anyone their post is saved or scheduled until this has returned successfully.\n\nNo post_id creates a post. Name accounts with ids from accounts_list, or a group from groups_list for all of its members — the two combine, and a group is expanded now, so adding an account to it later does not add it to this post. Accounts must all be in one workspace. Attach media by id from media_list; a post is either a video or a set of images, never both. draft true holds it here without sending anything.\n\nWith post_id, changes a post that has not gone out: caption, time, destinations, or draft state. account_ids and groups then replace the destination list entirely. draft false sends a draft. Setting scheduled_at on a post whose destinations failed queues the failed ones again and leaves the published ones alone — fix what made them fail first, usually by reconnecting. The caption and destinations can only change while nothing has published; after that only the time can, and new words mean a new post.\n\nWith post_id and cancel true, stops it: destinations that have not started are cancelled, and any already being published cannot be recalled and come back in still_going. Safe to repeat.\n\nPublishing has to be enabled on the account; where it is not, a new post saves nothing at all and a draft is left as it was, and the answer says so. Cancelling works whether or not publishing is enabled.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"account_ids": {
"description": "Accounts to post to, from accounts_list. On a new post, optional when groups is given; naming neither is refused. On an existing post, replaces the destinations — send every account you want.",
"items": {
"type": "string"
},
"type": "array"
},
"cancel": {
"description": "With post_id: stop the post before it goes out.",
"type": "boolean"
},
"content": {
"description": "The caption.",
"type": "string"
},
"draft": {
"description": "True holds the post here: nothing is queued and nothing reaches any platform. On an existing post, false sends a draft and true returns a scheduled post to draft. Unrelated to the per-platform draft option, which uploads to the platform for the creator to finish.",
"type": "boolean"
},
"groups": {
"description": "Group names from groups_list, expanded to their members and combined with account_ids. Matched without regard to case.",
"items": {
"type": "string"
},
"type": "array"
},
"idempotency_key": {
"description": "New posts only. Reuse on retry to avoid posting twice; returns the original post.",
"type": "string"
},
"media_ids": {
"description": "New posts only. Files to attach, in order — the slideshow order.",
"items": {
"type": "string"
},
"type": "array"
},
"platform_options": {
"description": "New posts only. Per-platform settings, keyed by platform. Only the keys shown are accepted — an unknown key is refused rather than ignored. Call platforms_list for what each one does, its default, and which kind of post it applies to.",
"properties": {
"facebook": {
"additionalProperties": false,
"properties": {},
"type": "object"
},
"instagram": {
"additionalProperties": false,
"properties": {
"coverUrl": {
"format": "uri",
"type": "string"
},
"isAiGenerated": {
"type": "boolean"
},
"shareToFeed": {
"type": "boolean"
},
"story": {
"type": "boolean"
},
"thumbOffset": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"trialReel": {
"enum": [
"SS_PERFORMANCE",
"MANUAL"
],
"type": "string"
}
},
"type": "object"
},
"tiktok": {
"additionalProperties": false,
"properties": {
"autoAddMusic": {
"type": "boolean"
},
"brandContentToggle": {
"type": "boolean"
},
"brandOrganicToggle": {
"type": "boolean"
},
"disableComment": {
"type": "boolean"
},
"disableDuet": {
"type": "boolean"
},
"disableStitch": {
"type": "boolean"
},
"draft": {
"type": "boolean"
},
"isAigc": {
"type": "boolean"
},
"photoCoverIndex": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
},
"privacyLevel": {
"enum": [
"PUBLIC_TO_EVERYONE",
"MUTUAL_FOLLOW_FRIENDS",
"FOLLOWER_OF_CREATOR",
"SELF_ONLY"
],
"type": "string"
},
"title": {
"maxLength": 90,
"type": "string"
},
"videoCoverTimestampMs": {
"maximum": 9007199254740991,
"minimum": 0,
"type": "integer"
}
},
"type": "object"
},
"x": {
"additionalProperties": false,
"properties": {},
"type": "object"
},
"youtube": {
"additionalProperties": false,
"properties": {
"categoryId": {
"type": "string"
},
"containsSyntheticMedia": {
"type": "boolean"
},
"madeForKids": {
"type": "boolean"
},
"privacy": {
"enum": [
"public",
"unlisted",
"private"
],
"type": "string"
},
"tags": {
"items": {
"type": "string"
},
"type": "array"
},
"title": {
"type": "string"
}
},
"type": "object"
}
},
"type": "object"
},
"post_id": {
"description": "A post to change or cancel, from posts_list. Omit to create one.",
"type": "string"
},
"scheduled_at": {
"description": "ISO 8601. Omit to send as soon as possible. A time in the past sends as soon as possible.",
"type": "string"
}
},
"type": "object"
},
"name": "posts_save"
},
{
"description": "Delete a product. Its accounts stay connected and belong to no product afterwards. Refused while it has campaigns. Its knowledge documents and gathered research are deleted with it, so this is refused while it has any unless confirm_discard is true — read the refusal, which says how many would go, before confirming.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"confirm_discard": {
"type": "boolean"
},
"id": {
"description": "The product, from products_list.",
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
"name": "products_delete"
},
{
"description": "The products your accounts post for — an app, a book, a shop — each with the accounts linked to it and the workspace it is in. An account belongs to at most one product. Use products_save to create one or change which accounts belong to it.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {},
"type": "object"
},
"name": "products_list"
},
{
"description": "Create a product, or change one. Found by id when given, otherwise by name (ignoring case) and created when there is none, so saving the same product twice changes nothing the second time.\n\naccount_ids is the complete list of accounts that post for it: accounts in another product move here, and accounts in this one that are not listed leave it. Leave it out to keep the accounts as they are. A product holds accounts from one workspace; when you are in several and name no accounts, pass workspace_id (from accounts_list).",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"account_ids": {
"description": "Every account that posts for it, from accounts_list.",
"items": {
"type": "string"
},
"type": "array"
},
"description": {
"description": "What it is, in a sentence or two.",
"maxLength": 500,
"type": "string"
},
"id": {
"description": "An existing product to change, from products_list.",
"type": "string"
},
"name": {
"description": "The name, or the new name when id is given.",
"maxLength": 80,
"minLength": 1,
"type": "string"
},
"workspace_id": {
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"name": "products_save"
},
{
"description": "Ask a question about your niche and get back the posts that answer it, from TikTok and Instagram unless platforms narrows it. Give question and product_id and it starts searching for that question, which takes a few minutes, and returns at once with a thread_id and status working. Call it again with just the thread_id, about every 15 seconds, until status is ready; then posts are the answer, best first. Each has its URL, caption, hashtags, views, likes, comments, shares and saves, the creator’s follower count, and outperformance: views as a multiple of that creator’s median over the posts we hold of theirs, null when we hold too few. fit says how well a post suits your product (in_niche, adjacent, off_topic) and posts judged off-topic are left out unless you ask for all. A thread takes one question at a time: asking again while it is working does not start a new one. With a failed status, ask the question again. Starting a question uses search credit, so do not repeat one that is working. With neither question nor thread_id it reads what is already indexed, instantly. A post we have watched also carries hook, genre, format and repeatableStructure (null until watched), and a question’s answer gives each post a why: one line on what the video is and how it was judged. The top-level formats and ideas are empty for now.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"fit": {
"description": "How closely a post must fit your product. relevant (default) drops posts judged off-topic and keeps ones not judged yet; in_niche keeps only judged in-niche posts; all keeps everything.",
"enum": [
"relevant",
"in_niche",
"all"
],
"type": "string"
},
"include_ads": {
"description": "Include posts the platform marks as paid promotion or a paid partnership. Default false.",
"type": "boolean"
},
"language": {
"description": "Only this language, as a two-letter code such as en. Posts whose language the platform could not tell are kept.",
"maxLength": 5,
"minLength": 2,
"type": "string"
},
"limit": {
"description": "How many posts. Default 10.",
"maximum": 50,
"minimum": 1,
"type": "integer"
},
"medium": {
"description": "Only videos, or only slideshows.",
"enum": [
"video",
"slideshow"
],
"type": "string"
},
"platforms": {
"description": "Which platforms to search and answer from: tiktok, instagram, or both. Default both.",
"items": {
"enum": [
"tiktok",
"instagram"
],
"type": "string"
},
"minItems": 1,
"type": "array"
},
"product_id": {
"description": "The product this is for, from products_list. Required with a question. Without one, narrows the index read to this product.",
"type": "string"
},
"question": {
"description": "What you want to know, in plain words, as you would ask a researcher. Starts a new search for it. Needs product_id.",
"maxLength": 2000,
"type": "string"
},
"since": {
"description": "Posted on or after this ISO 8601 time. Default: 7 days ago for an index read, 30 days for a question’s answer.",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"type": "string"
},
"thread_id": {
"description": "A thread from an earlier call. Alone, it returns where that question is, or its answer once ready. With a question, it asks a follow-up on the same thread once the last one is done.",
"type": "string"
}
},
"type": "object"
},
"name": "research_ask"
},
{
"description": "Stop a webhook. Events already on their way may still arrive.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"id": {
"description": "The webhook, from webhooks_list.",
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
"name": "webhooks_delete"
},
{
"description": "The webhooks set up in your workspaces: where each one delivers, which events, any product or account filter, and whether it is working. status \"paused\" means too many deliveries in a row failed; lastError says why, and webhooks_save with its id resumes it. hasAuthHeader says whether a credential is set, never what it is.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {},
"type": "object"
},
"name": "webhooks_list"
},
{
"description": "Ask to be told when something happens: each matching event is POSTed as JSON to your https URL within seconds. Create one, or change one by id — saving also resumes a paused webhook.\n\nEvents are thin: a type, a stable id, the workspace, product and account, and the ids to look things up by — never the comment or message text. On comment.created, read it with comments_list comment_id and answer with comments_reply or messages_reply comment_id before privateReplyUntil. On message.received, read the thread with messages_list conversation_id and answer before replyUntil.\n\nAnswer 2xx within 10 seconds. A failed delivery is retried three times over about twenty minutes, so the same event id can arrive more than once: ignore ids you have already handled. Only comments and messages from the last day are announced.\n\nauth_header is sent as the Authorization header on every delivery, for an endpoint that expects a credential (e.g. \"Bearer …\"). It is stored encrypted and never shown again; null removes it.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"account_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only events about this account, from accounts_list. null for every account."
},
"auth_header": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"events": {
"description": "Which events to send.",
"items": {
"enum": [
"comment.created",
"message.received"
],
"type": "string"
},
"minItems": 1,
"type": "array"
},
"id": {
"description": "An existing webhook to change, from webhooks_list.",
"type": "string"
},
"product_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only events about this product, from products_list. null for every product."
},
"url": {
"description": "Where to POST. https only.",
"type": "string"
},
"workspace_id": {
"description": "Which workspace, when you are in several and give no product or account.",
"type": "string"
}
},
"required": [
"url",
"events"
],
"type": "object"
},
"name": "webhooks_save"
}
]
}What the leaf hashes
{"body":"4656f7beb116b8da7d0e7c493b0d4a36f3c0f4b069379039f85284e7a0e34823","id":309296,"kind":"mcp.tools","method":"probe.mcp/1","observed_us":1793058801471029,"prev":null,"subject":"95fb964d-0d0c-48aa-842d-523ff8495d5e","subject_kind":"endpoint"}Proof
Fold these into the leaf in order, hashing each sorted pair with keccak256, to reach the root of (296695 rows).
- 0x032003e4de89d297fb1dbf0492d12339df82394b016c5614a4fa32b866ccd200
- 0xd7bb432fc79a4a9b605069570e469fa7020adcae78cac349ddefd2bba8086b3d
- 0x71fc693a45abe66f5905b65995ba0aa1cdc6da3406d218545063d668d8a80d05
- 0x85f2990d5ed4ffbc4f5cfaf9c8a0324257fb56824079e1bd885fb7ee10826267
- 0x65a352ab0f5c8510258fe3f28e8523dea3f2ca58b388457d17b9311438121c2e
- 0x6736ca1e7fb61b9868ff4be3fdba5209c6b0e3acf27f5595dd49abaced004ead
- 0xa9caf9beb18d69d27e944783b7d5a22c84ec2616532fd56e2d85eb3028146e43
- 0x067ae9983dced5e9c30b72d03c0274b60c1ae48407e569a1f5c8466ccacc25bc
- 0x48e38167e1857fae9878a08be05cde083f0575f14771639b04edc518c9d1af23
- 0x7eb88a3b9eed96824d9e196c7f83cd784e15460aa54a9a4dc628a19fb1c77aa6
- 0x4e18f6df894eff467396bfe85f6d6b90f40522629a1dd7517152c38e1c70e111
- 0xd75ede2689ed83bbc8980becaf4f32a77c7e05567790cd351e997bb28aa0844c
- 0x92ff7d176556ddbe3d885e2ab73948b14a6aa3568a8fd237427d4f8415235a23
- 0xd1d3499072edb10edc68f84bcae2365d2ab534df689250cab18c751b6f13b6ff
- 0x7ddc2fead128357f881b63e6c7c26d7fbbb84fca6c7c8e0bbfe386de86ca8d39
- 0xc6a4d7899a0f442958e26505011190b7cff2483611c1b94eba9043e0ba9ac36e
- 0x8c756542e482157df0c36464d75c937b845e4423dbbcfad08f0cf8d5a16b9a13
- 0x20704208aa6923d6b2450ef74ede87a6e0265d46447926038fe9506e9e154b2d
- 0x9b9ce5b74b9bab5121612ef6b64920a8d453cbf311096a423eef9702747e868a
- Day root
- 0xf43e8dcc3d451a4788b26be904c55e8c4c0fa75c9666796c51db38d37e2c0df8
- Chained
- 0x702d5ac508f08b0d1accf36af25822d8e5660367494edd17a642fb61e158a57a
- Published
- On Arc Testnet, block 69251483: 0x495162f8936e19f0039918feebe6c307f327cd6bf8c37219620b1970041fa9ae