Skip to main content
Glama

PostKing MCP Server

npm version License: MIT MCP

The official Model Context Protocol server for PostKing — an AI-powered content platform for social media scheduling, blog publishing, and brand management.

Connect Claude (Desktop, Cursor, or any MCP client) to your PostKing account and manage your entire content operation through conversation — generate posts, schedule them, repurpose URLs into social content, write and publish blog articles, generate landing pages and side pages, run SEO / GEO research and drafting, manage your asset library and weekly posting schedule, handle domains and API keys, and more.

The server exposes 291 tools across 33 modules — full parity with the postking-cli.

Transport note: All 291 tools are registered on both transports, including on the remote HTTP transport (mcp.postking.app). The 4 authentication tools (login_start, login_complete, logout, whoami) stay registered there too — they just explain the OAuth bearer-token model instead of running a device-code flow, since that transport is already authenticated before any tool call happens.


Quick start

Claude Desktop

Option A — Via the GUI:

  1. Open Claude Desktop → Settings (gear icon) → Developer → Edit Config

  2. This opens claude_desktop_config.json in your default editor

  3. Paste the following and save:

{
  "mcpServers": {
    "postking": {
      "command": "npx",
      "args": ["-y", "postking-mcp"]
    }
  }
}
  1. Restart Claude Desktop

Option B — Edit the config file directly:

Open ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows) in any text editor, paste the same JSON above, and save.

Once restarted, tell Claude: "Login to PostKing"

Claude Code (CLI)

claude mcp add postking -- npx -y postking-mcp

Hermes

npm i -g postking-mcp
hermes mcp add postking --command postking-mcp

Then in Hermes: "Login to PostKing".

Cursor / other MCP clients

Use the same npx -y postking-mcp command in your client's MCP server config.


Related MCP server: social0-mcp

Login flow

No API keys to copy. PostKing uses a device login flow:

  1. Tell Claude: "Login to PostKing"

  2. Claude calls login_start → shows a URL and short code

  3. Visit the URL in your browser, log in, approve

  4. Tell Claude: "Done"

  5. Claude calls login_complete → saves your token to ~/.postking/credentials.json

You never need to log in again. The token is permanent.


What you can do

Authentication

Available on stdio/local transport only. Remote HTTP transport authenticates via OAuth bearer token before the session is created.

Tool

Description

login_start

Begin device login — get a URL and code to approve in browser

login_complete

Finish login and save token after browser approval

logout

Clear locally stored credentials

whoami

Return the profile of the currently authenticated user (email, plan, credit balance)

Brands

Tool

Description

list_brands

List all brands on your account

set_active_brand

Set the default brand for this session

get_brand_info

View brand profile — tone, audience, themes

create_brand

Create a brand manually (step 1 of manual onboarding)

onboard_brand

Crawl a website and auto-generate a brand profile + 10 themes (step 1 of website onboarding)

set_brand_mediums

Save the list of platforms the brand publishes on (step 2 of onboarding)

get_brand_mediums

Read which publishing platforms a brand posts to

get_brand_content_language

Read the language a brand's AI-generated content is written in, plus the supported set

set_brand_content_language

Set the generation language for all future content — en, es, pt-BR, de, fr, cs

get_onboarding_status

Poll background audience analysis + theme generation (step 3 of onboarding)

Content themes

Tool

Description

list_themes

List all content themes with IDs

generate_themes

AI-generate new themes (uses credits)

edit_theme

Update a theme's title or instructions

delete_theme

Remove a theme

Social posts

Tool

Description

generate_post

AI-generate a post for a platform

create_post

Save a manual post draft to one or more platforms

list_posts

List posts filtered by status or platform

get_post

View a single post

approve_post

Approve and schedule a draft post

schedule_post

Set a scheduled time on an existing post

reschedule_post

Move a scheduled post to a new time

update_post

Replace a draft or scheduled post's text

reply_to_x_post

Reply to an X (Twitter) post from the brand's account (PRO plan and above)

cancel_post

Cancel a scheduled post without deleting it

delete_post

Cancel and delete a post

get_calendar

View upcoming scheduled content

generate_bulk_posts

Fill a date range with AI-generated posts

Repurpose

Tool

Description

repurpose_content

Turn a URL, text, or existing post into new social or blog content

Voice profiles

Tool

Description

list_voices

List available voice profiles

rewrite_with_voice

Rewrite text in a specific voice

Social accounts

Tool

Description

check_social_accounts

List connected and disconnected platforms

generate_connect_link

Get a secure OAuth link to connect a platform

disconnect_social_account

Disconnect a social account

Reddit

Reddit is a repurpose-to-Reddit workflow, not a scheduled publishing medium. Flow: reddit_generate_pool → reddit_get_pool → reddit_suggest → reddit_rewrite → reddit_list_posts.

Tool

Description

reddit_get_pool

View the brand's saved pool of relevant subreddits, sorted by relevance score

reddit_generate_pool

Async: discover and score relevant subreddits for the brand by crawling Reddit

reddit_global_pool

Return stats on the global subreddit dataset (informational only)

reddit_discover_subreddits

Sync: search Reddit for subreddits by user-directed queries (with free-text disambiguation context), ranked by subscribers and flagged against the brand pool — 15 credits per call

reddit_add_to_pool

Add subreddits to the brand's pool by name (resolves live from Reddit; partial success reported per name) — free

reddit_remove_from_pool

Remove subreddits from the brand's pool by name (brand-scoped only; never touches the global cache) — free

reddit_suggest

Sync: suggest up to 8 best-fit subreddits for a specific piece of content, each with 2-3 posting angles, promotion mode, and buyer intent

reddit_rewrite

Async: rewrite a blog article or raw content as a native Reddit post for a target subreddit

reddit_list_posts

List saved Reddit posts (outputs of reddit_rewrite), cursor-paginated

Blog

Tool

Description

list_blogs

List publications and articles (filterable by status)

list_publications

List publications only

create_publication

Create a new blog publication

update_publication

Update an existing publication's title, description, domain/routing, or layout (partial update)

generate_blog_post

AI-generate a full blog article with optional voice

get_blog_article

Fetch full article content, including the featured/header image (featuredImageUrl, featuredImageAlt, featuredImageDescription)

get_blog_status

Poll generation/publish status for an article

update_blog_article

Edit title, content, SEO fields, author, category, status, or the featured/header image (featuredImageUrl, featuredImageAlt, featuredImageDescription)

delete_blog_article

Permanently delete an article

blog_cta_list

List every CTA on an article individually, with raw anchor data — find a ctaId or an open anchor slot

blog_cta_add

Append a new CTA to an article without touching the existing ones

blog_cta_update

Edit one CTA by id (url/label/headline/body/style/anchor/sidePageId/slug) without touching the others

blog_cta_delete

Remove one CTA by id without touching the others

publish_blog_article

Push to WordPress, Medium, Substack, etc.

list_publishing_connections

List external platform connections

import_blog_articles

Import from RSS feed or Blogger URL

list_blog_authors

List blog authors

create_blog_author

Create a new blog author

list_blog_categories

List categories for a publication

create_blog_category

Create a new category

get_seo_roadmap

View SEO / GEO topic suggestions and completion stats

SEO / GEO

Canonical flow: seo_add_seeds → seo_generate_keywords → seo_categorize → seo_generate_clusters → approve clusters → seo_generate_roadmap → review briefs → seo_approve_briefs (auto-fires article generation) → poll get_job → audit & publish.

Tool

Description

seo_add_seeds

Seed SEO / GEO research with 3–10 topic keywords

seo_generate_keywords

Async: expand seeds into a full keyword universe (poll via get_job)

seo_list_keywords

List researched keywords with intent, priority, and volume

seo_edit_keyword

Edit a keyword — override intent, adjust priority, set user tags, or exclude from clustering

seo_delete_keyword

Soft-delete a single keyword from the research set

seo_categorize

Tag keywords by search intent and/or user tags

seo_generate_clusters

Async: group keywords into topic clusters (poll via get_job)

seo_list_clusters

List keyword clusters with brief-generation status

seo_bulk_approve_clusters

Bulk-approve N clusters in one call, kicking off async brief generation for each

seo_approve_cluster

Approve a single cluster, gating brief generation for it

seo_reject_cluster

Reject a single cluster — marks it rejected and detaches its keywords

seo_bulk_reject_clusters

Bulk-reject N clusters in one call

seo_unapprove_cluster

Revert an approved cluster back to pending_review

seo_restore_cluster

Restore a rejected cluster back to pending_review

seo_generate_roadmap

Turn one or more clusters into a prioritized content roadmap

seo_list_roadmap

List roadmap items (blog topics queued for writing)

seo_roadmap_get

Fetch a single roadmap item

seo_roadmap_edit

Edit a roadmap item's title, status, or priority

seo_roadmap_delete

Permanently delete a roadmap item

seo_roadmap_stats

Roadmap completion stats

seo_list_briefs

List content briefs across all clusters and statuses

seo_get_brief

Fetch a single brief including its full structured outline

seo_edit_brief

Edit a brief's structured outline or approve/reject it

seo_approve_briefs

Bulk-approve briefs and auto-fire article generation

seo_regenerate_brief

Re-run brief generation for a single brief

seo_resolve_brief_truths

Re-resolve the brand truths a brief's page is written from

seo_list_results

List generated results (blog articles, side pages, comparisons) from the SEO pipeline

seo_write_article

Manual path: draft a blog article from a roadmap item (use only when not going through seo_approve_briefs)

seo_gap

Find keyword / topic gaps vs. existing content

seo_competitor

Compare keyword coverage against a competitor domain

seo_publish_article

Publish or schedule an SEO-drafted article to a publication

seo_auto_assign_cta

Auto-suggest and assign side-page CTAs to published blog articles

seo_generate_side_page

Generate a side page optionally linked to an SEO cluster

Landing pages

Tool

Description

list_landing_pages

List all landing pages for a brand

generate_landing_page

Create and AI-generate a new landing page (async; poll via get_job)

import_landing_page_bundle

Import a static-build bundle (entry HTML + assets) hosted at URLs — for a local folder, use the postking-cli import-bundle command instead

view_landing_page

View a landing page including full section content

view_lp_draft

View the current unpublished draft

edit_landing_page

Edit landing page title or instructions (metadata only — does not touch page content)

set_landing_page_section

Set one field (dot-path) or replace a whole section on a landing page's draft

regenerate_landing_page

Re-generate a landing page's content using AI (async; poll via get_job)

vibe_edit_landing_page

Apply a natural-language AI edit to a landing page (async; propose → review → apply flow)

get_vibe_edit_status

Poll vibe-edit session status and review the field-level changes diff

apply_vibe_edit

Apply a completed vibe edit (all or a subset) to the draft as one new version

set_lp_section_layout

Reorder and/or toggle visibility of landing page sections

publish_landing_page

Publish the current draft

delete_landing_page

Permanently delete a landing page

list_lp_versions

List historical versions of a landing page

view_lp_version

View a specific historical version

restore_lp_version

Roll the draft back to a prior version

delete_lp_version

Permanently delete a historical version

list_side_pages

List side pages attached to a landing page

generate_side_page

AI-generate a side page under a parent landing page (async; poll via get_job)

view_side_page

View a side page including sections and rendered HTML

edit_side_page

Update the instructions or metadata of a side page

set_side_page_section

Update the content of a specific section within a side page

set_side_page_state

Publish or unpublish a side page

delete_side_page

Delete a side page

Weekly schedule

Tool

Description

get_weekly_schedule

Fetch the active weekly posting schedule

set_weekly_schedule

Configure platforms, times, and themes per day

enable_weekly_schedule

Turn the weekly auto-generator on

disable_weekly_schedule

Turn the weekly auto-generator off

delete_weekly_schedule

Remove the schedule entirely

run_weekly_schedule_day

Generate a single day's posts on demand

Visuals (asset library)

Tool

Description

list_assets

List brand assets (images/videos) with filters

view_asset

Fetch a single asset's metadata and URL

upload_asset

Upload an image/video (base64)

import_asset_from_url

Pull an asset from a remote URL

import_assets_csv

Batch-import up to 50 assets from a list of public URLs

tag_asset

Add or remove tags on an asset

delete_asset

Remove an asset (requires confirm)

list_asset_tags

List all tags used across assets

suggest_assets_for_post

Get AI-suggested assets for a specific post

search_stock_images

Search stock-photo libraries

Post visuals (cards & carousels)

Tool

Description

generate_post_visual_options

Fetch available visual options for a post (card templates, library matches, stock photos)

regenerate_post_visual

Refresh stock photos and quote/card templates for a post (does not re-match library assets)

pick_post_visual

Select a template/stock visual, or attach one or more of your own library assets, for a post on a given platform

clear_post_visual

Remove the selected visual from a post

list_post_cards

List the carousel cards attached to a post

edit_post_card

Edit a single carousel card by 1-based index

set_post_cards

Bulk-replace all carousel cards for a post

generate_post_carousel

Render a carousel PDF from the current cards

Jobs (async poller)

Tool

Description

list_jobs

List recent async jobs for the active brand

list_operations

List recent Operations (the newer async-op system) with kind and state filters

get_job

Poll a specific operation by ID or pollUrl; supports wait=true to block until done

cancel_job

Cancel a pending or running job/operation by operationId

API keys (self-service)

Tool

Description

list_api_keys

List your PostKing API keys

create_api_key

Mint a new API key

revoke_api_key

Revoke an API key (requires confirm)

Domains

Tool

Description

list_domains

List domains with verification and SSL status

add_domain

Add a new custom domain

verify_domain

Check DNS and activate a domain

delete_domain

Remove a domain (content is preserved)

connect_domain_to_publication

Wire a verified domain to a blog publication

Writing tools

Tool

Description

rewrite_text

Rewrite text using a voice profile or brand rules

humanize_text

Reduce AI detection signals in text

check_ai_content

Score text for AI detection likelihood

get_credits

Check your current credit balance and free-tier status

health

Check PostKing API health and version (no authentication required)

Storylines (marketing plans)

Canonical flow: storyline_create → storyline_clarify (loop) → storyline_generate_brief (poll) → storyline_get → storyline_edit_brief → storyline_confirm_brief → storyline_generate_strategy (poll) → curate line items → storyline_estimate → storyline_execute (poll).

