MCP Tool Catalog

Every tool the BlackOps MCP server exposes to your AI client, grouped by what it touches. Connect once — see Connect the MCP — and your assistant can call any of these by name.

141 tools, generated directly from the live server so this list never drifts. GPT Action tools also work as ChatGPT Actions; MCP-only tools run through the MCP connection.

Account & Context (25)

create_commMCP-only

Create a Comm intake channel and bind it to a Sortie with a fire policy. Example: a "journal" channel mapped to a daily-note routine on a 21:00 schedule, or an "ideas" channel mapped to a logging routine that fires on every push. Use list_sorties to find the sortie_id to link.

create_sortieMCP-only

Register a Sortie — a named webhook + (optional) bearer-token target a Comm fires. Use this to wire up a fire target from chat: point it at a Claude Code routine fire URL or any HTTP webhook, set the default_payload (drop a {{comms}} token where a Comm's drops should land), and the headers. SECURITY: the bearer token is encrypted at rest and never echoed back; to keep the secret out of the conversation, OMIT `token` and add it later in Settings → Sorties (the Sortie is created "unarmed" until a token is set). Returns the new sortie id to pass to create_comm / patch_comm.

drop_commsMCP-only

Drop a capture into a Comm — a named intake channel ("journal", "ideas") that accumulates short notes through the day and fires a linked Sortie on its policy. Use this whenever the user says "add this to my <name> comms", "log to <name>", or wants to stash a thought/update/idea against a channel. An on_push channel fires its routine immediately; a scheduled one accumulates until its daily time. Call list_comms first if you do not know the channel slug.

fire_commMCP-only

Fire a Comm now — dispatch every undispatched drop in the channel through its linked Sortie and mark them sent. Use for a manual channel, or to flush a scheduled/on_push channel early.

fire_sortieMCP-only

Fire a Sortie — a webhook + bearer-token pair registered in BlackOps (Settings → Sorties). The token stays encrypted server-side and never enters this conversation. Use this to trigger Claude Code Routines (e.g. a bug-fixer or PR-closer routine) or any HTTP webhook (Zapier, n8n, GitHub repo-dispatch, custom server). Returns the upstream response, surfacing claude_code_session_url when the fired routine provides one. Call list_sorties first if you do not know the exact name.

get_account_contextGPT Action

Get account context including defaults and publishing context for a domain.

get_ai_contextGPT Action

Get AI context pack for content generation. Recommended before creating tweets/posts.

get_analytics_memoryMCP-only

Get the full per-site analytics memory for a surface (ga4 or gsc): the latest reading and delta-since-last-look for each tool, the open recommendation ledger (with how many times each was surfaced and its status), and recent findings. A compact version of this is auto-injected into every GA4/GSC tool response; call this when you want the full history, e.g. before deciding what to recommend. Read-only.

get_brand_voiceGPT Action

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.

get_compositionsGPT Action

List a site's HyperFrames compositions (live animations played by <hyperframes-player>). Returns slug + name + description. Each is served at /api/compositions/<slug>. Call before creating one to avoid duplicating, and to find the id to patch. Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess.

get_compositions_by_idGPT Action

Get a single composition by ID, including the full html + mobile_html. Read this before patching so you tweak the real current markup.

get_meGPT Action

Get current user profile, accessible sites, and account info. Call this first to discover which sites you can manage.

get_noteGPT Action

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.

get_note_taxonomyGPT Action

Get the active site's note taxonomy: tag vocabulary, folder routing rules, and default folder. Call this BEFORE post_notes / patch_notes so you can pick known tags (post_notes will return a warning for unknown ones) and predict which folder a note's tags + note_type will route the synced file into. Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess.

get_recent_notesGPT Action

Get recent notes/context for the site. Recommended before creating tweets/posts.

get_repo_targetsGPT Action

List configured repository targets for note file writes. Returns available paths where notes can be saved.

list_accountsGPT Action

List available BlackOps domains/accounts.

list_commsMCP-only

List the Comm intake channels for your site — their slugs, linked sortie, fire mode (on_push/scheduled/manual), schedule, and how many drops are pending dispatch. Use before drop_comms or fire_comm to discover channel slugs.

list_notesGPT Action

Query notes with filters and pagination. Mirrors list_reservoir_items. Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess. Filters: tags (with tags_match=all|any, default all), note_type, status (default active), search (title + excerpt ILIKE). Pagination: limit (default 20, max 200), offset. Sort: created_at | updated_at | title (default updated_at desc). For a quick "most recent" lookup keep using get_recent_notes; use list_notes when you need filtered or paginated queries.

list_sortiesMCP-only

List the Sorties registered for your site — the named webhook/routine targets you can fire with fire_sortie. Returns names, fire URLs, status, and last-fired time. Never returns the stored bearer token.

log_analytics_findingMCP-only

Record what an analytics session found so the next session builds on it instead of repeating the same advice. Writes a structured finding, upserts recommendations into the per-site dedup ledger (identical advice is fingerprinted — re-passing one just bumps its counter, so check the injected open_recommendations first), applies any status updates you pass, and creates a dated, tagged note in BlackOps (tags: analytics-log, analytics:<domain>, surface:<ga4|gsc>). Call this at the END of an analytics conversation. WRITE TOOL. Requires Pro tier.

patch_brand_voiceGPT Action

Update brand voice rules conversationally. Use add, remove, or update to change individual items in tone, style_rules, content_bias, or cta_preferences. Never replaces the full record — only modifies the items you specify. Before calling, fetch get_brand_voice to show the user the current state and confirm the intended changes. Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess.

patch_commMCP-only

Update an existing Comm in place — change its fire policy (manual/scheduled/on_push), schedule time, linked Sortie, name/slug/description, or enable/disable it — WITHOUT recreating the channel or losing its accumulated drops. Use this to bind a channel to a Sortie ("link my journal channel to the daily-note sortie"), put it on a daily schedule ("fire my journal at 23:00"), pause it, or rename it. Pass only the fields you want to change. Call list_comms / list_sorties to discover slugs and sortie ids.

patch_compositions_by_idGPT Action

Update a composition (name, description, html, mobile_html, is_enabled). Applies immediately — NO deploy — to every component/post embedding it. This is the nimble path for "make it slower / hold longer / change the color": edit the html and patch. Slug rename is not supported; create a new composition for a new slug.

patch_notesGPT Action

Update an existing BlackOps note. Supports partial updates: title, content_markdown, status, note_type, tags, excerpt. Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess. Required: id (UUID, slug, or title).

Posts, Pages & Components (27)

attach_media_to_postGPT Action

Attach a media asset to a blog post. Placement options: hero (featured image), og_image (social sharing image), hero_video (video header), inline (append markdown embed to content).

delete_components_by_idGPT Action

Delete a component by ID. Pages that reference the deleted slug will render their fallback content (or an HTML comment if there was no fallback). Requires confirm: true.

delete_pages_by_idGPT Action

Delete a page by ID. Permanently removes the page from the site. Requires confirm: true.

delete_posts_by_idGPT Action

Delete a blog post by ID. Permanently removes the post from the site.

delete_verified_links_by_idGPT Action

Remove a URL from a site's verified-links allowlist. Requires confirm: true. Pages or components that reference the deleted URL will fail validation on the next write.

get_componentsGPT Action

List reusable components available for a site. ALWAYS call this BEFORE drafting a page's html_body — if a component already exists for something the page needs (pricing table, CTA, testimonials, etc.), reference it via <bo-component slug="..."></bo-component> instead of redrawing it. Components are inlined at render time, so updating a component automatically updates every page that references it. Returns slug + name + description for each component. Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess.

get_components_by_idGPT Action

Get a single component by ID, including the full html_body and custom_css. Use this to read the current implementation before patching.

get_pagesGPT Action

List custom landing pages and section/markdown pages for a site. Filter by status (draft|published) and page_structure. Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess.

get_pages_by_idGPT Action

Get a single page by ID, including the full html_body, sections, chrome flags, and SEO metadata.

get_postGPT Action

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.

get_postsGPT Action

List blog posts for a site. Filter by status (draft, published) with pagination support.

get_verified_linksGPT Action

List the URLs verified for a site. CALL THIS BEFORE drafting any html_body for pages or components — every href, src, poster, action, or data-href in the body must either be in this list, an in-page anchor (#section), a mailto:/tel: protocol link, or a path that already exists as a published site_pages route. The server validates at write time and rejects unverified URLs, so guessing/inventing links wastes a round trip. Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess.

patch_components_by_idGPT Action

Update an existing component. Editable fields: name, description, html_body, custom_css, is_enabled. Updates apply immediately to every published page that references this component via <bo-component slug="...">. Slug rename is intentionally not supported — create a new component if you need a new slug. Same brand-pull rule as post_components: refresh get_brand_design when rewriting html_body.

patch_pages_by_idGPT Action

Update an existing page. Editable fields: title, html_body, content, sections, page_structure, is_enabled, show_header, show_footer, full_bleed, show_in_nav, nav_label, nav_order, seo_title, seo_description, seo_image_url, seo_keywords. When rewriting html_body, follow the same rule as post_pages: call get_brand_design + get_brand_voice for the page's site first so the new HTML stays on-brand, call get_components and get_verified_links to reuse existing assets and avoid hallucinated URLs, and let any user-specified directives override the brand defaults for those specific items. Slug rename is intentionally not supported here.

patch_posts_by_idGPT Action

EDIT ONLY — modifies an existing post in-place. NEVER call this when you read a post for reference or inspiration; use post_posts to create new content instead. Edits to published posts go live immediately with no confirmation and no rollback. Only call this when the user has explicitly asked to edit a specific existing post. Editable fields: title, subtitle, slug, content, description (the post's PUBLIC meta description shown in search results — NOT an edit-comment; omit if not changing it), status, tags, seo_title, seo_description, featured_image, featured (boolean), published_at, hero_prompt_edited (sets the custom prompt used on next hero generation). IMPORTANT: when updating content, do NOT include the title in the body — no leading "# Title" H1 and no first line repeating the title. Title comes from the title field; duplicating it in content shows a duplicate to readers.

patch_verified_links_by_idGPT Action

Update a verified link entry. Editable fields: label, description, category, is_enabled. URL itself is immutable — delete and re-add to change the URL.

post_componentsGPT Action

Create a reusable per-site component (e.g. a pricing table, hero variant, CTA block, testimonials grid) that pages can embed via <bo-component slug="..."></bo-component>. Before drafting html_body, call get_brand_design + get_brand_voice for the same site so the component is brand-accurate, check get_components to avoid duplicating an existing one, and call get_verified_links — every href/src/poster/action URL in the component must be verified. NEVER invent URLs (e.g. "/checkout?plan=pro", "https://stripe.com/buy/abc"). Server rejects components with unverified URLs. If you need a URL the user hasn't supplied, ask them; only call post_verified_links to add a URL when they've given it to you explicitly and confirmed. Slug must be lowercase kebab-case and unique per site (e.g. "price-table", "trial-cta", "testimonials-grid"). Description should explain when this component is appropriate so future LLM calls know to reuse it. Static HTML, custom CSS, <video>, and declarative CSS/SVG animation render live inline. ANIMATIONS — never hand-write GSAP or custom JavaScript here: in blog POSTS injected <script> does not execute (only declarative CSS and SVG/SMIL animate live). Pick the mechanism by the motion: (1) PREFER a declarative component when the motion is expressible in CSS/SVG — staggered reveals, transitions, ticking checkmarks, progress bars, loops, simple choreography (e.g. "animate this card", "make the files fly into the zip"). It renders live: crisp at any size, theme-matched, tiny, and editable in one place. (2) Render to a VIDEO (create_video → render_video, embed as <video autoplay muted loop playsinline> or via attach_media_to_post) only when the motion needs real JS-level sequencing/physics that CSS can't express, OR must play where components are gated — a free *.blackopscenter.com subdomain, email, or social. The user never names a tool: they describe what they want, you pick component-vs-video. WHERE COMPONENTS RENDER: on the site's own custom domain (and the blackopscenter.com owner site); on a free *.blackopscenter.com customer subdomain they show a placeholder until a custom domain is connected. Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess.

post_compositionGPT Action

Create a LIVE HyperFrames animation — a self-contained animated HTML document stored in the DB and served at /api/compositions/<slug> with NO deploy. This is how you ship a live in-page animation (not a video) when the motion exceeds plain CSS: an animated explainer, a UI walkthrough, a looping/animated hero, "animate this card", "make the files fly into the zip". Write a complete HTML doc to the composition contract: a root <div data-composition-id="<id>" data-width="W" data-height="H" data-start="0" data-duration="S"> wrapping the content; a PAUSED GSAP timeline (gsap.timeline({paused:true})) registered at window.__timelines["<id>"]; GSAP loaded from a CDN. To loop with a rest, END the timeline with an empty hold tween (tl.to({}, {duration:5})) and set data-duration to cover the whole timeline. Provide mobile_html (a portrait, larger-text variant) for mobile readability. THEN embed it from a reusable component's html_body (post_components): <hyperframes-player data-src-desktop="/api/compositions/<slug>" data-src-mobile="/api/compositions/<slug>?variant=mobile" data-breakpoint="640" data-aspect-desktop="W / H" data-aspect-mobile="Wm / Hm" muted style="width:100%;max-width:600px;aspect-ratio:W / H;display:block;margin:1.5rem auto"></hyperframes-player>, then reference that component in a post via <bo-component slug="...">. The platform handles autoplay, looping, and the desktop/mobile switch. The user never names a tool: they describe what they want, you build it. Tweaks ("slower", "hold longer", "change the orange") are a one-call patch_compositions_by_id — instantly live, no deploy. Use a VIDEO (create_video → render_video) instead only when you need a downloadable file for social/email. Compositions render where components do: custom-domain sites + the blackopscenter.com owner site. Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess.

post_notesGPT Action

Create/update a BlackOps note record (general note capture) — the canonical entry point for note creation. Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess. Required content field: content_markdown (or transcript/conversation). VAULT SYNC IS AUTOMATIC: when the site has a connected repo target (Obsidian vault), the note is auto-written to the vault and the response includes a sync block with commitSha + filePath. Tag-based folder routing is applied automatically per the workspace's note taxonomy (call get_note_taxonomy to preview where tags will land). FOLDER OVERRIDE: pass override_folder_path (relative to the target's base_path, no leading slash) to bypass taxonomy routing and land the file at a specific folder — e.g. override_folder_path: "bugs/closed" puts the file under <base_path>/bugs/closed/<slug>.md. Use this to archive or move existing notes (when combined with source_id); the previous file is auto-deleted by the stale-file cleanup. Brain source_folder_path still wins over this override to preserve brain alignment. Do NOT use post_notes_write — it skips the BlackOps record and produces unqueryable file-only artifacts. BRAIN GUIDANCE: if the user references a brain by name (e.g. "update the BlackOps brain", "log this in the product brain"), pass that brain's UUID as brain_id and the server will resolve site_id, target_id, and source folder from the brain itself — do NOT infer site_id from topic keywords or guess a target_id. If the brain reference is ambiguous (multiple brains, name not given), ask the user before calling. The response includes a brain_alignment block confirming whether the note will be picked up by the brain compile.

post_pagesGPT Action

Create a custom landing page on the customer site at the given slug — root-level ("about") or prefixed ("vs/buffer", "for/agencies", "replace/notion", "alternative/<x>"). This tool's purpose is to publish a brand-accurate landing page for the target site, so before drafting html_body you MUST call get_brand_design AND get_brand_voice for the same site, AND call get_components to discover reusable components already authored for this site, AND call get_verified_links to discover the only URLs allowed in href/src/poster/action attributes. NEVER invent URLs. The server rejects pages whose html_body contains unverified URLs (with status 422 and a list of offenders). Allowed without verification: in-page anchors (#section), mailto:/tel: protocols, paths that match an existing published site page (use get_pages to check), and asset paths under /images/ /api/ /_next/ /brand/ /saas/ /fonts/. Everything else — every CTA URL, every checkout link, every external link — must come from get_verified_links. If the page needs a URL that isn't verified, ask the user; only call post_verified_links to add a URL when they've given you the URL explicitly and confirmed. Use the returned colors, fonts, gradients, scales, and voice to compose the HTML — the page should look and read like it belongs to that site. CRITICAL token usage: the brand_design response includes BOTH light-surface tokens (text_color, muted_color, border_color, background_color) AND dark-surface counterparts (text_color_dark, muted_color_dark, border_color_dark, background_color_dark). Whenever a section renders on a dark background (dark hero band, dark CTA, dark comparison table, full dark-mode page), use the *_dark tokens for text/muted/border so contrast stays readable. Never use the light muted_color on a dark background — secondary text disappears. REUSABLE COMPONENTS: when get_components returns a component matching what the page needs (pricing table, CTA, testimonials, etc.), embed it instead of redrawing the same block — write <bo-component slug="that-slug"></bo-component> at the spot in html_body where it should appear. Optional fallback content goes between the open and close tags. Components are inlined at render time, so updating a component updates every page that uses it. If no suitable component exists for a piece that will likely be reused (e.g. pricing), consider creating one with post_components first, then referencing it from the page. Anything the user explicitly specifies (a particular video, headline copy, color, layout, comparison points, custom CSS, etc.) overrides the brand defaults for that specific instruction; brand defaults fill in everything the user did not specify. Only call get_brain when the user explicitly asks to use a brain (e.g. "use the BlackOps brain to compare us to Squarespace") — otherwise do not pull brain context. Scripts, <video> with autoplay/loop, animations, and arbitrary CSS are all allowed inside html_body. Defaults to full_bleed: true with header + footer ON. SEO is mostly automatic: canonical URL, JSON-LD WebPage + BreadcrumbList, Open Graph and Twitter cards are emitted from the page record at render time. You should still supply seo_title (under 60 chars), seo_description (under 160 chars), seo_image_url (1200x630 OG image), and seo_keywords (5-12 search phrases) for best results. Pages start as drafts; pass status: "published" + confirm: true to publish in one call, or call post_pages_by_id_publish later. Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess.

post_pages_by_id_publishGPT Action

Publish a draft page, making it live at its configured slug. Requires confirm: true.

post_postsGPT Action

Create blog draft. Before calling, fetch get_me + get_brand_voice (+ get_ai_context/get_recent_notes). Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess. Required fields: title, content. Optional: subtitle (deck/subheadline shown beneath the title — populate this whenever the post has a natural subheadline or clarifying phrase). IMPORTANT: content must be Markdown — do NOT pass a fully HTML-formatted document (e.g. <p>text</p><h2>heading</h2>); the CMS renders markdown directly and block-level HTML tags appear as literal text. Inline HTML for specific embeds (custom HTML blocks, Remotion components) is acceptable within an otherwise-Markdown document. IMPORTANT: do NOT include the title in the content body — no leading "# Title" H1 and no first line repeating the title. The renderer displays the title from the title field above the content; including it in the body produces a duplicate. Start content with the intro paragraph or the first ## section heading.

post_posts_by_id_heroGPT Action

Generate a hero image for a blog post. Accepts optional prompt (custom image description), reference_image_ids (array of media library asset IDs for face/style references), and style (e.g. "western", "cinematic"). If no prompt is given, one is auto-generated from the post content. Reference images default to all site images if reference_image_ids is omitted. Returns the image inline in chat plus the public URL.

post_posts_by_id_publishGPT Action

Publish a draft blog post, making it live on the site. Requires confirm: true.

post_reservoir_ingestGPT Action

Ingest content into a knowledge reservoir. Add URLs, articles, or text as reference material. Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess.

post_to_mediumGPT Action

Cross-post a published blog post to Medium with canonical URL, tags, and SEO preserved. Requires a Medium integration token configured at /admin/settings?section=integrations. Requires confirm=true. Already-cross-posted posts return the existing Medium URL unless force=true.

post_verified_linksGPT Action

Add a URL to a site's verified-links allowlist. Use this only when the user has explicitly given you a URL to whitelist — never invent a URL and add it on your own. The url field must be an absolute URL (https://...), an absolute path on the site (/foo), or a mailto:/tel: protocol link. Categories: page, cta, asset, social, docs, embed, other. After adding, future page or component writes can reference this URL safely. Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess.

Social — X, Threads & LinkedIn (37)

attach_media_to_linkedin_postGPT Action

Attach media to a LinkedIn post draft. Reuse asset_id from upload_media.

attach_media_to_threadGPT Action

Attach a media asset (from upload_media) to a Threads draft. Threads requires media URLs to be publicly reachable HTTPS at publish time — the media library URL satisfies this. Container creation is deferred to publish.

attach_media_to_tweetGPT Action

Attach a media asset to a tweet draft. First upload the image with upload_media, then pass the returned asset_id here. tweet_index is 0-based (0 = first/only tweet, 1 = second tweet in a thread, etc.); omit to default to 0. Up to 4 images per tweet — limit enforced by the backend.

delete_linkedin_post_by_idGPT Action

Delete a LinkedIn post by ID. If published, also deletes from LinkedIn. Requires confirm: true.

delete_threads_by_idGPT Action

Delete a Threads draft from BlackOps. NOTE: the Threads API does not expose a delete endpoint — published Threads posts must be removed manually in the Threads app. This tool only removes the BlackOps record.

delete_tweets_by_idGPT Action

Delete a tweet or thread by ID. Removes the draft; does not delete from X if already posted.

generate_linkedin_carouselMCP-only

Render a branded PDF carousel and return a downloadable URL. NO LinkedIn account or draft post required. Use this when you want to post a carousel by hand (e.g. to a LinkedIn organization/company page the API cannot reach). Provide {topic, sourceMaterial?, slideCount?, theme?, tone?, allowImages?, imageGuidance?} to generate slides, OR {spec} to render a pre-built spec. Returns {public_url} (the PDF to download), asset_id, page_count, and the spec. Differs from post_linkedin_by_id_carousel, which requires a connected LinkedIn account and attaches the PDF to a draft post.

get_linkedin_accountsGPT Action

List connected LinkedIn accounts. Search by name or filter by site.

get_linkedin_post_by_idGPT Action

Get a single LinkedIn post by ID.

get_linkedin_postsGPT Action

List LinkedIn posts for a site. Filter by status (draft, scheduled, published).

get_threadsGPT Action

List Threads posts for a site. Filter by status (draft, scheduled, queued, posting, published, failed).

get_threads_accountsGPT Action

List connected Threads accounts for a site.

get_threads_by_idGPT Action

Get a single Threads post (or chain) by ID.

get_tweetsGPT Action

List tweets/threads for a site. Filter by status (draft, scheduled, posted) and X account.

get_tweets_by_idGPT Action

Get a single tweet or thread by ID, including text, status, and posting details.

get_x_accountsGPT Action

List connected X (Twitter) accounts. Search by username or filter by site.

patch_linkedin_post_by_idGPT Action

Update a LinkedIn post draft. Only drafts can be edited — LinkedIn API does not support editing published posts. To correct a published post, delete it and create a new one.

patch_threads_by_idGPT Action

Update a Threads draft. Drafts only — published Threads posts cannot be edited via the Threads API.

patch_tweets_by_idGPT Action

Update an existing tweet or thread. Edit text, thread content, or metadata.

post_linkedinGPT Action

Create LinkedIn post draft. Before calling, fetch get_me + get_brand_voice. Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess. Required: content (max 3000 chars). For article/link shares (post_type='article'), you MUST provide article_title and article_description since LinkedIn does not auto-scrape URLs for API-created posts. To add a thumbnail, first call upload_media + attach_media_to_linkedin_post. ATTRIBUTION: links to user-owned domains in content (and article_url) are auto-tagged with utm_source=linkedin, utm_medium=social, utm_campaign at draft time. LINK TO BLOG POST: when this post distributes a known blog post, pass its post_id (UUID, from get_posts) so the /admin/posts Distribution column links them automatically — no manual backfill.

post_linkedin_by_id_carouselGPT Action

Generate and attach a PDF carousel to a LinkedIn post draft. Provide {topic, sourceMaterial?, slideCount?, theme?, tone?, allowImages?, imageGuidance?} to generate a spec, OR {spec} to render a pre-built spec. Renders PDF server-side, uploads to LinkedIn as a document, and attaches to the post. Post stays draft — call post_linkedin_by_id_publish to ship. IMAGES: Set allowImages=true to include images on slides. Each slide can have an image with source "library" (asset_id from media library), "generate" (AI-generated from a prompt), or "url" (external https URL). Use imageGuidance to steer image style. To add/change images after generation, use post_linkedin_by_id_carousel_refine with an instruction like "add an image to slide 2" then re-render by calling this tool with the returned spec.

post_linkedin_by_id_carousel_refineGPT Action

Refine an existing carousel spec with a natural-language instruction (e.g., "swap slide 3 for a stat", "make cover punchier", "add an image to slide 2", "more variety — too many lists"). Supports adding, changing, or removing images on any slide. Returns the updated spec. Does NOT re-render the PDF — call post_linkedin_by_id_carousel with the returned spec to render and attach.

post_linkedin_by_id_publishGPT Action

Publish a LinkedIn post immediately. Requires confirm: true.

post_linkedin_by_id_scheduleGPT Action

Schedule a LinkedIn post for future publishing. Provide a datetime via scheduledFor. Requires confirm: true.

post_linkedin_campaignGPT Action

Create multi-post LinkedIn campaign with scheduled or draft posts. Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess. Owned-domain links are auto-tagged with UTM params (linkedin/social, per-item campaign slug). Requires confirm: true. LINK TO BLOG POST: pass a campaign-level post_id (UUID, from get_posts) to link every item to a blog post, or set post_id per item to override — the /admin/posts Distribution column then populates automatically with no manual backfill.

post_threadsGPT Action

Create a Threads post draft. Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess. Provide either content (single post) or thread[] (a multi-post chain). Threads enforces a 500-character limit per post and at most 1 hashtag per post — these are validated at draft time. For chains, each element publishes sequentially via reply_to_id; there is no batch endpoint. ATTRIBUTION: links to user-owned domains are auto-tagged with utm_source=threads&utm_medium=social&utm_campaign=<slug> at draft time — this tagging is applied BEFORE the 500-char validation, so the tagged URL length counts toward the limit. Budget ~70 chars of headroom per owned-domain link (keep authored content under ~430 chars when including a link). If validation fails, the error message shows authored length + UTM overhead separately. LINK TO BLOG POST: when this post distributes a known blog post, pass its post_id (UUID, from get_posts) so the /admin/posts Distribution column links them automatically — no manual backfill.

post_threads_by_id_postGPT Action

Publish a Threads draft immediately. For VIDEO posts the call may block for ~30s while Meta processes the container; text and image posts publish quickly. For chains, walks each element sequentially via reply_to_id; on partial failure a retry resumes from the last successful element. On success returns `threads_post_id` and `threads_post_url` (the public permalink) — surface the URL to the user so they can verify the post. Requires confirm: true.

post_threads_by_id_scheduleGPT Action

Schedule a Threads draft for future publishing. Provide a datetime via scheduledFor (also accepts scheduled_for / schedule_at). The scheduler runs every 5 minutes. Requires confirm: true.

post_threads_campaignGPT Action

Create a multi-post Threads campaign of drafts or scheduled posts. Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess. Each net-new post in the campaign consumes one slot of the 250-posts/24h profile rate limit (chain children and replies do not). Sequential chain publishing means total wall time scales with chain length. Owned-domain links are auto-tagged with UTM params (threads/social, per-item campaign slug). Requires confirm: true. LINK TO BLOG POST: pass a campaign-level post_id (UUID, from get_posts) to link every item to a blog post, or set post_id per item to override — the /admin/posts Distribution column then populates automatically with no manual backfill.

post_threads_replyGPT Action

Create a Threads reply draft (replies do NOT count toward the 250-posts/24h profile rate limit — only net-new posts do). Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess. Required: content, reply_to_id (the Threads post id you're replying to). Owned-domain links in content are auto-tagged with utm_source=threads, utm_medium=social, utm_campaign. Use post_threads_by_id_post to publish.

post_tweetsGPT Action

Create tweet draft. Before calling, fetch get_me + get_brand_voice (+ get_ai_context/get_recent_notes). Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess. Required content: text or thread. To attach an image to the tweet, first upload with upload_media, then call attach_media_to_tweet with the returned asset_id and this tweet's id. ATTRIBUTION: links to user-owned domains will have UTM parameters (utm_source=twitter, utm_medium=social, utm_campaign=...) automatically appended at draft time so traffic shows up in GA4 instead of as Direct — you can also include them yourself if you prefer explicit campaign slugs. LINK TO BLOG POST: when this tweet distributes a known blog post, pass its post_id (UUID, from get_posts) so the /admin/posts Distribution column links the social post to the blog post automatically — no manual backfill.

post_tweets_by_id_postGPT Action

Publish a tweet or thread to X (Twitter) immediately. Requires confirm: true.

post_tweets_by_id_scheduleGPT Action

Schedule a tweet or thread for future posting on X. Provide a datetime via scheduledFor.

post_tweets_campaignGPT Action

Create a multi-tweet campaign with scheduled or draft tweets. Each item can be a single tweet ({ text }) or a thread ({ thread: [{ text }] }), with an optional scheduled_for datetime. Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess. Owned-domain links are auto-tagged with UTM params (utm_source=twitter, utm_medium=social, utm_campaign per item) at draft time. LINK TO BLOG POST: pass a campaign-level post_id (UUID, from get_posts) to link every item to a blog post, or set post_id per item to override — the /admin/posts Distribution column then populates automatically with no manual backfill.

post_tweets_quoteGPT Action

Quote tweet an existing tweet on X. Provide tweet_id or tweet_url and your commentary text — the original tweet URL is appended so X renders a quoted-tweet card (works across all X API tiers). Owned-domain links in commentary are auto-tagged with utm_source=twitter, utm_medium=social, utm_campaign. Requires confirm: true.

post_tweets_replyGPT Action

Reply to an existing tweet on X. Provide tweet_id or tweet_url and reply text. Owned-domain links in the reply text are auto-tagged with utm_source=twitter, utm_medium=social, utm_campaign. Requires confirm: true.

post_tweets_searchGPT Action

Search recent tweets on X by keyword query. Returns matching public tweets.

Brains & Knowledge (6)

create_brainGPT Action

Create a new brain (knowledge base) for a site. A brain compiles a folder of markdown notes from a vault target into a single navigable knowledge map. Before calling: (1) call get_repo_targets to find the vault target name the user wants to read from, (2) if the user has access to multiple sites, pass domain or site_id — for single-site users this is optional. source_folder_path is optional — if omitted, the server auto-generates "brains/{slug}" as a dedicated subfolder so the brain has an isolated source directory. After creation, call update_brain to add the founding note; the brain compiles automatically via the GitHub webhook once the first note is committed to the source folder. Call get_brain afterwards to check compilation status.

get_brainGPT Action

Get the compiled knowledge map for a brain. Returns a manifest of all source notes with IDs and summaries. To read the full content of any individual note, call get_note with the note ID from the manifest. Brains are site-agnostic — no domain or site_id needed. When a brain exists but has not yet been compiled the response includes status: "pending" — call update_brain to add the first note, which triggers compilation automatically via the GitHub webhook.

list_brainsGPT Action

List all brains accessible to the authenticated user. Returns each brain's id, name, status, note count, and last compiled timestamp. Brains are site-agnostic — no domain or site_id needed.

share_brainGPT Action

Share a brain with an external recipient via email. The recipient receives a clean summary of the brain and can reply to a unique reply-to address; their reply is parsed, attributed, and written back into the brain as an external-input note. The recipient does not need a BlackOps account. Use this when the user says "share this brain with X", "invite X to contribute", or "send a summary of the brain to X". Call list_brains first if you do not already have the brain_id.

unshare_brainGPT Action

Revoke an active brain share. Future replies to the share address are dropped and trigger an auto-reply telling the sender the address is no longer recognized. Pass either share_id (preferred — returned from share_brain) or recipient_email (revokes all active shares of this brain to that recipient). The audit trail of prior inbound replies is preserved.

update_brainGPT Action

Add a new note to a brain's source folder — no target_id or file path knowledge required. The server resolves the vault target and source folder from the brain record and writes the note directly. Use this whenever the user says "update the brain", "add this to the brain", or "log this in the brain". Call list_brains first to get the brain_id if you don't already have it. After writing, the note will be picked up on the next brain compile. Use post_notes_write (with brain_id) only when you need lower-level control over the filename or relative path.

Capture & Import (6)

get_brand_designGPT Action

Get visual brand design settings for a site: accent color, background color, text color, font family, logo URL, favicon URL, and default voiceover voice ID. Use this to understand the site's visual identity when creating videos, carousels, or other branded assets.

get_capture_sessionGPT Action

Get a capture session by ID. Returns full session including meeting transcript, reactions transcript, fusion output, and the generated Note (if fusion is complete).

list_capture_sessionsGPT Action

List recorded meeting/capture sessions for a site. Returns session id, meeting metadata, fusion status, generated note id, and progress. Filter by status: pending | running | completed | failed.

patch_brand_designGPT Action

Update visual brand design settings conversationally: accent color, background color, text color, font family, logo URL, favicon URL, or voice IDs. Only the fields you provide are changed — all others remain unchanged. Before calling, show the user the intended changes and get confirm: true. Changes take effect immediately on the live site.

refuse_capture_sessionGPT Action

Re-run fusion on a capture session, optionally with a custom prompt to get a different output shape (e.g. only action items, or a status report). Returns immediately — poll get_capture_session to check progress.

transcribe_youtubeGPT Action

Transcribe a YouTube video and return the transcript synchronously. Accepts watch, youtu.be, embed, and shorts URLs. Returns { video_id, title, channel, duration_seconds, transcript_text, language, extraction_method, cached }. Reuses the same reservoir transcription pipeline (captions with optional whisper fallback). Cached by video_id; pass refresh=true to bypass the cache. Does not store the transcript in any reservoir — use post_reservoir_ingest separately if you want to persist it.

Reservoirs (6)

delete_reservoir_itemGPT Action

Permanently delete a reservoir item. Requires confirm:true. If the item has been referenced in generated content (times_referenced > 0), the call returns 409 — pass force:true to override. Prefer patch_reservoir_item with status:'archived' for non-destructive removal. Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess.

get_reservoirGPT Action

Get a single reservoir by id with full metadata, monitored keywords, and (by default) computed analytics: health score, content breakdown by source/type, recent activity, lineage. Pass include_analytics:false for a lighter response. Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess.

get_reservoir_itemGPT Action

Get a single reservoir item with full content (including transcript if present). Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess.

list_reservoir_itemsGPT Action

List items in a reservoir with filter/search/pagination. Default status: active. Valid sort values: added_at (default), updated_at, last_referenced_at, times_referenced, relevance_score, ai_reservoir_score, title. Note: created_at is aliased to added_at for back-compat. Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess.

list_reservoirsGPT Action

List all knowledge reservoirs for a site with item counts, monitored keywords, and last-activity dates. Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess.

patch_reservoir_itemGPT Action

Update fields on a reservoir item — useful for archiving (status: 'archived'), bookmarking, retagging, or correcting metadata. Non-destructive. Requires domain or site_id. If the user did not specify a site, call get_me to list their sites — use it automatically if only one, otherwise ask the user to choose. Do NOT guess.

Media (6)

delete_mediaGPT Action

Delete a media asset from the library and storage.

finalize_media_uploadGPT Action

Finalize a presigned URL media upload. Call this after uploading the file to the upload_url returned by upload_media. Validates the file exists and processes image dimensions/thumbnails.

get_mediaGPT Action

Get details for a single media asset including URL, dimensions, format, and metadata.

list_mediaGPT Action

Browse the site media library. Filter by kind (mcp-upload, blog-upload, etc.) or media_type (image, video). Returns paginated results.

patch_mediaGPT Action

Update an existing asset's alt_text, filename, and/or title. Use it to fix metadata after an upload — e.g. write alt text for bulk-upload siblings that came back empty, since you can see the images. Pass the asset id plus any fields to change; omitted fields are left unchanged.

upload_mediaGPT Action

Upload media to the site media library. Three modes: 1. URL mode — pass file_url + filename + content_type. The server fetches the URL and stores the bytes. Best when the asset is already hosted somewhere. 2. Interactive mode — pass nothing (or just domain/label). The server returns { url, token, expires_at }. Show the URL to the user; they open it in a browser, sign in, and upload one OR MORE images via the BlackOps quick-upload page, then click "Done". Use this for clipboard screenshots and local files the user pasted — it avoids round-tripping bytes through the model, and supports bulk (multiple images on one link). You may also pass filename, alt_text, and/or title here — they ride along on the handoff and are applied to the FIRST uploaded asset (additional images auto-generate their own). 3. Claim mode — pass token (from interactive mode). Returns all finalized assets once the user clicks "Done" (status="completed" with an assets[] array — one or many). Returns status="pending" while they are still uploading or have not clicked Done yet; poll again. Supports jpeg, png, webp, gif, mp4, webm, quicktime in URL mode. Quick-upload (interactive/claim) is image-only.

Analytics — GA4 & Search Console (17)

ga4_campaign_performanceMCP-only

UTM campaign performance for a site: sessions, users, key events, and conversion rate grouped by session campaign / source / medium, ranked by sessions. Lets you query traffic and conversions BY campaign rather than only by raw source. Note that some platforms (e.g. X/Twitter) strip UTM parameters, so those visits land under direct/none. Requires GA4 credentials configured in site settings.

ga4_conversionsMCP-only

GA4 conversions (key events) for a site: each conversion event with its occurrence count, converting sessions, converting users, and conversion rates against total sessions and users in the window. Answers "how many of our visitors actually signed up / started a trial / connected an integration". Requires GA4 credentials configured in site settings.

ga4_eventsMCP-only

Custom GA4 event counts for a site: event name, total occurrences, and unique users over a lookback window, ranked by count. Pass event_names to filter to specific events (e.g. sign_up, start_trial, connect_integration, first_publish). Use this to measure activation and engagement actions that session-level traffic tools cannot see. Requires GA4 credentials configured in site settings.

ga4_landing_page_conversionsMCP-only

Landing pages ranked by conversion rate for a site. Each landing page shows sessions, conversions, and conversion rate. Pass conversion_event to rank by a specific event (e.g. sign_up); omit it to rank by all key events. min_sessions filters out tiny-sample pages. Answers "which entry pages actually convert", which top-pages-by-pageviews cannot. Requires GA4 credentials configured in site settings.

ga4_site_comparisonMCP-only

Side-by-side traffic metrics for multiple sites in a single call. Pass the list of domains to compare. Uses Promise.allSettled so a misconfigured property does not fail the entire request.

ga4_site_searchMCP-only

Site search queries captured by GA4 (the view_search_results event): each search term with its count and unique users, ranked by frequency. Surfaces what a site's audience is actively looking for — content gaps and demand signals. Pass min_count to drop one-off long-tail queries. Requires GA4 credentials and site search instrumentation configured. Returns an empty term list when site search is not wired up on the property.

ga4_top_pagesMCP-only

Top pages on a site ranked by pageviews, with title, path, sessions, and average time on page. Requires GA4 credentials configured in site settings.

ga4_traffic_overviewMCP-only

Google Analytics 4 traffic overview for a site: sessions, users, pageviews, bounce rate, and average session duration over a lookback window. Requires GA4 credentials configured in site settings.

ga4_traffic_sourcesMCP-only

Traffic source/medium/channel breakdown for a site, ranked by sessions. Requires GA4 credentials configured in site settings.

ga4_trendMCP-only

Daily time-series for a single GA4 metric (sessions, users, pageviews, newUsers) over a lookback window. Requires GA4 credentials configured in site settings.

gsc_compare_periodsMCP-only

Compare Google Search Console performance across two date ranges with delta math built in. Returns winners, losers, and net change for the top-N queries or pages. Read-only. Requires GSC credentials configured in site settings and gsc_mcp_enabled.

gsc_index_statusMCP-only

Google Search Console indexing state for a list of URLs. Aggregates URL Inspection results into buckets (indexed, crawled-not-indexed, discovered-not-indexed, not-found, excluded). The most important GSC tool: it answers "is Google indexing my pages?". Read-only. Requires GSC credentials configured in site settings and gsc_mcp_enabled.

gsc_request_indexingMCP-only

Request that Google crawl and consider indexing a list of URLs. Use to push high-value URLs to the front of the crawl queue after content updates, force re-evaluation of "Crawled, currently not indexed" pages, or trigger initial indexing on freshly published URLs. Up to 10 URLs per call. Backed by the Google Indexing API with a 200/day per-site quota. Every URL is HEAD/GET pre-validated before submission so 404s and typos do not burn quota; invalid URLs are returned as skipped_invalid with a reason. Pass skipValidation=true only for intentionally-unreachable URLs (auth, maintenance, brand new). Every response includes quota_remaining, quota_total, quota_reset_at. On exhaustion the tool returns a structured response — it does not throw or retry. The first call for a given site prepends a one-time TOS disclosure (Google's Indexing API is officially scoped to job postings and livestream events; works for general content in practice). WRITE TOOL. Requires GSC credentials configured in site settings and gsc_mcp_enabled.

gsc_search_analyticsMCP-only

Google Search Console performance: queries, pages, countries, devices broken down by impressions, clicks, CTR, and average position. Read-only. Requires GSC credentials configured in site settings and gsc_mcp_enabled.

gsc_sitemapsMCP-only

List sitemaps submitted to Google Search Console for a property: status, last-read date, errors, warnings, submitted vs. indexed page counts. Pass includeUrls=true to also fetch and return the actual URL list for each sitemap (or child sitemaps for sitemap-index files). Read-only. Requires GSC credentials configured in site settings and gsc_mcp_enabled.

gsc_submit_sitemapMCP-only

Submit (or resubmit) a sitemap to Google Search Console. Use to push a fresh sitemap, force a refetch on a stale one, or notify Google after a sitemap structure change. Submitting an already-submitted sitemap is idempotent — Google treats it as a refetch request. WRITE TOOL. Requires GSC credentials configured in site settings and gsc_mcp_enabled.

gsc_url_inspectionMCP-only

Per-URL deep dive from Google Search Console: indexing state, last crawl, page-fetch state, robots.txt state, canonical, mobile usability, structured data verdict. Pass an array of URLs (1-50). For domain-wide indexing audits, prefer gsc_index_status. Read-only. Requires GSC credentials configured in site settings and gsc_mcp_enabled.

Video (11)

batch_videosGPT Action

Create multiple videos at once. Two modes: "variations" clones a base video with different content (for content series), "story-split" splits a long video into 15-second story segments. Platform pacing options: youtube, tiktok, instagram_stories, linkedin, twitter.

create_conversation_videoGPT Action

CHAT-ONLY scene builder. Produces a video with the parsed conversation as the entire content — no hook, no stat, no CTA. **Use this only when the user explicitly asks for a chat-only artifact** ("just the conversation," "raw chat video," "no bookends"). For shareable assets — proof stories, demos, case studies, marketing videos, social posts — use `create_video` with `from_note_id` instead; that orchestrator auto-assembles hook → chat → CTA so the chat is framed by an opener and a close. Returns the video id ready for `render_video`.

create_videoGPT Action

Create a new video project. THIS IS THE ORCHESTRATOR — use it for any shareable asset (proof story, demo, case study, marketing video, social post). Two ways to use it: 1. **Full spec mode**: Provide `spec.scenes` with templateId + slots for every scene (use `list_templates` to see templates: hook, chat-demo, stat, cta, pipeline, comparison, impact, quote, feature-grid, code-block, browser-frame, phone-frame). 2. **Conversation mode**: Pass `from_note_id` (a saved BlackOps conversation note). Without explicit scenes this auto-assembles **hook (from note title) → chat-demo (parsed conversation) → cta (brand close)** — a complete shareable asset, not a chat scroll. With explicit scenes, replace any scene whose templateId is "chat-from-note" with the parsed conversation. Tune chat behavior via `conversation` (voiceover_text, voice_id, max_messages, chat_style, duration, input_placeholder); override copy via `hook` and `cta`. IMPORTANT: Each scene supports a voiceover object with "text" (narration) and optional "voiceId" (ElevenLabs voice ID). If the user does not specify whether they want voiceover, ASK before creating. After creating, call generate_voiceover to produce audio. Use `create_conversation_video` ONLY when the user explicitly asks for a chat-only artifact with no hook/CTA.

delete_videoGPT Action

Delete a video and all its exports and segments.

generate_voiceoverGPT Action

Generate ElevenLabs voiceover audio for all scenes that have voiceover.text set. Automatically sizes scene durations to fit the narration. Call this after create_video or update_video when scenes include voiceover text. The audio will be mixed into the final MP4 when render_video is called. Voice fallback chain: per-scene voiceover.voiceId → video-level voiceId param → site custom_voice_id → site default_voice_id → Brian. Users can paste any ElevenLabs voice ID as their custom voice in Settings > Branding. Use list_voices to see curated voices, or use get_brand_design to check the site's configured voice.

get_videoGPT Action

Get a video by ID, including its exports (rendered files), segments (per-scene renders), and media_assets (auto-registered media library entries). When status === "rendered", the response includes media_assets[0].id — pass THAT asset_id directly to attach_media_to_tweet or attach_media_to_post (do NOT call list_media first, do NOT pass a raw URL). Rendered videos are automatically added to the media library; the asset_id is available here.

list_templatesGPT Action

List available video scene templates. Each template defines slots (content placeholders) that can be filled when creating scenes. Templates: hook (headline), chat-demo (chat UI), stat (metric counter), cta (call to action).

list_videosGPT Action

List all videos for a site. Returns id, title, status, format, duration, and progress.

list_voicesGPT Action

List available ElevenLabs voices for voiceover. Returns curated catalog with voice ID, name, gender, accent, and description. Use the voice ID in create_video (per-scene voiceover.voiceId) or generate_voiceover (voiceId param).

render_videoGPT Action

Trigger an async render job for a video. Returns immediately with a progress page URL — poll get_video to check status (generation_progress, generation_stage). Quality: draft (fast), standard, high. IMPORTANT: When status becomes "rendered", the MP4 is AUTOMATICALLY registered as a media library asset. The get_video response will include `media_assets[0].id` — pass THAT asset_id directly to attach_media_to_tweet or attach_media_to_post. Do NOT call list_media first, and do NOT pass a raw URL to attach_media_*. The full pipeline is: render_video → poll get_video until rendered → use media_assets[0].id → attach_media_to_tweet → post_tweets.

update_videoGPT Action

Update a video's title, spec (scenes, brand, format), or status. Provide only the fields to update.

Deprecated (2)

Still callable for one migration cycle, but slated for removal — prefer the replacement named in each description.

get_posts_by_idDeprecated

DEPRECATED — use get_post. Retained as an alias for one migration cycle. Fetch a single blog post by slug or UUID, including full content, metadata, and SEO fields.

post_notes_writeDeprecated

DEPRECATED — use post_notes instead. This tool writes a markdown file to a repo target WITHOUT creating a queryable BlackOps note record, which causes silent failures: the file exists but get_note returns 404, downstream tools that need a note_id break, and the artifact is invisible to list_notes / search / brain compile. post_notes already auto-syncs to the connected Obsidian vault (returns a sync.commitSha in the response), and is the correct entry point for note creation. Only call post_notes_write when the user has explicitly asked for a raw repo file write with no BlackOps record — which is rare and almost always a mistake. Required: markdown_content plus EITHER target_id OR brain_id. PATH CONTEXT: relative_path must be relative to the target's base_path — do NOT include the base path prefix. Example: if the target's base_path is /notes/cap/AI and the desired full path is /notes/cap/AI/personal-brand/file.md, set relative_path: personal-brand/file.md. Call get_repo_targets first to inspect each target's base_path before constructing paths.