Call this server's tools from your browser. Nothing to install.
Requests go through mcptry because browsers can't call most MCP servers directly. Header values are sent to the server for that request only and are never stored or logged.
Tool list from our last check. Connect live to refresh it.
Discover the rest of the BlackOps tool catalog. This connector surfaces a small default tool set; every other BlackOps capability (pages, video, brains and brain watches, hunts, sorties, LinkedIn/Threads/Medium, GA4/Search Console analytics, and more) is one lookup away. Call with no arguments for the full index of tool names, with query to search, or with names for complete definitions including input_schema. Then invoke any of them with use_tool.
Max full definitions returned for a query (default 5).
Exact tool names to fetch full definitions for.
Keyword search over tool names and descriptions (case-insensitive).
Pick your client. Values in capitals, like YOUR_TOKEN, are yours to fill in.
Run in a terminal
claude mcp add --transport http blackops-mcp https://mcp.blackopscenter.com/mcp
Discover the rest of the BlackOps tool catalog. This connector surfaces a small default tool set; every other BlackOps capability (pages, video, brains and brain watches, hunts, sorties, LinkedIn/Threads/Medium, GA4/Search Console analytics, and more) is one lookup away. Call with no arguments for the full index of tool names, with query to search, or with names for complete definitions including input_schema. Then invoke any of them with use_tool.
| Argument | Type | Description |
|---|---|---|
| limit | integer | Max full definitions returned for a query (default 5). |
| names | array | Exact tool names to fetch full definitions for. |
| query | string | Keyword search over tool names and descriptions (case-insensitive). |
{
"type": "object",
"properties": {
"limit": {
"type": "integer",
"maximum": 10,
"description": "Max full definitions returned for a query (default 5).",
"exclusiveMinimum": 0
},
"names": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"maxItems": 10,
"description": "Exact tool names to fetch full definitions for."
},
"query": {
"type": "string",
"minLength": 1,
"description": "Keyword search over tool names and descriptions (case-insensitive)."
}
}
}Retrieve the full text of one BlackOps note or blog post by its search id.
| Argument | Type | Description |
|---|---|---|
| id* | string | Record id from search, e.g. "note:<uuid>". |
{
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "string",
"minLength": 1,
"description": "Record id from search, e.g. \"note:<uuid>\"."
}
}
}Finalize a presigned URL media upload. Call after uploading to the upload_url from upload_media, or after PUTting bytes directly to an upload_url minted by get_media_upload_url. Needs only { asset_id, domain } plus the same MCP/API token already on this session — no browser or cookie. Validates the file and processes dimensions/thumbnails — for a PDF that means rasterizing page one into a badged thumbnail. Bytes that are not really a PDF are rejected; a genuine PDF that will not rasterize still finalizes, just without a preview.
| Argument | Type | Description |
|---|---|---|
| domain* | string | |
| asset_id* | string |
{
"type": "object",
"required": [
"asset_id",
"domain"
],
"properties": {
"domain": {
"type": "string",
"minLength": 1
},
"asset_id": {
"type": "string",
"minLength": 1
}
}
}Get account context including defaults and publishing context for a domain. The default site (the site writes go to when the user names none) is stated by get_account_settings and get_ai_context (default_site).
| Argument | Type | Description |
|---|---|---|
| domain* | string |
{
"type": "object",
"required": [
"domain"
],
"properties": {
"domain": {
"type": "string",
"minLength": 1
}
}
}Get AI context pack for content generation. Recommended before creating tweets/posts. Also returns default_site (id, domain, and the rule "unless the user names another site, writes go to <domain>") when the account has one.
| Argument | Type | Description |
|---|---|---|
| query | string | |
| domain | string | |
| site_id | string |
{
"type": "object",
"properties": {
"query": {
"type": "string"
},
"domain": {
"type": "string"
},
"site_id": {
"type": "string"
}
}
}Get the compiled knowledge map for a brain: a manifest of source notes with IDs and summaries — call get_note for a note's full content. Site-agnostic. Accepts a UUID, slug, name, or alias; no list_brains lookup needed first (call list_brains for a brain not named in your instructions). status: "pending" means it has never compiled — call update_brain to add the first note. To create a new brain, call create_brain. The response's pending_triage_count is how many items are held out of this compile awaiting a list_triage / promote_triage_item / dismiss_triage_item decision. AMBIGUITY: when a reference matches more than one brain the response is error "ambiguous_brain_ref" with a candidate list and NO brain. Present the candidates to the user and ask which they mean. Do not infer from context, and do not re-call this tool until they answer.
| Argument | Type | Description |
|---|---|---|
| brain_id | string | Brain UUID |
| brain_name | string | Brain slug, name, or alias — how the user referred to it |
{
"type": "object",
"properties": {
"brain_id": {
"type": "string",
"minLength": 1,
"description": "Brain UUID"
},
"brain_name": {
"type": "string",
"minLength": 1,
"description": "Brain slug, name, or alias — how the user referred to it"
}
}
}Get canonical brand voice for the site. Pass domain or site_id to target a specific site; omit to use the auth default. Always pass the same domain/site_id used with patch_brand_voice so both tools operate on the same record. Also returns pronoun_mode and approved_facts when set, empty otherwise — the account-aware check_brand_voice guidance.
| Argument | Type | Description |
|---|---|---|
| domain | string | |
| site_id | string |
{
"type": "object",
"properties": {
"domain": {
"type": "string"
},
"site_id": {
"type": "string"
}
}
}Get current user profile, accessible sites, and account info. Call this first to discover which sites you can manage.
No arguments.
{
"type": "object",
"properties": {}
}Get details for a single media asset including URL, dimensions, format, and metadata.
| Argument | Type | Description |
|---|---|---|
| id* | string | |
| domain* | string |
{
"type": "object",
"required": [
"id",
"domain"
],
"properties": {
"id": {
"type": "string",
"minLength": 1
},
"domain": {
"type": "string",
"minLength": 1
}
}
}Agent-direct upload, no human step. 1: get_media_upload_url({ domain, filename, content_type, size_bytes? }) returns { asset_id, upload_url, public_url, expires_in }. 2: HTTP PUT the raw bytes to upload_url with a matching Content-Type. 3: finalize_media_upload({ asset_id, domain }). For bytes with no public URL, or too big for upload_media URL mode (e.g. video over 200 MB). If the PUT fails with a network error (sandboxed or proxied agent), use upload_media interactive mode instead. Allowed: images, mp4/webm/quicktime, pdf, mp3/wav. Max 20 MB images, 50 MB PDF, 1 GB video. URL expires after expires_in seconds.
| Argument | Type | Description |
|---|---|---|
| kind | string | |
| title | string | |
| domain* | string | |
| alt_text | string | |
| filename* | string | |
| size_bytes | integer | |
| content_type* | string |
{
"type": "object",
"required": [
"domain",
"filename",
"content_type"
],
"properties": {
"kind": {
"type": "string"
},
"title": {
"type": "string"
},
"domain": {
"type": "string",
"minLength": 1
},
"alt_text": {
"type": "string"
},
"filename": {
"type": "string",
"minLength": 1
},
"size_bytes": {
"type": "integer",
"maximum": 9007199254740991,
"exclusiveMinimum": 0
},
"content_type": {
"type": "string",
"minLength": 1
}
}
}Get a single note by UUID, slug, or title. Use this to read the full content of individual notes, including brain source notes referenced in a brain manifest. VAULT SYNC STATUS: the response carries a sync block — status is "queued" (commit in flight), "synced" (landed; see file_path + commit_sha), "failed" (see last_error; the sweeper retries), or "none" (no vault target). This is how you confirm a deferred post_notes commit landed; post_notes itself can only report "queued".
| Argument | Type | Description |
|---|---|---|
| id* | string | Note UUID, slug, or title |
{
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "string",
"minLength": 1,
"description": "Note UUID, slug, or title"
}
}
}Fetch a single blog post by slug or UUID, including full content, metadata, and SEO fields. One call — no need to list posts first to resolve a slug.
| Argument | Type | Description |
|---|---|---|
| id* | string | |
| domain | string | |
| site_id | string |
{
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "string",
"minLength": 1
},
"domain": {
"type": "string"
},
"site_id": {
"type": "string"
}
}
}List blog posts for a site. Filter by status (draft, published) with pagination support.
| Argument | Type | Description |
|---|---|---|
| limit | integer | |
| cursor | string | |
| domain | string | |
| status | string | |
| site_id | string |
{
"type": "object",
"properties": {
"limit": {
"type": "integer",
"maximum": 9007199254740991,
"exclusiveMinimum": 0
},
"cursor": {
"type": "string"
},
"domain": {
"type": "string"
},
"status": {
"type": "string"
},
"site_id": {
"type": "string"
}
}
}Get recent notes/context for the site. Recommended before creating tweets/posts.
| Argument | Type | Description |
|---|---|---|
| limit | integer | |
| domain | string | |
| site_id | string |
{
"type": "object",
"properties": {
"limit": {
"type": "integer",
"maximum": 9007199254740991,
"exclusiveMinimum": 0
},
"domain": {
"type": "string"
},
"site_id": {
"type": "string"
}
}
}List connected X (Twitter) accounts. Search by username or filter by site. Each account record includes premium (boolean) and max_tweet_length (integer) — ALWAYS read these before drafting tweet content. Premium accounts allow up to 25,000 chars; non-premium are limited to 280. If max_tweet_length is null, treat the limit as unknown and ask the user rather than assuming 280.
| Argument | Type | Description |
|---|---|---|
| query | string | |
| domain | string | |
| site_id | string | |
| username | string | |
| account_name | string |
{
"type": "object",
"properties": {
"query": {
"type": "string"
},
"domain": {
"type": "string"
},
"site_id": {
"type": "string"
},
"username": {
"type": "string"
},
"account_name": {
"type": "string"
}
}
}List all brains accessible to the authenticated user. Returns each brain's id, name, description, aliases, status, note count, last compiled timestamp, and visibility. Match description and aliases to resolve natural-language references (e.g. "restaurant brain"). Brains are site-agnostic — no domain or site_id needed. Cross-brain retrieval: returns every brain in the account, so an answer about one can draw on another — say so when it does. Private brains are omitted here but stay readable via get_brain by name.
No arguments.
{
"type": "object",
"properties": {}
}List the user's stored skills (slug + description). Call this at the START of a task: if a skill matches what the user asked for, fetch it with get_skill and follow it instead of improvising.
| Argument | Type | Description |
|---|---|---|
| tags | array | Only skills carrying every one of these tags. |
| brain_id | string | Restrict to skills stored in one brain. |
| platform | string | Only skills that support this host (e.g. "claude", "cursor", "grok"). Skills that declare no platforms always match. |
{
"type": "object",
"properties": {
"tags": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"maxItems": 10,
"description": "Only skills carrying every one of these tags."
},
"brain_id": {
"type": "string",
"format": "uuid",
"description": "Restrict to skills stored in one brain."
},
"platform": {
"type": "string",
"minLength": 1,
"description": "Only skills that support this host (e.g. \"claude\", \"cursor\", \"grok\"). Skills that declare no platforms always match."
}
}
}EDIT ONLY — modifies a post in-place. NEVER call for reading; use post_posts to create. Published edits go live immediately. Always pass base_updated_at (from get_post.updated_at); without it a concurrent edit is silently overwritten. Custom styled HTML needs a richembed fenced block; bare block HTML is escaped. Do NOT include the title in the content body. Response has links.review_url for drafts — give that link to the user.
| Argument | Type | Description |
|---|---|---|
| id* | string | |
| slug | string | |
| tags | array | |
| title | string | |
| domain | string | |
| status | string | |
| content | string | |
| site_id | string | |
| featured | boolean | |
| subtitle | string |
Create a BlackOps note, or update one in place when source_id resolves to a known note. Requires content_markdown (or transcript/conversation). Prefer this over post_notes_write — richer metadata, dedup, search/list visibility, auto-vault-sync. source_id is the idempotency key: pass it (content hash, agent-defined string, or note UUID) so repeat calls update instead of forking. Already know the note? Use patch_notes with id instead. Check response warnings — an auto-suffixed slug ("my-note-2") with code SLUG_COLLISION means an intended update forked instead. Site is OPTIONAL (resolves explicit → account default intake → the user's only site); pass domain/site_id only for a note tied to one site. BRAINS: pass a named brain's UUID as brain_id — the server derives site/target/folder from it, and this always skips auto-routing below. Never infer site_id or guess target_id from topic keywords. brain_alignment in the response confirms the compile will pick the note up. WITHOUT brain_id, a site that has opted into brain auto-routing resolves one itself instead of leaving the note unfiled with a guess-and-ask: an Auto verdict files the note straight into that brain's Triage lane (routing: { band: "auto", filed: true, brain_id, brain_name, probability, verdict_id }); a Suggest or No-home verdict saves the note unfiled and the response carries needs_brain_choice — present its question and up to 3 options (each with a one-line reason) as ONE single-choice question, the way your host renders a question or choice card if it has one, alongside the also entries ("Leave unfiled" / "Create a new brain"), then call resolve_with (patch_notes with the chosen brain_id) with the pick. Never choose a brain from that list yourself. A site that has not opted in behaves exactly as before — the note is saved unfiled, no brain is queried. suggest_brain: true is a separate, unrelated opt-in: a keyword-based unassigned-brain match surfaced as suggested_brain, not auto-routing. TAGS outside the vocabulary still apply and stay queryable, with an UNKNOWN_TAG warning naming it — ask the user before calling propose_note_tags. VAULT SYNC is automatic but DEFERRED: the commit runs after the response, so sync is { status: "queued" }. The note IS saved — do NOT re-call. Confirm a landed commit with get_note, never vault_sync_queued_at; pass wait_for_sync: true only for commitSha/filePath inline. override_folder_path bypasses the workspace taxonomy, though a brain's source_folder_path still wins. phase/priority/position are Big Board columns (High|Medium|Low for priority); phase is free text.
Create a blog draft. Before calling, fetch get_me + get_brand_voice (+ get_ai_context/get_recent_notes). Site scope is automatic for a single-site account; pass domain or site_id to target one, and an account with several sites is asked to choose rather than guessed at. Do NOT repeat the title in the content body — no leading "# Title" and no first line restating it, or it renders twice, since the title field prints above the content. Start with the intro paragraph or the first ## heading. The response carries links.review_url: that is where a person previews and edits the draft, so hand the user that link, never the admin editor URL or a raw preview URL.
| Argument | Type | Description |
|---|---|---|
| slug | string | |
| tags | array | |
| title* | string | |
| domain | string | |
| source | string | |
| status | string | |
| confirm | boolean | |
| content* | string | Blog post body in Markdown. Do NOT pass a fully HTML-formatted document — block-level HTML tags (e.g. <p>, <h2>) appear as literal text. Custom styled HTML (cards, tables, CSS callouts) must go in a richembed fenced block, which renders live. Inline HTML for embeds or Remotion components inside an otherwise-Markdown post is fine. |
Generate (or regenerate) a blog post's hero image, or its OG social card — works the same before and after the post exists. Returns the image inline plus its public URL. The fields below cover prompts, references, style, and the commit:false review flow. Rules that span fields: only the title and subtitle may ever appear on an OG card, because given anything else the generator invents its own tagline; an OG card takes NO references unless you name them, since auto-matching used to put a real face on social cards nobody asked to be in; for target:"og" prompt is the VISUAL DIRECTION and still gets OG framing; to anchor a face, mark the photo as a "headshot" via mark_reference_image first.
| Argument | Type | Description |
|---|---|---|
| id* | string | Post UUID |
| style | string | Visual style. Defaults to "modern". |
| commit | boolean | Default true: apply the image to the post immediately. False generates a review CANDIDATE (kind hero-candidate) and leaves the post untouched. |
| domain | string | |
| prompt | string | Image prompt, auto-generated from the post if omitted. For target:"og", layered on the site share_card_style. |
| target | string | "hero" (default) sets featured_image; "og" makes the 1200x630 Open Graph card and sets og_image, leaving the hero untouched. |
Publish a draft blog post, making it live on the site. Requires confirm: true. On a 2026-07-28 connection whose client declares form elicitation you may omit it and the user confirms in a dialog; anywhere else, omitting it fails. Publishing a scheduled post publishes it immediately and clears the schedule. Pass override_brand_voice: true to bypass the brand-voice gate when a publish fails that check.
| Argument | Type | Description |
|---|---|---|
| id* | string | |
| domain | string | |
| confirm | boolean | |
| site_id | string | |
| override_brand_voice | boolean |
{
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "string",
"minLength": 1
},
"domain": {
"type": "string"
},
"confirm": {
"type": "boolean"
},
"site_id": {
"type": "string"
},
"override_brand_voice": {
"type": "boolean"
}
}
}Schedule a draft blog post for future publishing. Provide a datetime via scheduledFor; the platform publishes the post automatically at that time (checked every 5 minutes). Unschedule by patching status back to "draft"; publish immediately with post_posts_by_id_publish. Requires confirm: true.
| Argument | Type | Description |
|---|---|---|
| id* | string | |
| domain | string | |
| confirm* | boolean | |
| site_id | string | |
| schedule_at | string | |
| scheduledFor | string | |
| scheduled_for | string |
{
"type": "object",
"required": [
"id",
"confirm"
],
"properties": {
"id": {
"type": "string",
"minLength": 1
},
"domain": {
"type": "string"
},
"confirm": {
"type": "boolean"
},
"site_id": {
"type": "string"
},
"schedule_at": {
"type": "string"
},
"scheduledFor": {
"type": "string"
},
"scheduled_for": {
"type": "string"
}
}
}Create a tweet draft. Before calling, fetch get_me + get_brand_voice (+ get_ai_context/get_recent_notes) AND call get_x_accounts for the posting account's max_tweet_length — never assume 280, since Premium/verified accounts go up to 25,000. If max_tweet_length is null the limit is unknown: ask the user rather than defaulting to 280. Site scope is automatic for a single-site account; pass domain or site_id to target one, and an account with several sites is asked to choose rather than guessed at. Requires text or thread. To attach an image, upload with upload_media then call attach_media_to_tweet with the asset_id and this tweet's id. Links to user-owned domains get UTM parameters appended at draft time so the traffic shows up in GA4 instead of as Direct; pass your own if you want explicit campaign slugs. When the tweet distributes a known blog post, pass its post_id (UUID, from get_posts) so the /admin/posts Distribution column links the two automatically — no manual backfill.
| Argument | Type | Description |
|---|---|---|
| text | string | |
| title | string | |
| domain | string | |
| thread | array | |
| post_id | string | |
| site_id | string | |
| account_id | string | |
| description |
Search BlackOps notes and blog posts. Returns id, title, and url per match; pass an id to fetch for the full text. Generated daily notes (note_type "daily", titled "YYYY-MM-DD · {Name}") do not contain the word "daily" in their title — queries containing "daily" automatically include them via a supplementary typed lookup, but for reliable lookup by context name use list_notes with note_type: "daily" and search: "{name}", or list_daily_note_configs to see which contexts exist.
| Argument | Type | Description |
|---|---|---|
| query* | string | Search terms, matched against titles and bodies. |
| domain | string | Site domain. Defaults to the account default site. |
{
"type": "object",
"required": [
"query"
],
"properties": {
"query": {
"type": "string",
"minLength": 1,
"description": "Search terms, matched against titles and bodies."
},
"domain": {
"type": "string",
"minLength": 1,
"description": "Site domain. Defaults to the account default site."
}
}
}Add a new note to a brain — no target_id or file path knowledge required; the server resolves storage from the brain record (BlackOps directly for DB-backed brains, a GitHub commit for vault-backed ones). Use this whenever the user says "update the brain", "add this to the brain", or "log this in the brain". Call list_brains first for the brain_id if you do not have it. To create a new brain from scratch, call create_brain. A DB-backed brain recompiles immediately; a vault-backed one picks the note up on its next compile. Use post_notes_write (with brain_id) only when you need lower-level control over the filename or relative path.
| Argument | Type | Description |
|---|---|---|
| brain_id* | string | Brain UUID (from list_brains) |
| allow_secrets | boolean | |
| note_filename | string | Override the filename (without .md extension). Defaults to slugified section_title or date-based name. |
| section_title | string | Title for this note — used as the filename slug (e.g. "Threads Integration") |
| commit_message | string | Git commit message. Defaults to "Add brain note: <filename>" |
| markdown_content* | string | Markdown content for the new note to add to the brain |
Upload media to the site media library. Three modes: 1. URL mode — pass file_url + filename + content_type. Fetches server-side, one call, no human step. file_url must be https, SSRF-guarded (blocks private/loopback/link-local/metadata, re-checked on every redirect), capped at 50 MB (images/PDF) or 200 MB (video, under the 1 GB bucket limit to fit the 30s fetch timeout — bigger video needs the direct-PUT path below). Good when an agent already has a URL, e.g. from a generation call. 2. Interactive mode — pass nothing (or just domain/label). Returns { url, token, expires_at }: show the URL, the user signs in and uploads via the quick-upload page, then clicks "Done". Use for screenshots, recordings, or local files — avoids round-tripping bytes, supports bulk. filename/alt_text/title apply to the FIRST asset only (later images auto-generate their own; videos get none). 3. Claim mode — pass token (from interactive mode). Returns status="completed" with an assets[] array once the user clicks Done, or "pending" while they are still uploading — poll again. No public URL but your own HTTP client? get_media_upload_url({ domain, filename, content_type }) → { asset_id, upload_url }, PUT your bytes, then finalize_media_upload({ asset_id, domain }) — token only, no browser. Example: content/docs/features/image-upload.mdx. Supported: jpeg, png, webp, gif, mp4, webm, quicktime, application/pdf (quick-upload: video to 1 GB, else 50 MB). Video → media_type "video", no thumbnail. PDF → "document" (thumbnail = page one, 50 MB cap), asset_id + public URL like an image — the only document type; anything else rejected.
| Argument | Type | Description |
|---|---|---|
| kind | string | |
| label | string | |
| title | string | |
| token | string | |
Invoke any BlackOps catalog tool that is not on the default surface, by name. Arguments are validated against the same schema the tool has natively, and the call runs the identical handler with identical permissions — this is dispatch, not a bypass. Look up names and input schemas with describe_tools first.
| Argument | Type | Description |
|---|---|---|
| args | object | The tool's arguments, matching the input_schema from describe_tools. |
| name* | string | Catalog tool name, exactly as returned by describe_tools. |
{
"type": "object",
"required": [
"name"
],
"properties": {
"args": {
"type": "object",
"properties": {},
"description": "The tool's arguments, matching the input_schema from describe_tools.",
"additionalProperties": {}
},
"name": {
"type": "string",
"minLength": 1,
"description": "Catalog tool name, exactly as returned by describe_tools."
}
}
}We read every tool's name, description and inputs the way the model will, looking for instructions hidden from you. A clean result means no warning signs, not a guarantee. Scanned Nov 11, 2026.
Takes a password, API key or token as an argument, so the secret passes through the model's context and chat logs.
Fix: Read credentials from the server's own configuration (environment, OAuth) instead of a tool argument.
| seo_title | string |
| description | string | The post's PUBLIC meta description shown in search results and link previews. Overwrites any stored value immediately. THIS IS NOT an edit-comment or reason-for-change field — omit this key entirely unless you explicitly intend to replace the current description. |
| published_at | string |
| featured_image | string |
| base_updated_at | string | ISO from preceding get_post.updated_at. Server returns 409 CONFLICT with current_updated_at + current_content if post was edited since read; re-read, merge, retry. |
| seo_description | string |
| x_discussion_url | string | null | X post permalink for the post's "Discuss on X" block. null removes it. |
| hero_prompt_edited | string | Custom prompt that will be used on the next hero image generation for this post. |
{
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "string",
"minLength": 1
},
"slug": {
"type": "string"
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"title": {
"type": "string"
},
"domain": {
"type": "string"
},
"status": {
"type": "string"
},
"content": {
"type": "string"
},
"site_id": {
"type": "string"
},
"featured": {
"type": "boolean"
},
"subtitle": {
"type": "string"
},
"seo_title": {
"type": "string"
},
"description": {
"type": "string",
"description": "The post's PUBLIC meta description shown in search results and link previews. Overwrites any stored value immediately. THIS IS NOT an edit-comment or reason-for-change field — omit this key entirely unless you explicitly intend to replace the current description."
},
"published_at": {
"type": "string"
},
"featured_image": {
"type": "string"
},
"base_updated_at": {
"type": "string",
"description": "ISO from preceding get_post.updated_at. Server returns 409 CONFLICT with current_updated_at + current_content if post was edited since read; re-read, merge, retry."
},
"seo_description": {
"type": "string"
},
"x_discussion_url": {
"type": [
"string",
"null"
],
"description": "X post permalink for the post's \"Discuss on X\" block. null removes it."
},
"hero_prompt_edited": {
"type": "string",
"description": "Custom prompt that will be used on the next hero image generation for this post."
}
}
}| Argument | Type | Description |
|---|
| tags | array | |
| phase | string | |
| title | string | |
| domain | string | |
| status | string | |
| confirm | boolean | |
| excerpt | string | null | |
| site_id | string | |
| brain_id | string | |
| metadata | object | |
| position | string | |
| priority | string | |
| auto_sync | boolean | |
| note_type | string | |
| source_id | string | |
| target_id | string | null | |
| transcript | string | |
| conversation | object | |
| triage_state | string | Set to 'pending' to file this note into a brain's Triage lane (unreviewed) instead of committing it to the vault right away. Leave unset for an ordinary note. |
| allow_secrets | boolean | |
| assign_target | boolean | |
| suggest_brain | boolean | |
| wait_for_sync | boolean | |
| conversation_id | string | |
| content_markdown | string | |
| override_folder_path | string |
{
"type": "object",
"properties": {
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"phase": {
"type": "string"
},
"title": {
"type": "string"
},
"domain": {
"type": "string"
},
"status": {
"enum": [
"draft",
"active",
"archived"
],
"type": "string"
},
"confirm": {
"type": "boolean"
},
"excerpt": {
"type": [
"string",
"null"
]
},
"site_id": {
"type": "string"
},
"brain_id": {
"type": "string",
"format": "uuid"
},
"metadata": {
"type": "object",
"properties": {},
"additionalProperties": {}
},
"position": {
"type": "string"
},
"priority": {
"enum": [
"High",
"Medium",
"Low"
],
"type": "string"
},
"auto_sync": {
"type": "boolean"
},
"note_type": {
"type": "string"
},
"source_id": {
"type": "string"
},
"target_id": {
"type": [
"string",
"null"
]
},
"transcript": {
"type": "string"
},
"conversation": {
"type": "object",
"properties": {},
"additionalProperties": {}
},
"triage_state": {
"enum": [
"pending",
"promoted",
"dismissed",
"expired"
],
"type": "string",
"description": "Set to 'pending' to file this note into a brain's Triage lane (unreviewed) instead of committing it to the vault right away. Leave unset for an ordinary note."
},
"allow_secrets": {
"type": "boolean"
},
"assign_target": {
"type": "boolean"
},
"suggest_brain": {
"type": "boolean"
},
"wait_for_sync": {
"type": "boolean"
},
"conversation_id": {
"type": "string"
},
"content_markdown": {
"type": "string"
},
"override_folder_path": {
"type": "string",
"minLength": 1
}
}
}| excerpt | string |
| site_id | string |
| featured | boolean |
| subtitle | string | Subtitle/deck shown beneath the title. Populate it whenever the post has a natural subheadline or clarifying phrase. |
| seo_title | string |
| seo_description | string |
{
"type": "object",
"required": [
"title",
"content"
],
"properties": {
"slug": {
"type": "string"
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"title": {
"type": "string",
"minLength": 1
},
"domain": {
"type": "string"
},
"source": {
"type": "string"
},
"status": {
"enum": [
"draft",
"published"
],
"type": "string"
},
"confirm": {
"type": "boolean"
},
"content": {
"type": "string",
"minLength": 1,
"description": "Blog post body in Markdown. Do NOT pass a fully HTML-formatted document — block-level HTML tags (e.g. <p>, <h2>) appear as literal text. Custom styled HTML (cards, tables, CSS callouts) must go in a richembed fenced block, which renders live. Inline HTML for embeds or Remotion components inside an otherwise-Markdown post is fine."
},
"excerpt": {
"type": "string"
},
"site_id": {
"type": "string"
},
"featured": {
"type": "boolean"
},
"subtitle": {
"type": "string",
"description": "Subtitle/deck shown beneath the title. Populate it whenever the post has a natural subheadline or clarifying phrase."
},
"seo_title": {
"type": "string"
},
"seo_description": {
"type": "string"
}
}
}| site_id | string |
| alt_text | string | ACCEPT mode: override the auto-generated alt text on the accepted asset. Applies to accept_asset_id; ignored on accept_image_url. |
| subtitle | string | OG only. Secondary line rendered verbatim beneath the title. Defaults to the post's own subtitle; nothing appears unless passed or stored. |
| caller_name | string | Optional self-reported label for who/what is generating (e.g. an agent name). Shows up in get_hero_history as caller_name — a label you provide, not a verified identity. Omit to default to your account id. |
| accept_asset_id | string | ACCEPT mode, no generation: promote a candidate and attach it. Sets og_image for an OG candidate (og-candidate kind), or featured_image + hero_asset_id for a hero candidate. The field_set key in the response says which field was written. |
| accept_image_url | string | ACCEPT fallback when only the URL is known — sets featured_image (or og_image when target: "og" is also passed) without asset promotion. |
| include_subtitle | boolean | OG only. Default true. False renders a title-only card even when the post has a subtitle. |
| iteration_prompt | string | Edit instruction for iterating on a previous hero (e.g. "make the background darker"). Requires source_image_url, which anchors composition. |
| latest_candidate | boolean | READ mode, no generation: returns the newest un-accepted hero candidate for the post. |
| source_image_url | string | URL of the hero to iterate on (a prior result's image_url). Used with iteration_prompt. |
| include_title_text | boolean | OG only. Default true: render the title as text on the card. False produces a purely visual card. |
| reference_image_ids | array | Curated reference IDs and/or media-library asset IDs (upload_media / list_media). Omitted: reuses the first hero's references, else auto-matches from the prompt. [] uses none. |
{
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "string",
"minLength": 1,
"description": "Post UUID"
},
"style": {
"enum": [
"western",
"cinematic",
"modern",
"professional",
"artistic",
"minimalist"
],
"type": "string",
"description": "Visual style. Defaults to \"modern\"."
},
"commit": {
"type": "boolean",
"description": "Default true: apply the image to the post immediately. False generates a review CANDIDATE (kind hero-candidate) and leaves the post untouched."
},
"domain": {
"type": "string"
},
"prompt": {
"type": "string",
"description": "Image prompt, auto-generated from the post if omitted. For target:\"og\", layered on the site share_card_style."
},
"target": {
"enum": [
"hero",
"og"
],
"type": "string",
"description": "\"hero\" (default) sets featured_image; \"og\" makes the 1200x630 Open Graph card and sets og_image, leaving the hero untouched."
},
"site_id": {
"type": "string"
},
"alt_text": {
"type": "string",
"description": "ACCEPT mode: override the auto-generated alt text on the accepted asset. Applies to accept_asset_id; ignored on accept_image_url."
},
"subtitle": {
"type": "string",
"description": "OG only. Secondary line rendered verbatim beneath the title. Defaults to the post's own subtitle; nothing appears unless passed or stored."
},
"caller_name": {
"type": "string",
"description": "Optional self-reported label for who/what is generating (e.g. an agent name). Shows up in get_hero_history as caller_name — a label you provide, not a verified identity. Omit to default to your account id."
},
"accept_asset_id": {
"type": "string",
"description": "ACCEPT mode, no generation: promote a candidate and attach it. Sets og_image for an OG candidate (og-candidate kind), or featured_image + hero_asset_id for a hero candidate. The field_set key in the response says which field was written."
},
"accept_image_url": {
"type": "string",
"description": "ACCEPT fallback when only the URL is known — sets featured_image (or og_image when target: \"og\" is also passed) without asset promotion."
},
"include_subtitle": {
"type": "boolean",
"description": "OG only. Default true. False renders a title-only card even when the post has a subtitle."
},
"iteration_prompt": {
"type": "string",
"description": "Edit instruction for iterating on a previous hero (e.g. \"make the background darker\"). Requires source_image_url, which anchors composition."
},
"latest_candidate": {
"type": "boolean",
"description": "READ mode, no generation: returns the newest un-accepted hero candidate for the post."
},
"source_image_url": {
"type": "string",
"description": "URL of the hero to iterate on (a prior result's image_url). Used with iteration_prompt."
},
"include_title_text": {
"type": "boolean",
"description": "OG only. Default true: render the title as text on the card. False produces a purely visual card."
},
"reference_image_ids": {
"type": "array",
"items": {
"type": "string"
},
"description": "Curated reference IDs and/or media-library asset IDs (upload_media / list_media). Omitted: reuses the first hero's references, else auto-matches from the prompt. [] uses none."
}
}
}| string |
| account_username | string |
{
"type": "object",
"properties": {
"text": {
"type": "string"
},
"title": {
"type": "string"
},
"domain": {
"type": "string"
},
"thread": {
"type": "array",
"items": {
"type": "object",
"required": [
"text"
],
"properties": {
"text": {
"type": "string"
}
},
"additionalProperties": {}
}
},
"post_id": {
"type": "string",
"format": "uuid"
},
"site_id": {
"type": "string"
},
"account_id": {
"type": "string"
},
"description": {
"type": "string"
},
"account_username": {
"type": "string"
}
}
}{
"type": "object",
"required": [
"brain_id",
"markdown_content"
],
"properties": {
"brain_id": {
"type": "string",
"format": "uuid",
"description": "Brain UUID (from list_brains)"
},
"allow_secrets": {
"type": "boolean"
},
"note_filename": {
"type": "string",
"minLength": 1,
"description": "Override the filename (without .md extension). Defaults to slugified section_title or date-based name."
},
"section_title": {
"type": "string",
"minLength": 1,
"description": "Title for this note — used as the filename slug (e.g. \"Threads Integration\")"
},
"commit_message": {
"type": "string",
"maxLength": 300,
"minLength": 1,
"description": "Git commit message. Defaults to \"Add brain note: <filename>\""
},
"markdown_content": {
"type": "string",
"minLength": 1,
"description": "Markdown content for the new note to add to the brain"
}
}
}| domain |
| string |
| ttl_ms | integer |
| alt_text | string |
| file_url | string |
| filename | string |
| size_bytes | integer |
| content_type | string |
{
"type": "object",
"properties": {
"kind": {
"type": "string"
},
"label": {
"type": "string",
"maxLength": 200
},
"title": {
"type": "string"
},
"token": {
"type": "string",
"minLength": 1
},
"domain": {
"type": "string",
"minLength": 1
},
"ttl_ms": {
"type": "integer",
"maximum": 3600000,
"exclusiveMinimum": 0
},
"alt_text": {
"type": "string"
},
"file_url": {
"type": "string",
"pattern": "^https:\\/\\/"
},
"filename": {
"type": "string",
"minLength": 1
},
"size_bytes": {
"type": "integer",
"maximum": 9007199254740991,
"exclusiveMinimum": 0
},
"content_type": {
"type": "string",
"minLength": 1
}
}
}