Tool

Description

storyline_list

List the brand's storylines (marketing plans)

storyline_create

Create a new storyline with a campaign goal or intent prompt

storyline_get

Fetch a single storyline with full state (brief, strategy, line items, status)

storyline_update

Update storyline metadata: title, live status, or start/end/launch dates

storyline_delete

Archive (soft-delete) a storyline — reversible via storyline_restore

storyline_restore

Restore an archived storyline back to active state

storyline_clarify

Run the intake/clarification step (iterative Q&A until system has enough context)

storyline_generate_brief

Async: generate the marketing brief — positioning, key messages, audience, timing (poll via get_job)

storyline_set_brief

Manually set (replace) the full brief for a storyline

storyline_edit_brief

AI-edit the brief using natural-language instructions

storyline_confirm_brief

Confirm the brief and gate strategy generation

storyline_get_strategy

Fetch the generated strategy and its line items

storyline_generate_strategy

Async: generate the execution strategy and line item set (poll via get_job)

storyline_edit_strategy

AI-edit the strategy using natural-language instructions

storyline_estimate

Dry-run credit estimate for executing the storyline

storyline_add_line_item

Add a new content line item to the strategy

storyline_update_line_item

Edit an existing line item (channel, type, title, selected flag, etc.)

storyline_delete_line_item

Permanently remove a line item from the strategy (confirm: true required)

storyline_regenerate_line_item

Async: regenerate a single strategy line item (poll via get_job)

storyline_execute

Async: generate all selected drafts from the strategy (poll via get_job)

Competitors (intelligence)

Canonical flow: competitor_probe → competitor_probe_status → competitor_probe_classify → competitor_add (poll) → competitor_analyze (poll) → competitor_list → competitor_get_comparison/recompute → competitor_get_overview/generate_overview (poll). Namespace: competitor_* (distinct from seo_competitor/seo_gap).

Tool

Description

competitor_list

List tracked competitors with status, analysis state, and a dashboard deep-link

competitor_add

Async: batch-add 1–20 competitor domains and trigger crawl + profile analysis (poll via get_job)

competitor_update

Update competitor settings — e.g. toggle excludeFromSeoPull

competitor_delete

Soft-delete a tracked competitor (restorable via competitor_update with empty body)

competitor_analyze

Async: re-analyze pending or failed competitor rows (poll via get_job)

competitor_refresh

Async: refresh all active competitors — re-crawl + re-profile (poll via get_job)

competitor_get_comparison

Get the brand's head-to-head competitive comparison

competitor_recompute_comparison

Trigger a fresh comparison recompute (call after adding/analyzing competitors)

competitor_get_overview

Get the saved competitive landscape overview

competitor_generate_overview

Async: generate a fresh AI-synthesized landscape overview (poll via get_job)

competitor_comparison_sources

List SEO keyword sources that feed the competitive comparison

competitor_probe

Async: discover and surface rival domain candidates based on the brand (poll via get_job)

competitor_probe_status

Check the status of a probe run and list discovered candidates

competitor_probe_classify

Classify a probe candidate as add, skip, or blacklist

Knowledge base

Canonical flow: knowledge_list → knowledge_get → knowledge_create (poll get_job) → knowledge_update → knowledge_delete.

Tool

Description

knowledge_list

List knowledge base items — filter by tag, active status, or global flag

knowledge_create

Async: create a knowledge base item with optional AI enrichment (poll via get_job)

knowledge_get

Fetch a single knowledge base item with full content and metadata

knowledge_update

Update a knowledge base item's name, description, content, or tags

knowledge_delete

Soft-delete a knowledge base item

Brand truth

Atomic facts/observations about a brand (hard facts, audience truths, strategy notes, negative space, content insights, topics) used to ground generation. Brand truths are maintained by PostKing's own model — callers never write name/description/content/type/tags/personaScope directly. Canonical flow: brand_truth_list → brand_truth_get → brand_truth_create (LLM extraction decides what to store) → brand_truth_update (LLM-mediated correction, or pin toggle) → brand_truth_delete (soft) → brand_truth_restore if needed.

Tool

Description

brand_truth_list

List stored brand truths — filter by type, personaScope, tags, or free-text query; includeDeleted to also see soft-deleted rows

brand_truth_get

Fetch a single brand truth with full content and metadata

brand_truth_create

Describe facts in plain language; an LLM extraction pipeline decides which atomic truths to store vs skip (returns added + skipped)

brand_truth_update

Describe a correction in plain language and/or toggle pinned; PostKing's model decides whether/how to rewrite the entry (may refuse with applied:false + reason) — never a direct field edit

brand_truth_delete

Soft-delete a truth (undoable) and record rejection memory so it stops being re-suggested

brand_truth_restore

Undo a brand_truth_delete — clears deletedAt and the rejection memory

Audience / ICP

The brand's audience intelligence (ideal customer profile) mined from its website + onboarding. Canonical flow: get_audience → preview_audience_edit (discover valid sections) → edit_audience (async LLM ai-edit; poll get_job).

Tool

Description

get_audience

Fetch the brand's ICP — structured audienceData, positioning, ghostwriter persona, and contentModulation (short/medium/full)

preview_audience_edit

Read-only: discover which sections/subsections are valid to edit for this brand before calling edit_audience

edit_audience

Async LLM ai-edit of the audience/ICP (sections required; poll via get_job) — returns already_running if an edit is in flight

Canonical flow: trends_list → template_extract OR (template_list + template_pick) → template_create → existing post-generation tools. Note: trends_list is account-scoped (no brand required).

Tool

Description

trends_list

List trending posts by niche and platform — account-scoped, no brand required

template_list

List saved content templates for the brand

template_create

Save or build a new content template

template_update

Update a template's title, content, or favorite flag

template_delete

Delete a saved content template

template_extract

AI: deconstruct a trending post into a reusable content template

template_pick

AI: score and rank existing templates for a given theme or content goal

Billing (agent wallet + subscription)

Canonical flow (one-off): billing_list_packs → billing_topup → (Stripe Link or browser) → billing_wallet (poll until balance rises). Subscription: billing_list_tiers → billing_subscribe → (human or first-invoice Link) → subscription activates automatically.

Tool

Description

billing_list_packs

List available agent credit packs with SKU, price, and credit amount

billing_topup

Create a Stripe Checkout session to top up the agent wallet with a one-off credit pack

billing_wallet

Fetch the agent's prepaid credit balance and recent ledger entries

billing_list_tiers

List available PostKing subscription tiers with pricing and monthly credits

billing_subscribe

Create a Stripe Checkout session for a GROWTH, PRO, or ENTERPRISE subscription

Search performance & AI visibility

Canonical flow: search_sources (is a connector even live?) → search_performance (SEO clicks/impressions/CTR/position) → search_ai_visibility / search_ai_citations (AI-answer-engine visibility) → search_worklist ("do this next", synthesized from all of the above).

Tool

Description

search_sources

List the brand's connected search-performance sources (Google Search Console, Bing Webmaster, Google Analytics) with status and last sync time

search_performance

Search Console (Google/Bing) + GA4 performance readout — clicks, impressions, CTR, position; section-selectable (summary/queries/pages/timeseries)

search_ai_visibility

Deep AI Dive (GEO) visibility readout — mention/citation coverage vs. competitors across AI answer engines (Google AI Overview, ChatGPT, Perplexity, Claude), by topic. Requires PRO+ tier

search_ai_citations

Bing "AI Performance" citation readout — daily citation counts plus the latest grounding-query and cited-page snapshots from an imported CSV export

search_worklist

Ranked "do this next" SEO + GEO worklist synthesized from the tools above

Dashboard

Tool

Description

dashboard_link

Get a clickable browser URL to any section of the PostKing dashboard (overview, SEO, posts, blogs, landing pages, reddit, storylines, knowledge, trends, competitors, search performance, jobs, etc.)


Guided prompts

The server ships with built-in prompts accessible from the prompt picker in Claude Desktop:

Prompt

Description

getting_started

First-time setup: login → brand → connect → first post

repurpose_and_schedule

URL/text → repurpose → draft → approve → calendar

connect_social_accounts

Check and connect LinkedIn, X, Instagram, Threads, Facebook

manage_posts

View, reschedule, and delete posts

manage_themes

Generate, edit, and organize content themes

blog_publishing

Generate, edit, and publish blog posts

use_voice_profiles

Apply a voice style to generated or rewritten content

plan_storyline_campaign

Full marketing storyline: clarify → brief → strategy → curate → execute

competitor_intelligence

Build competitive intelligence: probe → add → analyze → comparison → overview

manage_knowledge_base

Browse, create, update, and soft-delete brand knowledge base items

trends_to_post

Browse trending posts, extract/pick a template, then generate a post


Example workflows

Repurpose a blog post to LinkedIn and X:

"Repurpose https://myblog.com/my-article for LinkedIn and X, using my brand voice"

Generate and schedule a week of content:

"Generate 7 LinkedIn posts using my growth themes, schedule them daily at 9am starting Monday"

Write and publish a blog post:

"Write a 1500-word post about AI productivity tools, publish it to my blog"

Import and repurpose existing content:

"Import the last 20 posts from https://myblog.com/feed and convert the top 5 into LinkedIn posts"


Requirements


Publishing to external platforms

PostKing supports publishing blog articles directly to:

  • WordPress (via REST API)

  • Medium

  • Substack

  • Webflow

  • Any platform with a publishing connection

Set up connections in your PostKing dashboard under Blog → Publishing Connections, then use publish_blog_article from Claude.


Development

git clone https://github.com/bitsandtea/postking-mcp
cd postking-mcp
npm install
npm run build

Test locally by pointing Claude Desktop at the built file:

{
  "mcpServers": {
    "postking": {
      "command": "node",
      "args": ["/absolute/path/to/postking-mcp/dist/index.js"]
    }
  }
}

Environment variables

Variable

Default

Description

POSTKING_API_URL

https://try.postking.app

Override the API base URL

POSTKING_API_TOKEN

—

Skip device login by providing a token directly


Contributing

Issues and pull requests are welcome. This repo is the MCP client layer only — it calls the PostKing API and exposes tools to any MCP-compatible AI client. If you find a bug, want to add a tool, or improve the prompts, open an issue or PR.


License

MIT

Available Tools

243 tools
add_domainAInspect

Add a new custom domain to the active brand. After adding, call verify_domain to check DNS and activate it.

Inputs: domain (required), brandId, isPrimary, primaryContentType.

apply_vibe_editAInspect

Applies a completed vibe edit (from vibe_edit_landing_page) to the DRAFT as ONE new version. Pass exactly one of: all=true (accept every change), indices (subset by their index from get_vibe_edit_status), or paths (subset by their path). This does NOT publish — call publish_landing_page next to go live. Can be undone via restore_lp_version using the returned previousVersionId. If the draft has moved on since the edit was proposed (stale session), this returns a structured { error: 'stale_session', ... } payload instead of applying — either re-run vibe_edit_landing_page against the current draft, or retry this call with force=true to layer the selected changes onto the current draft.

Inputs: slug (required), operationId (required), all, name, +4 more.

approve_postAInspect

Approve and schedule a draft post. Requires a future datetime. The scheduledAt must be an ISO 8601 UTC datetime, e.g. 2026-03-11T09:00:00Z. After approving, the post status becomes 'scheduled'.

Inputs: postId (required), scheduledAt (required), timezone.

assign_asset_to_slotAInspect

Assign, reassign, or clear the asset in a landing-page or side-page slot. slotKey is a dotted key like 'hero.backgroundVideo' or 'cta.image' (discover valid keys with list_asset_slots). For array slots pass assetIds; for single slots pass assetId. The asset must already be in the brand's library (see list_assets / upload_asset / import_asset_from_url) and match the slot's media type. Pass sidePageSlug to target a side page. Set clear:true (or assetId:null) to empty the slot. Synchronous — the change applies immediately, no polling. Main-LP changes create a new draft version.

Inputs: slug (required), slotKey (required), clear, assetId, +3 more.

billing_list_packsAInspect

List available credit packs for one-off top-ups. Returns all packs with their SKU, price in USD, and credit amount. Call this tool first to show the user their options, then ask which pack they want. Only after the user explicitly chooses a pack, call billing_topup with that packSku.

Inputs: no named parameters.

billing_list_tiersAInspect

List available PostKing subscription tiers (GROWTH, PRO, ENTERPRISE). Returns each tier's name, price in USD, monthly credits, and billing interval options. Use billing_subscribe to create a subscription Checkout session for a chosen tier.

Inputs: no named parameters.

billing_subscribeAInspect

Create a Stripe Checkout session for a PostKing subscription. Returns { checkoutUrl, sessionId, tier, interval, amountUsd }. Subscription credits refill User.credits each billing period. The subscription Checkout is best completed by a human; the Link virtual card covers the first invoice only (renewals need a durable payment method).

Inputs: tier (required), interval.

billing_topupAInspect

Top up credits by charging the account's card on file (Stripe off-session). Prefers the headless path — no checkout link required. IMPORTANT: Only call this tool after the USER has explicitly chosen a specific pack — it triggers a real charge. To show the user their options first, call billing_list_packs and present the results; do NOT pick a pack on the user's behalf. The response is ONE OF two shapes: (1) Headless success (default when a card is on file): { status: 'paid', paymentIntentId, amountUsd, credits, balance, packSku, cardLast4/receiptUrl when available }. When you receive status === 'paid', the payment has already completed and the credits are in the wallet NOW. Announce to the user: payment ID, last-4 card digits, credits added, and new balance. You are DONE — do NOT call billing_wallet to poll. (2) Checkout fallback (only when there is no card on file): { checkoutUrl, sessionId, amountUsd, credits, packSku }. When you receive checkoutUrl, hand that link to the user so they can complete payment in their browser. Valid skus: agent_4 ($4 / 160 credits), agent_5 ($5 / 220 credits), agent_25 ($25 / 1200 credits), agent_50 ($50 / 2600 credits).

Inputs: packSku (required).

billing_walletAInspect

Fetch the user's credit balance and recent usage entries. Returns { credits, recent } where recent is the last ~10 usage rows. Poll this to confirm a top-up landed ONLY after a billing_topup CHECKOUT result (one that returned a checkoutUrl), until credits rise. Do NOT poll after a status:'paid' headless top-up — those credits are already applied and the new balance is in the topup response.

Inputs: no named parameters.

brand_truth_createAInspect

Capture brand truths from plain natural-language text. Describe facts/observations about the brand in ordinary prose — a sentence or short paragraph (≤8000 chars). Do NOT pre-classify, pre-format, or guess the taxonomy: PostKing's LLM extraction pipeline reads the text and decides which atomic 'brand truths' to persist and which to skip (duplicates, too vague, or previously rejected facts). Returns { addedCount, skippedCount, added, skipped }: 'added' are the truths that were stored; 'skipped' lists each rejected quote with a reason. Review both — the skipped reasons tell you what didn't make it in and why.

Inputs: text (required), brandId.

brand_truth_deleteAInspect

Delete a brand truth by ID. This also records rejection memory: the system learns to stop re-suggesting that fact during future extractions. Use it deliberately — deleting a truth teaches PostKing that the fact should not come back.

Inputs: id (required), brandId.

brand_truth_getAInspect

Fetch a single brand truth by ID. short {id,name,type,pinned}; medium adds personaScope+tags+summary+timestamps; full = raw (includes full content). Use detail='full' to retrieve the complete content body.

Inputs: id (required), detail, brandId.

brand_truth_listAInspect

List the brand's stored brand truths (atomic facts/observations used to ground generation). short {id,name,type,pinned}; medium adds personaScope+tags+summary+timestamps; full = raw. Filter by type, personaScope, tags (array or comma-separated), or a free-text query.

Inputs: tags, type, limit, query, +3 more.

brand_truth_updateAInspect

Targeted edit of an existing, known brand truth (by ID). This does NOT re-run the LLM extraction pipeline — it writes the provided fields directly. Use it to correct wording (name/description/content), fix the type/personaScope, adjust tags, or pin/unpin. To capture NEW facts from prose, use brand_truth_create instead.

Inputs: id (required), name, tags, type, +5 more.

cancel_jobAInspect

Cancel a pending or running job/operation. Flips it to cancelled and stops it from being polled. Note: work already in flight may still finish server-side, but its result is discarded. Already-finished jobs cannot be cancelled. Pass the operationId (from list_jobs pollUrl / get_job).

Inputs: operationId (required), brandId.

cancel_postAInspect

Cancel a scheduled or approved post, reverting it to draft status without deleting it. Use delete_post to remove it entirely.

Inputs: postId (required).

check_ai_contentAInspect

Check whether text is likely AI-generated. Returns a score and analysis.

Inputs: text (required), brandId.

check_social_accountsAInspect

List all connected and disconnected social accounts for the active brand. Lists default short; pass detail=medium/full for more fields. Run before posting to confirm platform availability.

Inputs: detail, brandId.

clear_post_visualCInspect

Remove the selected visual from a post for a specific platform. Includes editInVisualEditor: a direct URL to edit the post in the visual editor (when active brand is set).

Inputs: postId (required), platform (required).

competitor_addAInspect

Async. Batch-add competitor domains (1–20) to the brand. Returns { operationId, status } — poll get_job until state=completed. Each domain triggers crawl + profile analysis. Typically takes ~2–5 min.

Inputs: domains (required), brandId.

competitor_analyzeAInspect

Async. Trigger analysis for existing BrandCompetitor rows that are pending or failed. Use competitor_add to create new rows; use this to retry failed ones. Returns { operationId, status } — poll get_job until state=completed. Typically takes ~2–5 min.

Inputs: brandCompetitorIds (required), brandId.

competitor_comparison_sourcesAInspect

List the data sources used to build the brand's competitive comparison. Returns raw source records (URLs, snippets, timestamps) — useful for auditing comparison accuracy.

Inputs: brandId.

competitor_deleteAInspect

Soft-delete a tracked competitor from the brand. No credits are refunded. Use competitor_update (empty body) to restore.

Inputs: competitorId (required), brandId.

competitor_generate_overviewAInspect

Async. Generate the competitive landscape overview (uses ~20 credits). Returns { operationId, status } — poll get_job until state=completed. Typically takes ~2–5 min.

Inputs: brandId.

competitor_get_comparisonAInspect

Get the brand's head-to-head competitive comparison. short {id,status,generatedAt,competitorCount}; medium adds summary+strengths+weaknesses; full = raw. Returns null when no comparison has been generated yet — use competitor_recompute_comparison to generate.

Inputs: detail, brandId.

competitor_get_overviewAInspect

Get the brand's competitive landscape overview. short {id,status,generatedAt}; medium adds summary excerpt; full = raw. Returns null when no overview exists — use competitor_generate_overview to create one.

Inputs: detail, brandId.

competitor_listAInspect

List the brand's tracked competitors. short {id,domain,analysisState}; medium adds source,creditsCharged,lastError,addedAt,lastCrawledAt,cacheSource; full = raw. Also returns a dashboard link to the Competitors tab.

Inputs: detail, brandId.

competitor_probeAInspect

Start a competitor discovery probe. PostKing crawls the web to find rival domains automatically. Returns { started: true } when kicked off, or { alreadyRan, status } when a probe result already exists. Poll competitor_probe_status to check readiness, then use competitor_probe_classify to accept/reject candidates.

Inputs: brandId.

competitor_probe_classifyAInspect

Classify a discovered (or manually added) competitor candidate. 'direct' seeds a BrandCompetitor row; 'similar' and 'not_relevant' update the probe JSON only. Call once per domain. Probe must be in completed state first. Returns { candidates } — the updated full candidate list.

Inputs: domain (required), classification (required), name, brandId.

competitor_probe_statusAInspect

Check the status of the competitor discovery probe. Returns { status, candidates? } — status is one of: pending | running | completed | failed. When completed, candidates contains the discovered domains ready for classification.

Inputs: brandId.

competitor_recompute_comparisonAInspect

Trigger a fresh head-to-head comparison recompute. Use after adding or re-analyzing competitors to get an up-to-date comparison.

Inputs: brandId.

competitor_refreshAInspect

Async. Refresh all active competitors for the brand (re-crawl + re-profile). Returns { operationId, status } — poll get_job until state=completed. Typically takes ~2–5 min.

Inputs: brandId.

competitor_updateAInspect

Update a competitor's settings. Currently supports toggling excludeFromSeoPull (removes the domain from keyword-gap pull without deleting it). Send an empty body to restore a soft-deleted competitor.

Inputs: competitorId (required), brandId, excludeFromSeoPull.

connect_domain_to_publicationAInspect

Connect a verified domain to a blog publication so articles are served from that domain. Supports three routingType modes: 'path' ({domain}/blog), 'root' (bare {domain}), and 'subdomain' (blog.{domain} — provisions a separate Domain row that needs its own DNS verification before it resolves).

Inputs: domainId (required), publicationId (required), brandId, pathPrefix, +1 more.

create_api_keyAInspect

Create a new PostKing API key. The raw token (pk_live_*) is returned ONCE in this response and never shown again. Store it immediately — treat it like a password. Scope: 'write' (default) or 'read'.

Inputs: name, scope.

create_blog_authorAInspect

Create a new author for blog articles. Returns an authorId that can be used in generate_blog_post and update_blog_article.

Inputs: lastName (required), firstName (required), email, brandId.

create_blog_categoryBInspect

Create a new category in a blog publication.

Inputs: name (required), slug (required), publicationId (required), brandId, +1 more.

create_brandAInspect

STEP 1 of brand onboarding (manual path — no website crawl). Creates a new brand from user-supplied name/description, sets it as active, then RETURNS a nextStep payload telling you to ask the user which platforms they publish on. After the user answers, call set_brand_mediums with their picks. Ask the user for a description if they did not provide one — onboarding will fail without it.

Inputs: name (required), tone, website, audience, +1 more.

create_comparison_pageAInspect

Create a comparison / 'X vs Y' / 'best ' page for the brand WITHOUT going through the full SEO cluster → brief flow. One call kicks off generation and returns quickly with an operationId and a 'still_generating' or 'completed' status — it does NOT block until the page is fully built. mode controls the engine: 'research' crawls the named competitors + live SERP results before writing — slower (can take several minutes) but produces the strongest, best-grounded page; 'simple' skips all crawling and lets the LLM author from what you provide — fast, best when you already have the facts or just want a quick draft. When your inputs are sparse (few/no options, no domains, no seedData), prefer 'research' — it will discover and ground the comparison for you and yield a far stronger page than 'simple'. seedData (simple mode): paste your own raw facts/notes/competitor details here and the LLM writes from them instead of crawling — this is how you feed your own data and avoid a crawl. Async — fires the create, then waits only a short grace window before responding. On success returns { briefId, sidePageId, sidePageSlug, landingPageSlug, webUrl, warnings }. If it is still running past the grace window, returns { status: 'still_generating', operationId } — poll get_job with that operationId until state is 'completed'; do NOT fabricate the page yourself, and do NOT call create_comparison_page again for the same request while it's pending. Any warnings are surfaced verbatim — relay them to the user (e.g. sparse-input notes such as 'research mode would produce a stronger page').

Inputs: mode (required), primaryKeyword (required), preset, brandId, +8 more.

create_postAInspect

Save a post draft with custom content to one or more platforms. Supported platforms: x, linkedin, instagram, threads, facebook. After creating, call approve_post with a future ISO 8601 datetime to schedule it. To check which platforms are connected first, call check_social_accounts. Each created post includes editInVisualEditor: a direct URL to edit it in the visual editor.

Inputs: content (required), platforms (required), brandId, scheduledAt.

create_publicationAInspect

Create a new blog publication (the container that articles live under). Returns a publicationId needed for generate_blog_post.

Inputs: title (required), layout, brandId, description.

delete_assetAInspect

Soft-delete an asset from the brand library. Pass confirm: true to proceed.

Inputs: assetId (required), confirm (required), brandId.

delete_blog_articleAInspect

Permanently delete a blog article.

Inputs: articleId (required), brandId.

delete_domainAInspect

Remove a custom domain. Connected blogs and landing pages are unlinked but not deleted.

Inputs: domainId (required).

delete_landing_pageAInspect

Permanently delete a landing page. Pass confirm: true to proceed — this is irreversible.

Inputs: slug (required), confirm (required).

delete_lp_versionAInspect

Permanently delete a historical landing page version. Cannot delete the published version or the only remaining version (the server will reject those). Pass confirm: true to proceed.

Inputs: slug (required), confirm (required), versionId (required).

delete_postAInspect

Cancel and delete a post regardless of its current status (draft, scheduled, or posted).

Inputs: postId (required).

delete_publicationAInspect

Permanently delete a blog publication. Only allowed when it has zero articles and no connected domain/external sync/publishing connections — otherwise the API refuses with an explanation of what's still attached (remove/disconnect those first, e.g. delete_blog_article for every article under it).

Inputs: publicationId (required), brandId.

delete_side_pageBInspect

Delete a side page. Pass confirm: true to proceed.

Inputs: slug (required), confirm (required), sideKey (required).

delete_side_page_versionAInspect

Permanently delete a historical side-page version. Deleting the current (draft) version is allowed and repoints the draft to the newest remaining version. Cannot delete the published (live) version or the only remaining version — the server will reject those and the rejection reason is returned as-is. Pass confirm: true to proceed.

Inputs: slug (required), confirm (required), sideKey (required), versionId (required).

delete_themeAInspect

Delete a content theme from the active brand.

Inputs: themeId (required), brandId.

delete_weekly_scheduleAInspect

Permanently remove the weekly schedule for the active brand. Pass confirm: true to proceed.

Inputs: confirm (required), brandId.

disable_weekly_scheduleAInspect

Pause the weekly content schedule without deleting it. Re-enable later with enable_weekly_schedule.

Inputs: brandId.

disconnect_social_accountBInspect

Disconnect a social account by its account ID.

Inputs: accountId (required), brandId.

edit_audienceAInspect

Async LLM ai-edit of the brand's audience/ICP. Describe the change in prompt (natural language). sections is REQUIRED — the audience section(s) to edit (e.g. 'demographics', 'painPoints', 'positioning'). If unsure which sections are valid for this brand, call preview_audience_edit first and use the section keys it returns. Returns { operationId, status } — poll get_job(operationId) until state is 'completed' (or 'failed'/'cancelled' on error). Only one audience edit can run at a time; a second call returns an 'already_running' notice. Typically takes ~30–90 s.

Inputs: prompt (required), sections (required), brandId, subsections.

edit_landing_pageAInspect

Update METADATA ONLY — title and/or instructions — of a landing page. Does NOT touch page content. For content changes, use set_landing_page_section (targeted field/section writes) or vibe_edit_landing_page (AI-powered edits).

Inputs: slug (required), title, instructions.

edit_post_cardAInspect

Edit a single carousel card on a post by its 1-based index. Provide title and/or body to update. Set rerender=true to regenerate the visual asset.

Inputs: postId (required), cardIndex (required), body, title, +2 more.

edit_side_pageAInspect

Update a side page's page-level metadata and, for type:"text" pages only, its content. Metadata (any side-page type): name (display title, shown in auto-generated footer/nav 'Solutions' links and breadcrumbs), newKey (rename the URL-slug fragment; old URL 404s, no redirect; internal references are rewritten in the background), and instructions (stored as an annotation for future context — does NOT trigger an AI edit). Content — type:"text" pages ONLY: title and/or htmlContent. Text side pages store a flat {title, htmlContent} document, not per-section overrides, so this is the direct way to write their content — landing/comparison pages have no title/htmlContent fields and must use set_side_page_section (or set_side_page_section with instructions-only for an AI rewrite of a text page's whole document) instead. Passing only one of title/htmlContent fetches and preserves the other automatically, so a partial write never clobbers the unset field. Every edit creates a new draft version (see list_side_page_versions / restore_side_page_version) — nothing here is destructive, any write (including a bad title/htmlContent edit) can be undone by restoring a prior version. On a published page, edits stay draft-only until set_side_page_state({published:true}) publishes them. When newKey triggers a reference rewrite, the response includes slugRewriteOperationId — poll it to confirm the cascade finished.

Inputs: slug (required), sideKey (required), name, title, +4 more.

edit_themeAInspect

Edit an existing content theme's title or content instructions.

Inputs: themeId (required), title, brandId, content.

enable_weekly_scheduleAInspect

Enable the weekly content schedule without changing its configuration. The schedule must already be created with set_weekly_schedule.

Inputs: brandId.

generate_blog_postAInspect

Generate a full AI blog article. Requires a publicationId (from list_blogs or create_publication). Pass a voiceProfileId to write in a specific person's style (IDs from list_voices). Returns an articleId + operationId; generation is async — poll get_blog_status until completed, then get_blog_article. Use update_blog_article to edit, or publish_blog_article to push to external platforms. To make it live on your PostKing blog, call update_blog_article with status: 'published'.

Inputs: topic (required), publicationId (required), brandId, targetLength, +9 more.

generate_bulk_postsBInspect

Generate and schedule multiple posts across a date range in the background.

Inputs: days (required), platform (required), times, voice, +3 more.

generate_landing_pageAInspect

Create and AI-generate a new landing page for the brand. Step 1: Creates the LP record with the given slug. Step 2: Kicks off async AI content generation immediately. Returns { slug, operationId, pollUrl } — poll with get_job(operationId) until state is 'completed' (or 'failed'/'partially_failed'/'cancelled' on error). For targeted edits to an existing page, prefer vibe_edit_landing_page.

Inputs: topic (required), slug, brandId, voiceProfileId.

generate_postAInspect

Generate AI content for a platform. Returns quickly with a postId and a 'generating' or 'completed' status — it does NOT block until generation fully finishes. Deducts 10 credits per variation. To control what the post is about, pass theme with a free-text brief (any topic/angle/facts/tone). If you omit theme, the topic is RANDOM — so always pass it when the user wants specific content. When variations > 1, ALL variations are returned under a SINGLE postId in the variations array — it does NOT create one post per variation. content is variation 1 (the primary, already saved on the post). Never call generate_post again to 'get the other variations' — they're all in the response. originalContent (if seen elsewhere) is the pre-voice-rewrite draft, not a separate variation. After generating, use create_post to save a chosen variation, then approve_post to schedule it. To repurpose: call repurpose_content first, then create_post with the result, then approve_post. Generation can take 1-5 minutes (longer with multiple variations or voice rewrite). This tool only waits a short grace period so fast generations can return inline content; if it returns status 'generating', the job is still running server-side — poll get_post with the returned postId until operationStatus is 'completed', then use that content. Do NOT call generate_post again for the same request while it's pending — retrying creates a duplicate draft and wastes credits. After generation, brand visual options (quote/card templates, brand images, stock photos) are prepared but NOT attached — share viewInBrowser for the visual picker, or call pick_post_visual to attach one. Do not attach a visual unless the user chooses it. The response includes editInVisualEditor: a direct URL to edit the post in the visual editor (once completed).

Inputs: platform (required), theme, voice, brandId, +2 more.

generate_post_carouselAInspect

Generate a carousel PDF for a LinkedIn (or other) post from the post's cards. Returns an asset ID and download URL for the PDF. Requires cards to be set first via set_post_cards or edit_post_card.

Inputs: postId (required), style, title, variant.

generate_post_visual_optionsAInspect

Fetch available visual options for a post — card templates, library matches, stock photos. Returns a bestPick recommendation plus categorized options per platform. Use pick_post_visual to apply one of the returned options. Returns slim option list with pickArgs by default (medium). Use detail='short' for counts only, 'full' for raw catalog. Includes editInVisualEditor: a direct URL to edit the post in the visual editor (when active brand is set).

Inputs: postId (required), detail, category, platform.

generate_side_pageAInspect

AI-generates a side page under a parent landing page. Async — kicks off the side-page generator and returns { success, operationId, operationRowId, pollUrl, sidePageId }. This is the GENERATOR (POST /side-pages/generate) — NOT a row creator. Comparison-type briefs may run synchronously and return sidePageId directly with no operationId. Two body modes: • freeform: pass key + prompt (+ optional keywords, selectedSections, voiceProfileId, sidePageType). Freeform now writes real section-level content (hero/features/showcase/faq/cta), not just metadata. • brief: pass key + brief (structured outline) + optional briefId and roadmapItemId. Poll get_job with the returned operationId until state is completed (or failed/partially_failed/cancelled on error); the generated page's sections will be populated once complete.

Inputs: key (required), slug (required), brief, prompt, +7 more.

generate_textAInspect

Generate or rewrite general-purpose, email-style/formal text — follow-up emails, cover letters, outreach messages, formal notes, etc. Returns quickly with an operationId and a 'still_generating' or 'completed' status — it does NOT block until generation fully finishes. This is NOT for social media posts — use generate_post for those. This is also NOT for a simple voice-only rewrite of existing text with no other options — for that, use rewrite_with_voice or rewrite_text instead. Reach for generate_text when you need mode selection (generate vs rewrite), a stated purpose, a target length, or when there's no source text at all (mode='generate'). mode='generate' writes new text from a prompt (what to write, e.g. 'a follow-up email after a sales call, polite but direct'). mode='rewrite' rewrites existing sourceText into a new form/tone. purpose is optional free text describing the goal, e.g. 'win-back email' or 'job application cover letter'. length can be short | medium | long, or a specific target word count (20-5000). Supports detail param: short=status+wordCount only, medium=truncated content (500 chars)+wordCount (default), full=raw result including content, aiDetectionScore, burstinessScore, promptLogId, wordCount. If it returns status 'still_generating', the job is still running server-side — poll get_job with the returned operationId (wait:true) until state is 'completed', then read the text from the operation's result. Do NOT call generate_text again for the same request while it's pending — retrying wastes effort and may create duplicate work.

Inputs: mode (required), detail, length, prompt, +4 more.

generate_themesAInspect

Generate new content themes using AI. Waits a short grace window for generation to finish; if it's still running server-side after that, returns a 'generating' status instead of blocking — call list_themes a few seconds later to retrieve the new themes. Deducts credits.

Inputs: count, input, brandId, instructions.

get_audienceAInspect

Fetch the brand's audience intelligence / ICP (ideal customer profile). short = compact summary (name + primaryRoles + top painPoints + persona.role); medium adds positioning + fuller demographics; full = the raw payload (audienceData + positioning + persona + contentModulation). persona is the ghostwriter persona ({ role, styleNotes, ... }) and may be null. If the brand has no audience data yet, run website/audience analysis (onboarding) first.

Inputs: detail, brandId.

get_blog_articleAInspect

Fetch a blog article by ID. detail='short' returns id/title/slug/status; detail='medium' adds excerpt+wordCount+previewUrl+editUrl; detail='full' (default) returns the COMPLETE content plus previewUrl (GUI preview link) and editUrl (dashboard editor link). Pass maxContentChars only if you need to bound the body size; omit it to get the whole article.

Inputs: articleId (required), detail, brandId, maxContentChars.

get_blog_statusAInspect

Poll the async generation status of a blog article. Use the articleId returned by generate_blog_post. Status: pending | running | completed | failed.

Inputs: articleId (required), brandId.

get_brand_infoAInspect

Get a brand's profile. Returns core identity fields plus slim summaries: themes as [{id,title}], voiceProfiles as [{id,name,isActive,optimizedMedium}], blogAuthors as [{id,firstName,lastName}], and postCount/memberCount as numbers. Use list_themes, list_voices, list_blog_authors, list_posts, or get_brand_members for full detail on each.

Inputs: detail, brandId.

get_brand_mediumsAInspect

Read which publishing platforms (mediums) a brand posts to. Read-only counterpart to set_brand_mediums. NOTE: Reddit is NOT a medium — Reddit is a separate repurpose module; use the reddit_* tools or dashboard_link section 'reddit'.

Inputs: brandId.

get_brand_membersAInspect

List all active members of a brand with their role and user info (id, name, email).

Inputs: brandId.

get_calendarAInspect

View upcoming scheduled posts sorted by date. Returns id+status+scheduledAt by default; use detail='medium' or 'full' for more fields. For a single post use get_post.

Inputs: days, detail, brandId.

get_creditsAInspect

Check your current PostKing credit balance and free-tier status.

Inputs: detail.

get_jobAInspect

To check whether ONE specific operation you started is finished, pending, or failed, call this with its operationId (the pollUrl param accepts a bare operationId + brandId). Do NOT use list_operations to check a specific op. Poll the status of any background Operation by its operationId or pollUrl. Returns the Operation row: { id, kind, state (pending|running|completed|partially_failed|failed|cancelled), brandId, scopeType, scopeId, progress, result, errors, startedAt, finishedAt, createdAt, updatedAt }. Call repeatedly until state is 'completed' or 'failed' (or 'cancelled'). When completed, the payload you want is in result; on failure, see errors. Pass wait:true to block until the job is done (polls every 3s, capped at ~30s per call) — preferred over calling repeatedly. For longer-running jobs, call get_job again with wait:true to keep polling until it completes. Most generate_* and vibe_edit_* tools (including seo_generate_clusters and seo_generate_keywords) return an operationId — use this to poll them. Supports detail param: short=id+kind+state+progress, medium=adds timestamps+resultRef (key IDs from result, no full payload), full=raw including complete result JSONB.

Inputs: pollUrl (required), wait, detail, brandId, +1 more.

get_onboarding_statusAInspect

STEP 3 of brand onboarding. Polls background analysis + theme generation. detail='short' returns status only; detail='medium' (default) adds audienceSummary+themeCount; detail='full' returns raw data. Poll every ~15s. When done, surface the audience review + themes to the user.

Inputs: detail, brandId.

get_postAInspect

View the full content and status of a single post. Use detail='short'|'medium'|'full' to control verbosity (default full). Multi-variation posts expose a variations array (all variations live on one postId). Output shows the final voice-rewritten content by default; pass includeOriginal=true to also see the pre-rewrite draft. Includes contentReviewUrl: a direct link to read and approve the generated body, and editInVisualEditor: a direct URL to edit the post in the visual editor.

Inputs: postId (required), detail, includeOriginal.

get_seo_roadmapAInspect

View the SEO / GEO content roadmap — suggested blog topics, keywords, and completion status. detail='short' returns stats only; detail='medium' adds slim item list (id+title+status+keyword); detail='full' (default) returns raw response.

Inputs: detail, status, brandId.

get_social_media_rulesAInspect

Read a brand's per-platform social media content rules (the same rules editable in dashboard Settings → Social media rules). Covers content/structure/engagement/visual-strategy guidance plus secrets, guidelines, content types, things to avoid, and core principles. Call this BEFORE set_social_media_rules so you only change the fields you intend to.

Inputs: brandId, platform.

get_vibe_edit_statusAInspect

Poll vibe (AI) edit session status. detail='medium' (default) is the REVIEW view: { status, progress, stale, baseVersionId, currentVersionId, changesCount, credits, changes, error } where each changes entry is { index, path, before, after } (before/after truncated to 200 chars) — use these index/path values to select a subset in apply_vibe_edit. 'short' returns just { status, progress, error }. 'full' returns the raw payload including the untruncated editedData. error is populated when status is 'failed' and carries the failure reason — surface it to the user instead of just reporting 'failed'. When status is 'completed', call apply_vibe_edit next (this tool never applies anything).

Inputs: slug (required), operationId (required), detail.

get_weekly_scheduleAInspect

Retrieve the current weekly content schedule for the active brand. Returns enabled status, lead time, timezone, and per-day platform configs. If no schedule is configured yet, returns suggested defaults. Includes a viewInBrowser link to open the calendar page in the app.

Inputs: detail, brandId.

healthAInspect

Check PostKing API health and local auth state. No authentication required — safe to call first thing in a session to see whether you're logged in and what to do next.

Inputs: no named parameters.

humanize_textCInspect

Apply LLM rewrite and BERT replacements to reduce AI detection signals in text.

Inputs: text (required), brandId, platform.

import_asset_from_urlAInspect

Import an asset into the brand library from a public URL. The server fetches and stores the file. Set assetType (e.g. 'google-image') when importing a result surfaced by search_web_images — it is recorded as a tag on the asset to preserve provenance.

Inputs: url (required), name, tags, brandId, +1 more.

import_assets_csvAInspect

Batch-import up to 50 assets by providing an array of public URLs. All are added to the brand library. Supports detail param for the returned asset list.

Inputs: urls (required), detail, brandId.

import_blog_articlesAInspect

Import articles from an external blog, RSS feed, or Blogger URL into a PostKing publication as drafts. Returns id+title+slug by default (short); use detail='medium' for wordCount. Inspect individual articles with get_blog_article.

Inputs: sourceUrl (required), publicationId (required), limit, detail, +1 more.

import_landing_page_htmlAInspect

Bring-your-own-HTML: import an existing landing page from pasted HTML or a live URL. Synchronous — no polling needed. Pass exactly one of html (paste the full page source) or url (fetch and import from a live page). By default creates a brand-new landing page (optionally with name; the slug is always auto-generated). Pass convertExistingSlug instead to overwrite an existing landing page's content with the imported HTML. Set createMissingSidePages to true to auto-create stub side pages for internal links discovered in the HTML that don't already exist. Returns { landingPage: {id, slug}, report } where report audits the import: externalHosts (third-party domains referenced), relativeAssetPaths (local asset paths that may need re-hosting), placeholders (unresolved template tokens found), internalLinks (each { href, slug, existingSidePage }), themeExtracted (whether a theme was inferred from the HTML), truncated (whether the source HTML was cut down to fit limits), and extractability ({ verdict: 'ok'|'warn', reasons } — 'warn' means framework hydration scripts won't load post-import but static content still renders). If the source is a client-rendered app shell whose content depends entirely on framework scripts that can't be hosted here (e.g. a bare Next.js/React app shell), the import is refused before anything is persisted — this tool returns a non-throwing result { error: 'not_extractable', message, reasons } instead. Relay the reasons to the user and suggest pasting a static/exported HTML instead, or publishing directly from their site builder. Example: import_landing_page_html({ url: 'https://example.com/pricing', name: 'Pricing' }).

Inputs: url, html, name, brandId, +2 more.

knowledge_createAInspect

Async. Create a new knowledge-base item for the brand. Returns { operationId, status } — poll get_job until state=completed. If description or tags are omitted, PostKing auto-generates them from the content. For contentType='json', content must be valid JSON — this tool validates client-side before calling the API. Typically takes ~15–30 s.

Inputs: name (required), content (required), contentType (required), tags, +3 more.

knowledge_deleteAInspect

Soft-delete a knowledge-base item. The item is deactivated (isActive=false) and no longer appears in knowledge_list. This action is not reversible via the API.

Inputs: itemId (required), brandId.

knowledge_getAInspect

Fetch a single knowledge-base item by ID. short {id,name,contentType}; medium adds tags+summary+timestamps; full = raw (includes full content). Use detail='full' to retrieve the complete content body.

Inputs: itemId (required), detail, brandId.

knowledge_listAInspect

List the brand's knowledge-base items. short {id,name,contentType}; medium adds tags+summary+timestamps; full = raw. Filter by tag, active status, or global scope.

Inputs: tag, detail, global, brandId, +1 more.

knowledge_updateAInspect

Update a knowledge-base item. Minor edits (name, tags, description) return the updated item synchronously. When content changes significantly, PostKing queues an AI description regeneration and returns { operationId, status } — poll get_job until state=completed. For contentType='json', content must be valid JSON — this tool validates client-side before calling the API. Typically takes ~15–30 s.

Inputs: itemId (required), name, tags, brandId, +3 more.

list_api_keysAInspect

List all API keys on the account. Shows prefix, scope, and revocation status. Does NOT show raw tokens. Lists default short; pass detail=medium/full for more fields.

Inputs: detail.

list_assetsAInspect

List assets in the brand's visual library. Filter by type (IMAGE|DOCUMENT|VIDEO|LINK|LOTTIE), tags, or search text. Supports detail param: short=id+type+name, medium=key fields, full=raw.

Inputs: tags, type, limit, detail, +2 more.

list_asset_slotsAInspect

List the asset slots (image/video placeholders) for a landing page or side page, with each slot's current asset assignment. Use this to discover valid slotKeys before calling assign_asset_to_slot. Pass sidePageSlug to inspect a side page's slots.

Inputs: slug (required), pageKey, sidePageSlug.

list_asset_tagsAInspect

List all unique tags used across the brand's asset library.

Inputs: brandId.

list_blog_authorsAInspect

List all blog authors for the active brand. Returns id+name by default (short); use detail='medium' for email/social links. Author IDs can be passed to generate_blog_post or update_blog_article.

Inputs: detail, brandId.

list_blog_categoriesAInspect

List all categories for a blog publication. Returns id+name+slug by default (short); use detail='medium' for description+articleCount.

Inputs: publicationId (required), detail, brandId.

list_blogsAInspect

LIST tool. Even detail='full' OMITS article bodies (kept bounded) — to read an article's content, call get_blog_article. The number of rows is controlled by limit (default 50, max 200), NOT by detail; for a 'full list' of titles, raise limit and keep detail='short'.

Inputs: limit, detail, status, brandId.

list_brandsAInspect

List all brands on your PostKing account. Returns id+name+website by default (short). Use detail='medium' for description, 'full' for all raw fields. To zoom into one brand call get_brand_info with detail='full'.

Inputs: detail.

list_domainsAInspect

List all custom domains for the active brand. Lists default short; pass detail=medium/full for more fields including SSL status, verification, and connected blogs or landing pages.

Inputs: detail, brandId.

list_jobsAInspect

To check a SPECIFIC operation's status, call get_job with its operationId — this list only returns the most recent ops and may omit a just-started one. List background jobs for the active brand. Use status='pending' to see in-flight ops, 'completed' to see finished ones. Use get_job with an operationId to poll a specific job — most async tools return an operationId. Supports detail param: short=id+kind+state, medium=6 key fields, full=raw.

Inputs: limit, detail, status, brandId.

list_landing_pagesAInspect

Lists landing pages. Default detail='short' (id/slug/name/status). Use view_landing_page for full content.

Inputs: detail, brandId.

list_lp_versionsAInspect

List all saved versions of a landing page. Default detail='short'. Each version includes previewUrl (public GUI preview link — the published version's form when that version is the live one, otherwise the ?version= form); the top-level previewUrl is for the current draft. Use view_lp_version to see section content.

Inputs: slug (required), detail.

list_operationsAInspect

To check a SPECIFIC operation's status, call get_job with its operationId — this list only returns the most recent ops and may omit a just-started one. List recent Operations (the newer async-op system) for the active brand. Each operation has: id, kind, state (pending|running|completed|partially_failed|failed|cancelled), progress, result, errors. Use get_job with an operationId to poll a specific one. Filters: kind (e.g. seo_keyword_generate, seo_cluster_generate, lp_generate), state. Supports detail param: short=id+kind+state, medium=adds scopeId+progress+timestamps (no result/errors), full=raw including result.

Inputs: kind, limit, state, detail, +1 more.

list_post_cardsAInspect

List the carousel cards attached to a post. Cards are used for LinkedIn carousel / PDF generation. Returns {index,title} by default; use detail='medium' for truncated body, 'full' for all fields.

Inputs: postId (required), detail.

list_postsAInspect

List recent posts and drafts. Filter by status or platform. Use status='created' to find unscheduled drafts. Returns id+status+scheduledAt by default; use detail='medium' or 'full' for more fields. For a single post use get_post.

Inputs: limit, detail, status, brandId, +1 more.

list_publicationsAInspect

List all blog publications (the containers that blog articles live under). detail='short' returns id+name; detail='full' returns raw rows. Distinct from list_publishing_connections which lists external platforms like WordPress.

Inputs: detail, brandId.

list_publishing_connectionsAInspect

List external publishing connections for a blog publication (WordPress, Medium, Substack, etc.).

Inputs: publicationId (required), brandId.

list_side_pagesAInspect

List side pages attached to a landing page. Default detail='short'. Heavy JSONB (overrides/config) only at full via view_side_page. medium/full include currentVersionId (the draft) and publishedVersionId (the live version) per row — compare them to spot pages with unpublished draft edits without a second call.

Inputs: slug (required), detail.

list_side_page_versionsAInspect

List all saved versions of a side page. Default detail='short'. Always includes top-level currentVersionId (the draft) and publishedVersionId (the live version) so an agent can tell draft vs. live without a second call. Use view_side_page_version to see section content.

Inputs: slug (required), sideKey (required), detail.

list_themesAInspect

List all content themes for the active brand with their IDs. detail='short' (default) returns id+title; detail='medium' adds content preview; detail='full' returns raw content.

Inputs: detail, brandId.

list_voicesAInspect

List all available voice profiles with their IDs. Lists default short; pass detail=medium/full for more fields.

Inputs: detail.

login_completeAInspect

Wait for the user to approve the PostKing login code in their browser and then save the token. Polls automatically; call this immediately after login_start.

Inputs: no named parameters.

login_startAInspect

Start the PostKing login flow. Returns a URL and short code for the user to visit in their browser. IMPORTANT: Immediately after this tool returns, show the URL + code to the user and then call login_complete — it will wait (polling in the background) until the user approves the request in their browser, so there is no need to ask the user to tell you when they are done.

Inputs: no named parameters.

logoutAInspect

Clear locally stored PostKing credentials.

Inputs: no named parameters.

onboard_brandAInspect

STEP 1 of brand onboarding (website path). Crawls the site in the background and kicks off audience analysis + 10 themes. Sets the new brand as active and RETURNS a nextStep payload. IMMEDIATELY after this returns, ask the user which social platforms they publish on, then call set_brand_mediums. Do not call get_onboarding_status until mediums are set.

Inputs: websiteUrl (required), name.

pick_post_visualAInspect

Select a visual for a post on a given platform. Use the chosen option's pickArgs from generate_post_visual_options VERBATIM — for card/quote templates that means passing kind + style + variant together; for a library/smart asset or a stock photo, pass the assetId or slot from its pickArgs. Do not invent style names. variant is a 1-based template variant index. Includes editInVisualEditor: a direct URL to edit the post in the visual editor (when active brand is set).

Inputs: postId (required), platform (required), kind, slot, +3 more.

preview_audience_editAInspect

Read-only helper. Call this BEFORE edit_audience to discover which sections/subsections values are valid for this brand. Pass the natural-language change you intend to make; returns the available sections/subsections (computed from the brand's current audience data) plus a preview. Use the returned section keys (e.g. 'demographics', 'painPoints', 'positioning') as the required sections array for edit_audience.

Inputs: prompt (required), brandId.

publish_blog_articleAInspect

Push a blog article to connected external platforms (WordPress, Medium, Substack, etc.). Get connection IDs from list_publishing_connections.

Inputs: articleId (required), connectionIds (required), brandId.

publish_landing_pageAInspect

Publish a landing page, making it publicly accessible at its URL.

Inputs: slug (required).

reddit_generate_poolAInspect

Kick off async generation of a subreddit pool for the brand — finds relevant subreddits by crawling Reddit. Typically takes ~1–3 min. Returns { operationId, status }. Poll get_job with the operationId until state=completed, then call reddit_get_pool to see results. Reddit is a repurpose-to-Reddit workflow, NOT a scheduled publishing medium.

Inputs: brandId.

reddit_get_poolAInspect

Returns the brand's pool of relevant subreddits — THIS IS the brand-level subreddit match (each scored). Use it to answer 'which/what/top N subreddits should my brand post in?' — NO content needed; results are sorted most-relevant first; pass top for a top-N list. (reddit_suggest is a different, content-specific step.) Reddit is a repurpose-to-Reddit workflow, NOT a scheduled publishing medium.

Inputs: top, brandId.

reddit_global_poolAInspect

Return stats on the global subreddit dataset (count of known subreddits available for matching). Informational only — no DB writes.

Inputs: brandId.

reddit_list_postsAInspect

List saved Reddit posts (outputs of reddit_rewrite). Cursor-paginated. Returns { posts: [{ id, platform, content, outputData, sessionId, voiceId, createdAt }], nextCursor }. outputData contains: redditTitle, body, notes, wordCount, angle, length, subreddit, variationIndex. Flow step 4 of 4: pool → suggest → rewrite → LIST_POSTS.

Inputs: limit, cursor, brandId.

reddit_rewriteAInspect

Async. Rewrite a blog article (or raw content) into a Reddit-native post for a specific subreddit. Typically takes ~30–90 sec per variation. Returns quickly — if generation finishes within a short grace window, the finished Reddit post is returned inline; otherwise it returns a postId and a 'still in progress' status. Poll get_post with that postId until operationStatus is COMPLETED. Do NOT call reddit_rewrite again for the same request while it's pending. The subreddit does NOT need to be in the brand's pool — if it isn't, the rewrite still proceeds using general Reddit best-practices, and the result includes a subredditNotice string flagging that this subreddit hasn't been onboarded yet. Flow step 3 of 4: pool → suggest → REWRITE → list_posts.

Inputs: subreddit (required), angle, length, brandId, +5 more.

reddit_suggestAInspect

Given a brand's content (a blog post by id, or pasted title+text), return up to 8 best-fit subreddits from the brand's pool, each with 2-3 distinct posting angles (angle type + tailored title + framing hook), plus promotion mode, buyer intent, match score, and the key rule to watch. Use an angle's title/hook to then draft a native post via reddit_rewrite. short {subreddit,match_score,promotion_mode,buyer_intent,angle} (angle = first angle only); medium adds reason,rule_to_watch,angles (all angles); full = raw. Synchronous, 0 credits. Requires the brand pool to exist — call reddit_generate_pool first if it doesn't. Flow step 2 of 4: pool → SUGGEST → rewrite → list_posts.

Inputs: title, detail, postId, brandId, +1 more.

regenerate_landing_pageAInspect

Re-generate a landing page's content using AI. Optionally restrict to specific sections. Returns an operationId — poll with get_job to track progress. For targeted edits to an existing page, prefer vibe_edit_landing_page.

Inputs: slug (required), sections, instructions, voiceProfileId.

regenerate_post_visualAInspect

Regenerate the visual option set for a post — refreshes stock photo results and re-scores library assets. Returns slim option list with pickArgs by default (medium). Use detail='short' for counts only, 'full' for raw catalog. Includes editInVisualEditor: a direct URL to edit the post in the visual editor (when active brand is set).

Inputs: postId (required), detail, platform, loadExternal.

repurpose_contentAInspect

Turn a URL, text, blog post, or existing PostKing post into new content for social media or blogs. IMPORTANT: When the source is a URL, pass it directly to this tool via sourceUrl — do NOT fetch or crawl the URL yourself first. PostKing handles all crawling internally. Source types: url | text | blog | social_post. Target types: social (LinkedIn, X, etc.) | blog | text. Supports detail param: short=ids only, medium=key fields (default), full=raw response.

Inputs: sourceType (required), targetType (required), angle, detail, +11 more.

reschedule_postBInspect

Move a scheduled post to a new time. Pass a future ISO 8601 UTC datetime.

Inputs: postId (required), scheduledAt (required).

restore_lp_versionAInspect

Undo/rollback the draft to a prior version. Find valid version IDs via list_lp_versions. This does not touch the published version.

Inputs: slug (required), versionId (required).

restore_side_page_versionAInspect

Restore a side page's draft to a prior version. Find valid version IDs via list_side_page_versions. This only changes the DRAFT — it moves currentVersionId forward to a new version copied from the target (forward history is never deleted). The live/public page is unaffected until you publish again via set_side_page_state({ published: true }).

Inputs: slug (required), sideKey (required), versionId (required).

revoke_api_keyAInspect

Permanently revoke an API key. Pass confirm: true to proceed — this is irreversible and any clients using this key will stop working immediately.

Inputs: keyId (required), confirm (required).

rewrite_textBInspect

Rewrite text using a voice profile or general writing rules.

Inputs: text (required), voice, brandId, platform.

rewrite_with_voiceCInspect

Rewrite text using a specific voice profile.

Inputs: text (required), profileId (required), brandId, platform.

run_weekly_schedule_dayAInspect

Trigger the smart-week content generation engine for a specific date. This immediately queues posts for that day's schedule configuration. Use YYYY-MM-DD format for the date. Returns postsCreated count.

Inputs: date (required), brandId.

schedule_blog_articleAInspect

Schedule an existing blog article to auto-publish at a future date/time. scheduledAt must be a future ISO 8601 datetime. When the time arrives, the article publishes to the PostKing blog and auto-pushes to any connected external platforms flagged autoPublish. To publish immediately instead, use update_blog_article with status='published'.

Inputs: articleId (required), scheduledAt (required), brandId.

schedule_postAInspect

Schedule a draft or approved post for a specific time. Equivalent to approve_post but named to match 'pking posts schedule'. Pass a future ISO 8601 UTC datetime. After scheduling the post status becomes 'scheduled'.

Inputs: postId (required), scheduledAt (required), timezone.

search_stock_imagesAInspect

Search stock photo/video libraries for images matching a query. Returns URLs and descriptions. Use import_asset_from_url to add a result to the library. Supports detail param: short=url+thumbnail, medium=adds description+credit, full=raw.

Inputs: query (required), detail, brandId, platform.

search_web_imagesAInspect

Search Google Images across the whole web for a query — broader than search_stock_images, which only searches licensed stock photo/video libraries. Returns image URLs, the source site, and a link back to the source page. openLicensedOnly is a best-effort source filter, not a legal license guarantee — agents and users should still verify usage rights before publishing any result. Use import_asset_from_url to add a chosen result to the library. Supports detail param: short=url+source, medium=adds sourceUrl+alt+dimensions, full=raw.

Inputs: query (required), gl, hl, detail, +3 more.

seo_add_seedsAInspect

Step 1 of the SEO / GEO flow. Add 3–10 seed keywords that describe what the brand wants to rank for. After this, call seo_generate_keywords to expand them into the full keyword universe.

Inputs: seeds (required), brandId.

seo_approve_briefsAInspect

Approves one or more SeoBriefs and AUTO-fires L4 article/comparison generation immediately — do NOT call seo_write_article after this. Typically takes ~3–8 min per article. After approval, poll each returned operationId with get_job until state is completed (or failed/partially_failed/cancelled on error). A brief in status writing means generation is already in progress — poll the existing operation, do not re-submit. Body: briefIds (array, max 200). Response: { approved, failed: [{briefId, reason}], operationIds, operations: [{briefId, operationId, type}] }.

Inputs: briefIds (required), brandId, generateHeroImage.

seo_approve_clusterAInspect

Approve a single cluster. Gates brief generation — only approved clusters get briefs drafted. Position in flow: after seo_generate_clusters + seo_list_clusters, before seo_generate_roadmap / brief review. Typically takes ~2–5 min per cluster. Returns { cluster, operationId } — the operationId is for the async brief-generation job kicked off by approval. Poll get_job with the operationId until state is completed (or failed/partially_failed/cancelled on error).

Inputs: clusterId (required), brandId.

seo_auto_assign_ctaAInspect

Optional capstone step — runs AFTER blog articles are published. Auto-suggests a published side-page CTA for each blog article in the batch by matching the article's keywords (cluster + tags + title) against the brand's published side pages, then writes the result to BlogArticle.sidePageInfo (header + ctaText + ctaButtonText + ctaHref). Defaults are safe to re-run: skips blogs that already have a CTA (overwriteExisting=false) and skips Webflow-synced blogs (skipWebflowSynced=true) since CTA edits don't push back to Webflow. Synchronous — returns { updated, skipped, errors, total, results: [{blogId, status, sidePageId?, sidePageSlug?}] } directly; no polling needed. Pass blogIds: "all" to process every blog for the brand, or a list of up to 50 blog IDs. Hard cap of 50 blogs per call. For brands with more uncovered blogs, batch your blogIds arrays in groups of 50. The matcher uses keywords today; reusing an existing CTA header/ctaText body as a matching signal is a planned enhancement.

Inputs: blogIds (required), brandId, overwriteExisting, skipWebflowSynced.

seo_bulk_approve_clustersAInspect

Step 5b — bulk-approve N clusters in one call. Recommended path when an agent wants to move multiple clusters forward. Approving a cluster fires an async seo_brief_generate Operation per cluster; brief generation only runs on approved clusters. Typically takes ~2–5 min per cluster. Response includes operations: [{ clusterId, operationId }] and operationIds: string[] — Poll get_job with the operationId until state is completed (or failed/partially_failed/cancelled on error).

Inputs: clusterIds (required), brandId.

seo_bulk_delete_keywordsAInspect

Soft-delete N SeoScoredKeyword rows in one call (sets deletedAt; rows stay in the DB but are filtered out of all queries). Housekeeping op — not part of the main flow. Pass confirm: true to proceed. Use to clear out a batch of junk/irrelevant keywords the auto-pipeline missed, e.g. after filtering seo_list_keywords by relevanceMax.

Inputs: confirm (required), keywordIds (required), brandId.

seo_bulk_edit_keywordsAInspect

Edit userTags, intent, priority, and/or excludedFromClustering across N SeoScoredKeyword rows in one call — the same values are applied to every id in keywordIds. Housekeeping op — not part of the main flow. Pass confirm: true to proceed (this can silently overwrite tags/intent/priority for many keywords at once). At least one of intent, userTags, priority, or excludedFromClustering must be supplied. Typical flow: call seo_list_keyword_ids with a filter to get the target ids, then pass them here. Example: {"keywordIds":["kw_1","kw_2"],"excludedFromClustering":true,"confirm":true}.

Inputs: confirm (required), keywordIds (required), intent, brandId, +3 more.

seo_bulk_reject_clustersAInspect

Bulk-reject N clusters in one call. Symmetric to seo_bulk_approve_clusters.

Inputs: clusterIds (required), brandId.

seo_categorizeAInspect

Step 3 of the SEO / GEO flow. Tag keywords by search intent and/or user tags. Pass updates: an array of {keywordId, intent?, userTags?} (intent ∈ informational | commercial | navigational | transactional). Example: {"updates":[{"keywordId":"kw_123","intent":"commercial"}]}. After this, call seo_generate_clusters.

Inputs: updates (required), brandId.

seo_competitorAInspect

Compare the brand's keyword coverage against a competitor domain. Returns short detail by default: bucket totals only {overlapping: {total}, brandUnique: {total}, competitorOnly: {total}}. Use detail="medium" for capped keyword lists (up to 50 per bucket) or detail="full" for the raw API response.

Inputs: competitorDomain (required), detail, brandId.

seo_create_clusterAInspect

Create a real, named SEO cluster by hand — bypasses the auto-clustering pipeline entirely (no LLM call). The cluster starts empty; use seo_create_custom_brief with the returned id as clusterId to add its first brief. Manual clusters are tagged origin: "manual" so the dashboard can distinguish them from pipeline-generated clusters, and are created already approved (no separate approval step needed). Cluster names must be unique per brand — if the name is already taken, this returns a clear cluster_name_taken error instead of creating a duplicate; pick a different name or reuse the existing cluster via seo_list_clusters.

Inputs: name (required), brandId, description, pillarKeyword.

seo_create_custom_briefAInspect

Create a single custom SEO brief on demand — the MCP entry point for the 'generate-one' custom-brief flow (previously only reachable via raw agent-v1 REST). Pass clusterId (from seo_create_cluster or seo_list_clusters) to add this brief into an EXISTING named cluster. Omit clusterId to fall back to the legacy behavior: a throwaway single-brief cluster is minted automatically (tagged origin="manual"). Async — returns { operationId, status }. Poll get_job with the operationId until state is 'completed' (or 'failed'/'partially_failed'/'cancelled' on error), then call seo_get_brief with the briefId from the completed operation's result to read the generated outline. Typically takes ~2–5 min per cluster.

Inputs: type (required), pillarKeyword (required), intent, brandId, +4 more.

seo_delete_clusterAInspect

Hard-delete a cluster. This CASCADES: every SeoRoadmap item under this cluster is deleted, along with its brief. Blog articles and keywords that pointed at this cluster are NOT deleted but have their cluster link cleared. This is NOT UNDOABLE — there is no soft-delete for clusters (unlike keywords). Housekeeping op — not part of the main flow. Pass confirm: true to proceed. Prefer seo_reject_cluster if you just want to remove a cluster from the active pipeline without destroying its roadmap items and briefs — reject is reversible via seo_restore_cluster, delete is not.

Inputs: confirm (required), clusterId (required), brandId.

seo_delete_keywordAInspect

Soft-delete a single SeoScoredKeyword (sets deletedAt; the row stays in the DB but is filtered out of all queries). Housekeeping op — not part of the main flow. Pass confirm: true to proceed. Use for obvious junk keywords the auto-pipeline missed. Prefer seo_edit_keyword with excludedFromClustering=true when you only want to hold a keyword out of the next clustering pass.

Inputs: confirm (required), keywordId (required), brandId.

seo_edit_briefAInspect

Edit an SeoBrief before approval. The inner route does NOT accept free-text 'instructions' — refinement is structured. Pass briefData (the full replacement JSON for the brief outline — H2s, FAQs, keyword targets, etc.) and/or status ('approved' | 'rejected'). Approving via this tool fires L4 article/comparison generation immediately and returns { brief, operationId } — prefer seo_approve_briefs for the canonical approval step. Typical refinement loop: seo_get_brief → mutate briefData locally → seo_edit_brief with the new briefData (status omitted) → seo_approve_briefs.

Inputs: briefId (required), status, brandId, briefData, +4 more.

seo_edit_clusterAInspect

Edit a cluster's name, pillarKeyword, description, keywordsMeta, contentMix, and/or briefAssignments. Housekeeping op — not part of the main flow. At least one field must be supplied. MEMBERSHIP: there is no separate add/remove-member endpoint. Cluster membership is entirely controlled by keywordsMeta — it is a REPLACEMENT array, not a delta/patch. To add a keyword to the cluster, fetch the cluster's current keywordsMeta (seo_list_clusters with detail="full"), append a new entry {keyword, id, volume, kd, intent, relevance, priority, excluded?} (use the SeoScoredKeyword id from seo_list_keywords / seo_list_keyword_ids), and send the WHOLE array back. To remove a keyword, send the array with that entry omitted. Sending a partial array will drop the missing members from the cluster. contentMix must be an object with blog/tool/comparison/landing fractions summing to 1.0 (the server normalizes small rounding drift). briefAssignments is an array of {keyword, type, ...} entries (type ∈ hub|blog|comparison|tool|landing|skip); duplicate keywords are rejected. Example (rename): {"clusterId":"kwc_123","name":"Better cluster name"}. Example (remove a member): fetch full keywordsMeta, filter out the unwanted keyword, then {"clusterId":"kwc_123","keywordsMeta":[...remaining members]}.

Inputs: clusterId (required), name, brandId, contentMix, +4 more.

seo_edit_keywordAInspect

Edit a single SeoScoredKeyword. Housekeeping op — not part of the main flow. At least one of intent, userTags, priority, or excludedFromClustering must be supplied. Use to override the auto-detected intent label, attach user tags, manually nudge priority (0..1), or exclude a noisy keyword from clustering. Example: {"keywordId":"kw_123","intent":"commercial","userTags":["enterprise"]}.

Inputs: keywordId (required), intent, brandId, priority, +2 more.

seo_gapAInspect

Identify content gaps — topics the brand's competitors cover but the brand doesn't. Returns short detail by default: {id?, topic?, keyword?} labels only per gap. Use detail="medium" for compact gaps (+ searchVolume, difficulty, competitorDomains) or detail="full" for the raw API response.

Inputs: detail, brandId.

seo_generate_clustersAInspect

Step 4 of the SEO / GEO flow — async cluster-generation step. Groups related keywords into topic clusters that become candidate pillar topics. Typically takes ~1–2 min. Returns {operationId, status} — Poll get_job with the operationId until state is completed (or failed/partially_failed/cancelled on error). After completion, call seo_list_clusters to pick a target, then seo_generate_roadmap.

Inputs: brandId.

seo_generate_keywordsAInspect

Step 2 of the SEO / GEO flow. Async — expands seed keywords into the full keyword universe. Typically takes ~1–3 min. Uses credits. Returns {operationId, status} — Poll get_job with the operationId until state is completed (or failed/partially_failed/cancelled on error). By default the server auto-derives 30-40 seed concepts from the brand's own context (products, ICP, positioning) and expands those. Pass seeds to steer expansion yourself instead — e.g. to target specific topics or geographies the brand context wouldn't surface on its own ("California", "Texas", "Nashville plumbers"). Supplying seeds REPLACES the automatic brand-derived seed generation for this call — it does not add to it. 3-20 short phrases, the kind of thing someone would actually type into Google (2-4 words, no jargon). The only other thing the agent can tweak is autoScore (defaults to true server-side — set false to skip volume/difficulty scoring). After completion, call seo_categorize.

Inputs: seeds, brandId, autoScore.

seo_generate_roadmapAInspect

Step 6. Turn one or more clusters into a prioritized content roadmap of blog articles to write. Pass clusterId (single) or clusterIds (array of cluster IDs from seo_list_clusters) — omit both to roadmap all clusters. After this, call seo_write_article.

Inputs: brandId, clusterId, clusterIds.

seo_generate_side_pageAInspect

Generates a side page for a brand's landing page, optionally linked to an SEO cluster (clusterId). When linked, the side page surfaces in cluster-context queries and inherits the cluster's keyword targeting — strengthening topical authority that feeds GEO citation patterns. Two body modes: • freeform: pass key + prompt (+ optional keywords, selectedSections, voiceProfileId, sidePageType). Freeform now writes real section-level content (hero/features/showcase/faq/cta), not just metadata. • brief: pass key + brief (structured outline) + optional briefId and roadmapItemId. Typically takes ~2–5 min. Async — returns { success, operationId, operationRowId, pollUrl, sidePageId }. Poll get_job with the returned operationId until state is completed (or failed/partially_failed/cancelled on error); the generated page's sections will be populated once complete. Comparison-type briefs run synchronously and return sidePageId directly. slug is the PARENT landing page slug under which the side page is created.

Inputs: key (required), slug (required), brief, prompt, +8 more.

seo_get_briefAInspect

Fetch a single SeoBrief by id, including its briefData outline, status, roadmap item, and cluster. Returns full detail by default (complete brief incl briefData). Use detail="medium" for {id, type, status, title, clusterName, briefSummary, sidePageUrl} or detail="short" for {id, type, status}. Use to inspect a brief before refining it with seo_edit_brief or approving it with seo_approve_briefs.

Inputs: briefId (required), detail, brandId.

seo_list_briefsAInspect

Returns ALL briefs across EVERY status by default — do NOT add a status filter unless the user explicitly asks. statusBreakdown gives the per-status counts (match these to the dashboard's brief count). NOTE: briefs whose generation is still in-flight may not appear here yet — check list_operations / get_job for in-progress generation. Returns short detail by default: {id, type, status, title} per brief. Use detail="medium" for compact summary (clusterId, clusterName, briefSummary, sidePageUrl, generationError, blogArticleId, generatedAt, approvedAt) or detail="full" for raw briefs including briefData outline. To inspect a single brief's full outline, call seo_get_brief with detail="full". Filters: status (CSV — e.g. 'pending_review,approved'), type (CSV — e.g. 'blog,comparison,landing'), clusterId, roadmapItemId, q (cluster-name fuzzy match), limit (default 50, max 200), cursor. Response shape: { count, total, nextCursor, statusBreakdown, detail, briefs: [...] }.

Inputs: q, type, limit, cursor, +5 more.

seo_list_clustersAInspect

Step 5. List clusters so the agent can pick one (or several) to approve before brief and roadmap generation. Returns short detail by default: {id, name, status} per cluster. Use detail="medium" for the full compact summary (pillarKeyword, briefGenerationStatus, briefCount, keywordCount, topKeywords, firstBriefId, description, productFit, relevanceScore) or detail="full" for raw cluster objects. Full keyword detail (keywordsMeta, contentMix, briefAssignments) is intentionally omitted at short/medium to keep context small — use cluster IDs with approve/reject tools directly. Supports server-side filtering: status (CSV of pending_review/approved/rejected), productFit (core/adjacent/out_of_scope), archetype (competitor), origin (CSV of pipeline/manual), q (text search over name/description/pillarKeyword).

Inputs: q, detail, origin, status, +3 more.

seo_list_keyword_idsAInspect

Return just the ids of every SeoScoredKeyword matching a filter — unpaginated, no keyword data attached. Housekeeping op — not part of the main flow. Accepts the same filter set as seo_list_keywords: source, intent, clusterId, q, hasTag, volumeMin/volumeMax, kdMin/kdMax, relevanceMin/relevanceMax, priorityMin/priorityMax, includeDeleted, excludedFromClustering. Use to select "all keywords matching filter X" in one call, then feed the returned ids into seo_bulk_delete_keywords or seo_bulk_edit_keywords. Example: filter relevanceMax=0.2 to find low-relevance keywords, then bulk-delete or bulk-edit them. Or hasTag="geo:us-mn" to select every Minnesota-tagged keyword after seo_tag_geography.

Inputs: q, kdMax, kdMin, hasTag, +12 more.

seo_list_keywordsAInspect

List generated keywords for the brand. Useful for auditing between steps. Returns short detail by default: {id, keyword, intent} per keyword. Use detail="medium" for the full compact summary (priority, searchVolume, difficulty, relevance, clusterId, excludedFromClustering, userTags) or detail="full" for raw keyword objects. Supports server-side filtering: source, intent, clusterId, q (substring search), hasTag, volumeMin/volumeMax, kdMin/kdMax, relevanceMin/relevanceMax, priorityMin/priorityMax, includeDeleted, excludedFromClustering. hasTag filters on userTags (OR match) — use it to find geo-tagged keywords after seo_tag_geography, e.g. hasTag="geo:us-mn" or hasTag="geo:us-mn,geo:us-tx" for multiple regions. Use cursor (from a previous call's response) to page through results beyond limit.

Inputs: q, kdMax, kdMin, limit, +15 more.

seo_list_resultsAInspect

List the 'Generated Results' (blog articles + side pages + comparisons) the SEO/GEO pipeline has produced — mirrors the dashboard Results tab. Includes BOTH draft and published items. Use kind to filter. This is the canonical 'what content has been generated' list — prefer it over reconstructing results from briefs.

Inputs: kind, limit, cursor, detail, +2 more.

seo_list_roadmapAInspect

List roadmap items (blog topics queued for writing). Returns short detail by default: {id, title, status} per item. Use detail="medium" for the compact summary (priority, primaryKeywords, clusterId) or detail="full" for raw objects. Call seo_roadmap_get with detail="full" for a single item's complete detail.

Inputs: detail, status, brandId.

seo_merge_clustersAInspect

Merge one cluster into another: reassigns the source cluster's keywords, roadmap items (and their briefs, which follow transitively), and any linked blog articles to the target cluster, then deletes the source cluster. Not undoable. Housekeeping op — not part of the main flow. Use when seo_list_clusters or a rescan report shows near-duplicate clusters that should be consolidated. The target cluster's own name/description/keywordsMeta/contentMix are NOT changed by the merge — only the FK relations (keyword.clusterId, roadmap.clusterId, blogArticle.clusterId) move over. Use seo_edit_cluster afterward if the target's keywordsMeta needs updating to include the newly reassigned keywords.

Inputs: clusterId (required), sourceClusterId (required), brandId.

seo_publish_articleAInspect

Step 10. Publish or schedule a roadmap-generated article to a publication. Free-tier choke point — may return FREE_CAP_REACHED with a checkoutUrl.

Inputs: articleId (required), brandId, scheduledAt, connectionIds, +1 more.

seo_regenerate_briefAInspect

Re-runs L3 brief generation for a single brief (scoped to its cluster). Typically takes ~2–5 min. Async — returns {operationId, status}. Poll get_job with the operationId until state is completed (or failed/partially_failed/cancelled on error), then re-fetch with seo_get_brief to see the refreshed briefData. Use when the existing brief's outline is unusable and a structured seo_edit_brief won't recover it.

Inputs: briefId (required), brandId.

seo_reject_clusterAInspect

Reject a single cluster — marks it rejected and detaches its scored keywords. Use when a generated cluster isn't relevant.

Inputs: clusterId (required), brandId.

seo_restore_clusterAInspect

Restore a rejected cluster back to pending_review so it can be approved again.

Inputs: clusterId (required), brandId.

seo_restore_keywordAInspect

Undo a soft-delete: clears deletedAt on the given SeoScoredKeyword ids so they reappear in seo_list_keywords / seo_list_keyword_ids. Housekeeping op — not part of the main flow. Use after seo_delete_keyword or seo_bulk_delete_keywords removed something that shouldn't have been removed. IDs that are not currently soft-deleted are silently no-ops (the response's restored count only reflects rows that actually changed). Find deleted ids with seo_list_keyword_ids using includeDeleted=true.

Inputs: keywordIds (required), brandId.

seo_roadmap_deleteAInspect

Permanently delete a roadmap item. Pass confirm: true to proceed — this is irreversible.

Inputs: itemId (required), confirm (required), brandId.

seo_roadmap_editAInspect

Edit a roadmap item — update its title, status (suggested|in_progress|completed|ignored), or priority.

Inputs: itemId (required), title, status, brandId, +1 more.

seo_roadmap_getAInspect

View a single roadmap item by ID. Returns full detail by default (raw object). Use detail="medium" for {id, title, status, primaryKeywords, clusterId} or detail="short" for {id, title, status}.

Inputs: itemId (required), detail, brandId.

seo_roadmap_statsBInspect

Progress stats for the content roadmap (completed, in-progress, suggested counts).

Inputs: brandId.

seo_tag_geographyAInspect

Geo pivot Stage 1. Async — classifies every keyword's geographic intent and writes a geo:* tag into userTags. Tags: geo:<country>-<subdivision> (e.g. "geo:us-mn") for a place that resolves to one region, geo:<country> (e.g. "geo:us") for country-only intent, geo:none for no geographic intent, geo:ambiguous for a place name that maps to multiple regions with no way to resolve it. Typically takes ~1–2 min. Uses credits (unless dryRun is true). Returns {operationId, status} — poll get_job with the operationId until state is completed (or failed/partially_failed/cancelled on error). The job result includes tagCounts (tag -> count), ambiguousKeywords (needs human review), and costUsd. Idempotent by default: keywords that already carry any geo:* tag are skipped on a re-run — pass retag:true to force re-classification of everything. Pass dryRun:true to get the full classification breakdown WITHOUT writing any tags — use this first to review tagCounts and ambiguousKeywords before committing. After completion, use seo_list_keywords or seo_list_keyword_ids with hasTag="geo:us-mn" (etc.) to select the tagged keywords for further action.

Inputs: retag, dryRun, brandId.

seo_unapprove_clusterAInspect

Revert an approved cluster back to pending_review. Fails if briefs have already been generated for this cluster (cannot be reverted once briefs exist).

Inputs: clusterId (required), brandId.

seo_write_articleAInspect

ALTERNATIVE write path — only call this when a brief was NOT approved via seo_approve_briefs (which already auto-generates). If the brief status is writing, generation is already in progress — poll the existing operationId with get_job until state is completed rather than calling this again. Step 7 (manual path). Draft a full blog article for a roadmap item. Uses credits. Typically takes ~3–8 min per article. Precondition: the brief for this roadmap item must be in status approved. If the brief is still drafted or pending_review, review with seo_list_briefs / seo_get_brief, refine with seo_edit_brief, then approve with seo_approve_briefs (which will auto-generate). Returns an articleId that can be reviewed, edited, or published.

Inputs: roadmapItemId (required), count, brandId, voiceProfileId.

set_active_brandAInspect

Set the active brand for this session. All subsequent tools will use this brand by default.

Inputs: brandId (required).

set_brand_mediumsAInspect

STEP 2 of brand onboarding. Saves the list of platforms the brand publishes on. Call this immediately after create_brand or onboard_brand and the user has picked platforms. After this, call get_onboarding_status every ~15 seconds until it reports done.

Inputs: mediums (required), brandId.

set_landing_page_sectionAInspect

Set one field on a landing page section (dot-paths in field supported, e.g. 'plans.0.ctaUrl'), or replace a whole section with replaceSection=true. Pass the bare content-section key (e.g. 'hero', 'features', 'pricing') — the server maps it into the page's content tree. Top-level roots like slotMap, config, navigation, siteMetadata are also accepted as-is. Each call creates a new draft version — for many related changes across a page, prefer vibe_edit_landing_page instead. Example: section='hero', field='title', value='New headline'.

Inputs: slug (required), value (required), section (required), name, +3 more.

set_lp_section_layoutAInspect

Reorder and/or toggle visibility of a landing page's sections. Pass at least one of sectionOrder/sectionVisibility. Valid section-order keys (all 11): hero, features, pricing, cta, faq, howItWorks, showcase, categoryExplorer, replacesStack, comparisonMatrix, roiCalculator. sectionVisibility keys are the toggleable subset of the above. When both are given, order is attempted first, then visibility — each is applied independently, so one can succeed while the other fails. The result always reports both outcomes: { order: |{error}, visibility: |{error}, partialFailure: true } if only one part failed. This tool only throws if every requested part fails (or if a single requested part fails).

Inputs: slug (required), sectionOrder, sectionVisibility.

set_post_cardsAInspect

Bulk-replace all carousel cards for a post. Provide a full array of card objects with title, body, and optional number.

Inputs: cards (required), postId (required), rerender.

set_side_page_sectionAInspect

Update one section of a side page with STRUCTURED, typed fields (not a content string). The write must match the section's real shape or it is rejected with a 400 validation error. Landing sections use typed objects, e.g. hero → { title: { prefix, suffix }, description, testimonials: [...] }; comparison sections (matrix, verdict, scorecard, decisionTree, priceCalculator, competitorClaims, ...) use their comparison-schema shape. Use view_side_page(detail:'full') first to see the current section shape, then send the same shape back with your edits. Pass EITHER fields (a partial section object merged onto the current section) OR field (a dot-path) + value for a single nested change, OR instructions alone for a natural-language edit (the server runs an AI pass scoped to this section). type:"text" pages: there is no per-section nesting — the whole page is one flat {title, htmlContent} document. sectionId is accepted for symmetry (e.g. "content"/"htmlContent"/"title") but every edit applies to the whole document: pass fields:{title,htmlContent}, field:"title"|"htmlContent"+value, or instructions alone for an AI rewrite of the whole page. edit_side_page's title/htmlContent params are a simpler direct-write shortcut for the same document. Every edit creates a new draft version (like landing-page section edits) — see list_side_page_versions / restore_side_page_version; on a published page, edits stay draft-only until set_side_page_state({published:true}) publishes them.

Inputs: slug (required), sideKey (required), sectionId (required), field, +3 more.

set_side_page_stateAInspect

Publish or unpublish a side page. published:true publishes the CURRENT DRAFT — it sets the published pointer to the latest draft version, which is how you make draft edits (from edit_side_page / set_side_page_section) live. published:false hides the page publicly but keeps the last-published version marker, so re-publishing with no further edits restores it instantly. The response includes publishedVersionId — the version now live (unchanged from before on unpublish) — so you know exactly which version is public without a follow-up view_side_page call.

Inputs: slug (required), sideKey (required), published (required).

set_social_media_rulesAInspect

Update a brand's social media content rules for ONE platform. By default this MERGES your provided fields into the existing rules (send only what you want to change — other fields are preserved; arrays you provide replace the old array). Set replace=true to overwrite the entire platform ruleset. Valid platforms: linkedin, x/twitter, facebook, instagram, threads, general. Tip: call get_social_media_rules first to see current values.

Inputs: rules (required), platform (required), brandId, replace.

set_weekly_scheduleAInspect

Create or replace the weekly content schedule for the active brand. dayConfigs: array of { dayOfWeek (0=Sun…6=Sat), mediums: [{ medium, postsPerDay }] }. Mediums: x/twitter | linkedin | instagram | facebook | threads | blog. After setting, call enable_weekly_schedule to activate it.

Inputs: dayConfigs (required), brandId, enabled, timezone, +2 more.

storyline_add_line_itemAInspect

Add a new line item (deliverable) to a storyline's strategy. Specify the channel, type, title, description, and a config map (pass {} if no extra config).

Inputs: type (required), title (required), config (required), channel (required), +5 more.

storyline_clarifyAInspect

Run the intake/clarification step for a storyline. The API returns follow-up questions or a readiness signal; call iteratively until the system has enough context. After clarification is complete, call storyline_generate_brief.

Inputs: storylineId (required), brandId, userMessage.

storyline_confirm_briefAInspect

Confirm (lock) the brief for a storyline, advancing it to the strategy phase. After confirmation, call storyline_generate_strategy.

Inputs: storylineId (required), brandId.

storyline_createAInspect

Create a new storyline (marketing plan) for the brand. Pass a prompt describing the campaign goal; optionally provide a title. After creation, call storyline_clarify to gather context, then storyline_generate_brief.

Inputs: prompt (required), title, brandId.

storyline_deleteAInspect

Archive (soft-delete) a storyline. Pass confirm: true to proceed. Use storyline_restore to reverse this.

Inputs: confirm (required), storylineId (required), brandId.

storyline_delete_line_itemAInspect

Permanently remove a line item from a storyline's strategy. Pass confirm: true to proceed.

Inputs: itemId (required), confirm (required), storylineId (required), brandId.

storyline_edit_briefAInspect

Apply an AI-driven edit to the current brief using a natural-language instruction. Examples: 'Make the tone more casual', 'Add a proof point about our 99% uptime SLA'. Optionally pass expectedVersion for optimistic concurrency.

Inputs: instruction (required), storylineId (required), brandId, expectedVersion.

storyline_edit_strategyAInspect

Apply an AI-driven edit to the current strategy using a natural-language instruction. Examples: 'Add a LinkedIn video post for launch week', 'Remove the influencer outreach line items'.

Inputs: instruction (required), storylineId (required), brandId.

storyline_estimateAInspect

Read-only dry-run. Estimate the credits required to execute the storyline without actually running it. Use before storyline_execute to surface the cost to the user for approval. Returns { estimatedCredits, lineItemBreakdown } or similar.

Inputs: storylineId (required), brandId.

storyline_executeAInspect

Async. Execute a storyline — generates content drafts for all selected line items. Returns { operationId, status } — poll get_job with the operationId until state=completed. Typically takes ~3–8 min. Call storyline_estimate first to surface the credit cost before execution.

Inputs: storylineId (required), brandId.

storyline_generate_briefAInspect

Async. Generate the marketing brief for a storyline (positioning, key messages, audience, timing, tone notes). Returns { operationId, status } — poll get_job with the operationId until state=completed. Typically takes ~1–3 min. After completion, review the brief with storyline_get, then call storyline_confirm_brief to advance to strategy.

Inputs: storylineId (required), brandId.

storyline_generate_strategyAInspect

Async. Generate the strategy and line-items for a storyline based on its confirmed brief. Returns { operationId, status } — poll get_job with the operationId until state=completed. Typically takes ~2–5 min. After completion, review with storyline_get_strategy, then optionally edit with storyline_edit_strategy or add/remove line items.

Inputs: storylineId (required), brandId.

storyline_getAInspect

Fetch a single storyline by ID with its full state (brief, strategy, line items, status). Returns full detail by default. Use detail="medium" for a compact summary or detail="short" for {id,title,status}.

Inputs: storylineId (required), detail, brandId.

storyline_get_strategyAInspect

Fetch the strategy and line items for a storyline. Returns full detail by default (raw strategy + all line items). Use detail="medium" for a compact summary or detail="short" for {id,status} + line-item count.

Inputs: storylineId (required), detail, brandId.

storyline_listAInspect

List the brand's storylines (marketing plans). short detail {id,title,status}; medium adds isLive, dates, promptSummary; full = raw.

Inputs: detail, brandId.

storyline_regenerate_line_itemAInspect

Async. Re-generate a single line item's content draft. Returns { operationId, status } — poll get_job with the operationId until state=completed. Typically takes ~1–3 min.

Inputs: itemId (required), storylineId (required), brandId.

storyline_restoreAInspect

Restore an archived storyline back to active state.

Inputs: storylineId (required), brandId.

storyline_set_briefAInspect

Manually set (replace) the full brief for a storyline. Use to provide a human-authored brief or to push back an edited version retrieved via storyline_get. Pass the complete brief object and the current expectedVersion (use 0 when setting from scratch). After setting, call storyline_confirm_brief to advance to strategy generation.

Inputs: brief (required), storylineId (required), expectedVersion (required), brandId.

storyline_updateAInspect

Update metadata on a storyline: title, live status, or start/end/launch dates. Pass at least one field to change.

Inputs: storylineId (required), title, isLive, brandId, +3 more.

storyline_update_line_itemAInspect

Update a line item on a storyline — select/deselect, retitle, change description, targetDate, or config. Pass only the fields to change.

Inputs: itemId (required), storylineId (required), title, config, +4 more.

suggest_assets_for_postAInspect

Get AI-suggested assets from the brand library that match a given post context or topic.

Inputs: context (required), limit, brandId.

tag_assetAInspect

Add or remove tags on an asset. Provide addTags and/or removeTags as arrays.

Inputs: assetId (required), addTags, brandId, removeTags.

template_createAInspect

Create one or more content templates for the brand. Pass a single template object, or pass the 'templates' array param for bulk creation. If both are supplied, 'templates' (bulk) takes precedence. Returns the created template record(s).

Inputs: body, title, brandId, example, +5 more.

template_deleteAInspect

Permanently delete a content template from the brand. This action is irreversible.

Inputs: templateId (required), brandId.

template_extractAInspect

AI extracts a reusable content template from a pasted post text. Synchronous (seconds) — no polling needed. Pass save=true to also persist the template to the brand's library. Returns the extracted template object; if saved, includes the new template id.

Inputs: postText (required), save, brandId.

template_listAInspect

List the brand's saved content templates. short {id,title,category}; medium adds platforms,isFavorite,bodyPreview (160 chars); full = raw. Pass category to filter (e.g. 'hook', 'cta', 'thread'). Results are ordered by isFavorite desc, then usageCount desc.

Inputs: detail, brandId, category.

template_pickAInspect

RE-RANKER: AI scores a caller-supplied list of candidate templates and picks the N best-fitting ones for a given theme or topic. This tool does NOT read stored templates server-side — the caller must supply the candidates explicitly (e.g. call template_list first, then pass the results here). Synchronous — no polling needed. Pass the templates array from template_list (full detail) as candidates. Returns { templateIds } — an ordered array of the winning template IDs.

Inputs: count (required), theme (required), templates (required), brandId.

template_updateAInspect

Update an existing content template. All fields are optional — only supplied fields are changed. Use isFavorite=true/false to toggle favorite status.

Inputs: templateId (required), body, title, brandId, +5 more.

update_blog_articleAInspect

Edit a blog article — title, content, excerpt, SEO fields, status, author, category, featured/header image, or CTA. Set status='published' to make it live on your PostKing blog. CTA (call-to-action) is structured data, NOT part of the article body — never write CTA markup into content. Use cta: { url, label, headline, body } to set it (url is required when enabling), or cta: { enabled: false } to remove it. cta and sidePageInfo are mutually exclusive — pass sidePageInfo only if you need to link to an existing side page by id/slug (from list_side_pages) instead of a raw url; either way, malformed CTA shapes are now rejected by the server rather than silently persisted, so pass exactly the documented fields.

Inputs: articleId (required), cta, title, status, +11 more.

update_publicationAInspect

Update an existing blog publication's metadata — title, description, domain/routing config, or layout. Only the fields you pass are changed (partial update). Distinct from create_publication (which creates a new one). publicationId comes from list_publications or list_blogs.

Inputs: publicationId (required), title, layout, brandId, +4 more.

upload_assetAInspect

Upload an asset to the brand library from a local file path or base64-encoded content. Prefer filePath for local files: the server reads and base64-encodes the file itself, avoiding truncation of large base64 strings over the tool_call boundary. fileBase64 is still supported for remote/inline use where no local path is available. For large files over the remote/HTTP transport, a single fileBase64 string can get truncated crossing the LLM→tool_call boundary — use the chunked flow instead: upload_asset_begin → upload_asset_chunk (× N) → upload_asset_finish. Provide exactly one of filePath or fileBase64. Returns the new asset ID and URL.

Inputs: name, tags, brandId, fileName, +4 more.

upload_asset_abortAInspect

Cancel a chunked asset upload in progress and discard any buffered chunks.

Inputs: uploadId (required).

upload_asset_beginAInspect

Start a chunked asset upload. Use this instead of upload_asset's fileBase64 param for large files over the remote/HTTP transport, where a single large base64 string can get truncated crossing the LLM→tool_call boundary. Flow: upload_asset_begin (once) → upload_asset_chunk (once per chunk, in order) → upload_asset_finish (once). Returns an uploadId that expires after 10 minutes of inactivity.

Inputs: fileName (required), name, tags, sha256, +4 more.

upload_asset_chunkAInspect

Send one chunk of a base64-encoded file previously started with upload_asset_begin. Chunks must be sent in order, index starting at 0, with no gaps.

Inputs: index (required), uploadId (required), fileBase64Chunk (required).

upload_asset_finishAInspect

Finalize a chunked asset upload: reassembles the buffered chunks, verifies integrity, and uploads the asset to the brand library. Returns the new asset ID and URL.

Inputs: uploadId (required).

verify_domainAInspect

Check DNS verification for a domain. Returns whether it's pointing to PostKing servers and what A record is needed if not.

Inputs: domainId (required).

vibe_edit_landing_pageAInspect

Use AI to propose an edit to a landing page based on natural-language instructions. This is step 1 of a propose → review → apply flow — it does NOT change anything by itself: 1) Call this tool. Returns { operationId } — nothing is applied yet. 2) Poll get_vibe_edit_status(slug, operationId) — NOT get_job — until status is 'completed'. Vibe-edit sessions live in a separate store from the generic job/operation queue, so get_job will not find them. 3) Review the changes array returned by get_vibe_edit_status: field-level before/after entries, each with an index and a path. 4) Call apply_vibe_edit with all=true (accept everything) or a subset via indices/paths. 5) Call publish_landing_page to make the applied changes live. scope='full' edits the whole page; scope='section' restricts the edit to one section — sectionId is REQUIRED when scope='section'. Example section keys: hero, features, pricing, cta, faq, howItWorks, showcase, categoryExplorer, replacesStack, comparisonMatrix, roiCalculator.

Inputs: slug (required), instructions (required), scope, sectionId.

view_assetAInspect

View details of a single asset by ID. Supports detail param: short=id+type+name, medium=key fields, full=raw.

Inputs: assetId (required), detail, brandId.

view_landing_pageAInspect

Fetch a landing page by slug. detail='full' (default) returns full data JSONB plus previewUrl (public GUI preview link) and webUrl (dashboard editor link); 'medium' returns summary + sectionKeys/sectionWordCounts + previewUrl + webUrl; 'short' returns id/slug/name/status. Section bodies and rendered HTML appear only at full.

Inputs: slug (required), detail.

view_lp_draftAInspect

View the unpublished draft of a landing page. detail='full' (default) includes full versionData plus previewUrl (public GUI preview link, ?version= form); 'medium' adds sectionKeys/sectionWordCounts + previewUrl; 'short' is id/slug/name/status only.

Inputs: slug (required), detail.

view_lp_versionAInspect

View a specific LP version. detail='full' (default) returns full data plus previewUrl (public GUI preview link — the published form if this is the live version, otherwise the ?version= form); 'medium' adds sectionKeys/sectionWordCounts + previewUrl.

Inputs: slug (required), versionId (required), detail.

view_side_pageAInspect

View a side page including sections and rendered HTML. detail='full' (default) includes rendered HTML and full overrides (use this to read a section's typed shape before editing it with set_side_page_section); 'medium' gives summary + overrideSectionKeys (the section ids you can pass to set_side_page_section); 'short' gives id/slug/name/type/isPublished. Rendered HTML appears only at full. medium/full also include currentVersionId (the draft) and publishedVersionId (the live version) — a mismatch means there are unpublished draft edits.

Inputs: slug (required), sideKey (required), detail.

view_side_page_versionAInspect

View a specific side-page version snapshot. detail='full' (default) returns the complete snapshot { type, overrides, siteMetadata, slotMap, config } plus _meta { versionId, isCurrent, isPublished, createdAt }; 'medium' gives type + _meta + overrideSectionKeys (section ids only, no content); 'short' gives just _meta.

Inputs: slug (required), sideKey (required), versionId (required), detail.

whoamiAInspect

Return the profile of the currently authenticated PostKing user (email, plan, credit balance, token source).

Inputs: no named parameters.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.3/5.0

    Scored across 243 tools

    Disambiguation2/5

    Despite detailed descriptions, many tools occupy overlapping roles: generate_side_page and seo_generate_side_page are near-duplicates, list_jobs/list_operations/get_job offer three ways to inspect async work, and upload_asset overlaps with the upload_asset_begin/chunk/finish flow. An agent selecting from 243 tools will frequently face ambiguous choices.

    Naming Consistency3/5

    Names are mostly snake_case verb_noun, but conventions shift across and within domains: seo_roadmap_get vs seo_list_roadmap vs get_seo_roadmap, list_blogs vs list_publications, and unprefixed tools like whoami and health break the pattern. It is readable but not a coherent naming system.

    Tool Count1/5

    243 tools is far beyond a reasonable MCP surface, forcing massive context consumption and making it hard for an agent to even notice the right tool. This is an extreme scope mismatch for a single server regardless of how many features PostKing has.

    Completeness4/5

    Coverage is remarkably broad: posts, blogs, SEO pipeline, landing pages, side pages, assets, competitors, storylines, knowledge, and billing all have lifecycle support. Minor gaps exist, such as no direct update-post-content tool and asymmetries between soft-delete/restore flows, but they are workarounds rather than dead ends.

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      C
      maintenance
      MCP server to manage social media accounts from AI assistants, enabling post creation, scheduling, publishing, and media uploads across multiple platforms.
      13
      11 npm
      1
      MIT
    • A
      license
      Not graded
      quality
      F
      maintenance
      MCP server for managing social media posts across multiple platforms using the Postiz API. Supports creating, updating, deleting posts, and generating videos.
      38 npm
      3
      MIT
    • A
      license
      A
      quality
      C
      maintenance
      MCP server for QPost that lets AI agents schedule and publish video/image posts to YouTube, TikTok, and Instagram via QPost's REST API.
      7
      82 npm
      MIT