MCP

Tool reference

Every tool the PostNext MCP server exposes, with its inputs, return shape and a copy-paste example.

Authentication

Every request to https://mcp.postnext.io/api requires an Authorization header with a Bearer token. You have two ways to get one.

OAuth (recommended for AI clients)

AI clients run Dynamic Client Registration on first connect, then walk the user through an OAuth consent screen. The /mcp/connect page handles this automatically. Your client receives a 30-day access token.

API key

For scripts and CI, generate a personal API key in the PostNext app under Account → API Keys. The key starts with apikey_ and is presented as a bearer token like any other.

Endpoint

All tool calls go to a single JSON-RPC 2.0 endpoint over HTTPS POST.

POST https://mcp.postnext.io/api

Tools

list_scheduled_posts

List your scheduled posts (queued for publish but not yet sent).

Arguments

limitnumber ·optional · default 20
Maximum results to return (1-100, default 20).
fromstring (ISO 8601) ·optional
ISO timestamp; only return posts scheduled at or after this time.

Returns

An object with posts: [{id, platform, content, scheduledAt, status}]. Up to limit results.

Example

curl -X POST https://mcp.postnext.io/api \
  -H "Authorization: Bearer apikey_xxx" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"tools/call","id":1,
       "params":{"name":"list_scheduled_posts",
                 "arguments":{"limit":5}}}'

list_drafts

List your draft posts (not yet scheduled).

Arguments

limitnumber ·optional · default 20
Maximum results to return (1-100, default 20).

Returns

An object with drafts: [{id, platform, content, updatedAt}]. Up to limit results.

Example

{"jsonrpc":"2.0","method":"tools/call","id":2,
 "params":{"name":"list_drafts","arguments":{"limit":10}}}

list_connected_accounts

List the social accounts connected to your team.

Arguments

No arguments.

Returns

An object with accounts: [{platform, handle, connected, lastSyncAt}].

Example

{"jsonrpc":"2.0","method":"tools/call","id":3,
 "params":{"name":"list_connected_accounts","arguments":{}}}

get_account_healthPaid plan

Get a health summary across all connected platforms.

Arguments

platformenum ·optional
Social platform: twitter, instagram, linkedin, threads, or tiktok.
windowDays7 | 30 | 90 ·optional · default 30
Lookback window in days: 7, 30 or 90 (default 30).

Returns

An object with windowDays, postsScheduled, postsPublished, postsFailed, a byPlatform breakdown and topErrors[].

Example

{"jsonrpc":"2.0","method":"tools/call","id":4,
 "params":{"name":"get_account_health",
           "arguments":{"windowDays":30}}}

create_post_draft

Create a new draft post. Drafts are not auto-published.

Arguments

platformenum ·required
Social platform: twitter, instagram, linkedin, threads, or tiktok.
contentstring ·required
Post body (1-2200 characters).
mediaUrlsarray<string> ·optional
Up to 10 image/video URLs.
clientRequestIdstring ·optional
Optional idempotency key. Same key within 5 minutes returns the cached result.

Returns

An object with the new draft: {id, platform, content, status: "DRAFT", createdAt}.

Example

{"jsonrpc":"2.0","method":"tools/call","id":5,
 "params":{"name":"create_post_draft",
           "arguments":{"platform":"twitter",
                        "content":"Hello from MCP"}}}

update_post_draft

Update an existing draft. At least one of content or mediaUrls must be provided.

Arguments

postIdstring ·required
PostNext post id from a list call.
contentstring ·optional
Post body (1-2200 characters).
mediaUrlsarray<string> ·optional
Up to 10 image/video URLs.
clientRequestIdstring ·optional
Optional idempotency key. Same key within 5 minutes returns the cached result.

Returns

An object with the updated draft: {id, platform, content, mediaUrls, status, updatedAt}.

Example

{"jsonrpc":"2.0","method":"tools/call","id":6,
 "params":{"name":"update_post_draft",
           "arguments":{"postId":"",
                        "content":"Updated copy"}}}

connect_channel

Generate a one-time URL the user can open to authorize a new platform connection.

Arguments

platformenum ·required
Social platform: twitter, instagram, linkedin, threads, or tiktok.

Returns

An object with authUrl (one-time link the user opens to authorise), expiresAt and platform.

Example

{"jsonrpc":"2.0","method":"tools/call","id":7,
 "params":{"name":"connect_channel",
           "arguments":{"platform":"linkedin"}}}

schedule_post

Move a draft (status DRAFT) into the BullMQ publish queue at a future timestamp. Idempotent within ±60s drift; rejects re-schedule attempts at a different time without explicit cancel first.

Arguments

postIdstring ·required
PostNext post id from a list call.
scheduledAtstring (ISO 8601) ·required
ISO 8601 timestamp; must not be more than 5 minutes in the past.

Returns

An object with postId, scheduledAt (ISO), status: SCHEDULED.

Example

{"jsonrpc":"2.0","method":"tools/call","id":8,
 "params":{"name":"schedule_post",
           "arguments":{"postId":"",
                        "scheduledAt":"2026-05-10T09:00:00Z"}}}

cancel_scheduled_post

Cancel a scheduled post and remove it from the publish queue. The underlying draft is preserved.

Arguments

postIdstring ·required
PostNext post id from a list call.

Returns

An object with postId and status: CANCELLED.

Example

{"jsonrpc":"2.0","method":"tools/call","id":9,
 "params":{"name":"cancel_scheduled_post",
           "arguments":{"postId":""}}}

delete_draft

Permanently delete a draft post. Refuses non-DRAFT posts (use cancel_scheduled_post for SCHEDULED).

Arguments

postIdstring ·required
PostNext post id from a list call.

Returns

An object with postId and deleted: true.

Example

{"jsonrpc":"2.0","method":"tools/call","id":10,
 "params":{"name":"delete_draft",
           "arguments":{"postId":""}}}

get_post

Return the full PostGroup for a given postId with provider-by-platform content + status + timestamps.

Arguments

postIdstring ·required
PostNext post id from a list call.

Returns

An object with postId, status, scheduledAt, createdAt, updatedAt and providers (record of platform → content).

Example

{"jsonrpc":"2.0","method":"tools/call","id":11,
 "params":{"name":"get_post",
           "arguments":{"postId":""}}}

search_posts

Substring (case-insensitive) search across post content for the active team. Filters: status, platform, limit (1-100, default 20).

Arguments

querystring ·required
Substring to search for (3-200 characters; regex meta-chars are escaped).
statusenum ·optional
Optional: DRAFT | SCHEDULED | PUBLISHED | FAILED | CANCELLED.
platformenum ·optional
Social platform: twitter, instagram, linkedin, threads, or tiktok.
limitnumber ·optional · default 20
Maximum results to return (1-100, default 20).

Returns

An object with posts: [{postId, status, platforms, snippet, scheduledAt, updatedAt}]. Snippet contains the matching context with ellipsis on either side.

Example

{"jsonrpc":"2.0","method":"tools/call","id":12,
 "params":{"name":"search_posts",
           "arguments":{"query":"launch","limit":10}}}

list_teams

Return the teams the authenticated user owns or admins, with the currently active team flagged.

Arguments

No arguments.

Returns

An object with currentTeamId and teams: [{teamId, teamName, isCurrent}].

Example

{"jsonrpc":"2.0","method":"tools/call","id":13,
 "params":{"name":"list_teams","arguments":{}}}

set_current_team

Switch the active team for this Bearer token. The user must be a member. Persisted on the OAuth token doc; in-session mutation makes it effective immediately for subsequent tools in the same conversation.

Arguments

teamIdstring ·required
Target teamId from list_teams. Membership is re-validated server-side.

Returns

An object with teamId, teamName, persisted (true if OAuth, false if API key) and an optional note.

Example

{"jsonrpc":"2.0","method":"tools/call","id":14,
 "params":{"name":"set_current_team",
           "arguments":{"teamId":"team_xxxxx"}}}

get_plan_limits

Read the user's current subscription tier and per-tier quotas (channels, storage, AI credits, posting). Available on every plan. Useful before mutating tools to predict whether the call will be blocked.

Arguments

No arguments.

Returns

An object with tier, tierDisplayName, isPaid, isTrial, upgradeUrl, limits (channels/storage/aiCalls/posts each as {limit, current, exceeded} or {limit, allowed}) and creditsAvailable ({total, subscriptionRemaining, purchasedBalance} or null).

Example

{"jsonrpc":"2.0","method":"tools/call","id":15,
 "params":{"name":"get_plan_limits","arguments":{}}}

get_post_metrics

Fetch engagement metrics for a published post across every platform it was sent to. Twitter and Instagram return populated metrics (likes, retweets/shares, comments/replies, impressions); LinkedIn, Threads and TikTok return publish status and URL only (engagement collection deferred to a later release). A normalised totals roll-up sums likes/comments/shares/impressions across whichever platforms reported them.

Arguments

postId PostNext post id from a list call.

Returns

An object with postId, status, providers: [{platform, publishedPostId, publishedUrl, publishedAt, status, metrics}] and totals: {likes, comments, shares, impressions}. metrics is an object of numeric counts per platform, or null when the platform does not yet collect engagement.

Example

{"jsonrpc":"2.0","method":"tools/call","id":16,
 "params":{"name":"get_post_metrics",
           "arguments":{"postId":""}}}

get_publish_status

Diagnose what happened to a scheduled post: queue state, per-platform success/error, processing time, and the worker's job id. Returns isScheduled=false for posts that exist as drafts but were never moved into the publish queue, with a hint pointing at schedule_post.

Arguments

postId PostNext post id from a list call.

Returns

An object with postId, isScheduled, status, scheduledAt, publishedAt, platforms, processingTimeMs, jobId, topLevelError, and results: [{platform, success, publishedPostId, publishedAt, error}]. Includes hint when isScheduled is false.

Example

{"jsonrpc":"2.0","method":"tools/call","id":17,
 "params":{"name":"get_publish_status",
           "arguments":{"postId":""}}}

update_brand_profile

Patch the user's active brand profile. Whitelisted fields: bio, brandVoice, personalityTraits, mainThemes, expertiseAreas, preferredHashtags, audienceSize. Anything else is silently dropped. Resolves "active" as team default first, then the user's first own active profile.

Arguments

brandVoice Array of brand-voice descriptors (e.g. ["professional", "concise"]).

Other patchable fields: bio, personalityTraits, mainThemes, expertiseAreas, preferredHashtags, audienceSize.

Returns

An object with profileId, name, updated: [field names that were patched], and the current values of bio, brandVoice, personalityTraits, mainThemes, expertiseAreas, preferredHashtags, audienceSize after the patch.

Example

{"jsonrpc":"2.0","method":"tools/call","id":18,
 "params":{"name":"update_brand_profile",
           "arguments":{"brandVoice":["professional","concise"]}}}

get_best_time_to_post Paid plan

Recommend the top N (dayOfWeek, hour) slots for the next post on a given platform, ranked by engagement-per-post over the past 90 days. Twitter and Instagram return engagement-weighted scores; LinkedIn, Threads, TikTok rank by post-frequency only. Times are in the supplied IANA timezone (default UTC). Paid plan required.

Arguments

platform Social platform: twitter, instagram, linkedin, threads, or tiktok.

timezone IANA timezone name (e.g. Europe/Berlin, America/New_York). Defaults to UTC.

topN Number of slot recommendations to return (1-24, default 5).

Returns

An object with platform, timezone, sampleWindowDays, sampleSize, metricsAvailable, and recommendations: [{dayOfWeek (1-7, Mon=1), dayLabel, hour (0-23), score, basedOn: {posts, avgEngagement}}]. Includes hint for cold-start or metrics-unavailable cases.

Example

{"jsonrpc":"2.0","method":"tools/call","id":19,
 "params":{"name":"get_best_time_to_post",
           "arguments":{"platform":"twitter","timezone":"Europe/Berlin","topN":5}}}

get_channel_analytics

Aggregate performance for one connected channel, or for every channel at once. Returns impressions, reach, likes, comments and engagement rate for the period, the change against the preceding period of the same length, and the follower series. Omit platform for a team-wide total. Use get_post_metrics for a single post and get_best_time_to_post for scheduling.

Arguments

platform Social platform: twitter, instagram, linkedin, threads, or tiktok.

channelName Which connected account, when the platform has more than one.

period Window to report on: 7d, 30d, 90d or all (default 30d).

Returns

An object with scope, period, totals, vsPrevious, coverage, dataThrough and followers, which carries trackingSince, current, change and the series.

Example

{"jsonrpc":"2.0","method":"tools/call","id":34,
 "params":{"name":"get_channel_analytics",
           "arguments":{"platform":"linkedin","period":"30d"}}}

search_tools

Search the MCP tool catalog by free-text query, category, or intent. Returns categories, requiresScope, one-line descriptions, and the use-case tags that matched. Free for all plans (discovery surface).

Arguments

All optional. Call with no arguments to list every available tool.

query Free-text search across tool names, descriptions, and use-case tags.

category Filter to one category: posts, accounts, analytics, brand, teams, discovery, other.

Returns

An object with totalTools, matchCount, categories: [string[]], and tools: [{name, category, requiresScope, description, useCases, matchedOn: [name|category|description|use_case]}]. Includes hint when no match or no filter.

Example

{"jsonrpc":"2.0","method":"tools/call","id":20,
 "params":{"name":"search_tools",
           "arguments":{"query":"why did my post fail"}}}

get_plan

Plan identity and billing dates: tier, renewal date, trial end date, and whether the subscription is set to cancel at the period end. For quotas and usage, call get_plan_limits instead.

Arguments

No arguments.

Returns

An object with tier, tierDisplayName, isPaid, isTrial, gated, subscriptionStatus, renewsAt, trialEndsAt, cancelAtPeriodEnd, currency and upgradeUrl.

Example

{"jsonrpc":"2.0","method":"tools/call","id":21,
 "params":{"name":"get_plan",
           "arguments":{}}}

upload_asset

Inline base64 upload of an image or video to the asset library. Reliable only for very small files, around 8KB or less: a larger payload silently truncates in the tool arguments and stores a corrupt file. Use request_asset_upload for anything bigger.

Arguments

filename File name including its extension, up to 255 characters.

contentType MIME type of the file, from the allowed image and video list.

base64 The file bytes, base64 encoded. Keep this tiny, and read the warning above first.

Returns

An object with assetId, url, sizeBytes and mimeType. Pass the url to create_post_draft as mediaUrls.

Example

{"jsonrpc":"2.0","method":"tools/call","id":22,
 "params":{"name":"upload_asset",
           "arguments":{"filename":"logo.png","contentType":"image/png","base64":"iVBORw0KGgo..."}}}

request_asset_upload

The recommended upload path, for images and video of any size. Two steps: call this tool to get a pre-signed URL and a ready-made curl command, then PUT the file bytes to that URL. The PUT response carries the final asset URL.

Arguments

filename File name including its extension, up to 255 characters.

contentType MIME type of the file, from the allowed image and video list.

sizeBytes Exact size of the file in bytes, used to sign the upload.

Returns

An object with uploadId, uploadUrl, uploadToken, expiresInSeconds and instructions holding the exact PUT command.

Example

{"jsonrpc":"2.0","method":"tools/call","id":23,
 "params":{"name":"request_asset_upload",
           "arguments":{"filename":"clip.mp4","contentType":"video/mp4","sizeBytes":4194304}}}

get_latest_blog_post

Whether the team has a WordPress blog connected, plus a snippet of the most recent post. Read-only and free of credit cost. Call it before create_blog_plan or test_blog_connection to see what is already wired up.

Arguments

No arguments.

Returns

An object with blogConnected, an integration summary carrying no secrets, and latestPost with its title, snippet, status and published URL.

Example

{"jsonrpc":"2.0","method":"tools/call","id":24,
 "params":{"name":"get_latest_blog_post",
           "arguments":{}}}

list_blog_plans

List the blog plans belonging to the team, newest first, with status, per-status topic counts, credit reservations and a dashboard link. Read-only and free of credit cost.

Arguments

limit Maximum plans to return (1-50, default 20).

status Filter by status: generating, active, paused, completed, cancelled or failed.

Returns

An object with plans and total. Each plan carries its id, status, topic counts and dashboard link.

Example

{"jsonrpc":"2.0","method":"tools/call","id":25,
 "params":{"name":"list_blog_plans",
           "arguments":{"status":"active","limit":10}}}

create_blog_plan Paid plan

Create a blog content plan for a brand profile. Topics generate asynchronously, so the plan returns immediately in status generating: poll list_blog_plans for progress. On Business and Teams plans the posts are also generated and published to a connected WordPress blog.

Arguments

startDate First day the plan covers, as YYYY-MM-DD.

planDays How many days the plan covers (1-30, default 7).

brandProfileId Brand profile to plan for. Defaults to the active profile on the team.

integrationId Which connected blog to use, when the team has more than one.

autoPublish Publish the generated posts to the connected blog automatically (Business and Teams).

Returns

An object with planId, status, startDate, planDays, brandProfileId, integrationId, topicCount and dashboardUrl.

Example

{"jsonrpc":"2.0","method":"tools/call","id":26,
 "params":{"name":"create_blog_plan",
           "arguments":{"startDate":"2026-10-01","planDays":14,"autoPublish":true}}}

test_blog_connection Paid plan

Check that the connected WordPress blog answers and that its token is still valid, and record the result on the integration. Returns the plugin version and what it can do.

Arguments

integrationId Which connected blog to use, when the team has more than one.

Returns

An object with success, message, version, capabilities, integrationId and the updated status.

Example

{"jsonrpc":"2.0","method":"tools/call","id":27,
 "params":{"name":"test_blog_connection",
           "arguments":{}}}

list_mini_sites

List the bio pages belonging to the selected team, with their public URL, publish state and setup progress. Start here: every other bio-page tool takes the siteId this returns, and can omit it when the team has exactly one site.

Arguments

No arguments.

Returns

An object with sites, each carrying id, slug, name, published, url, views and setup progress.

Example

{"jsonrpc":"2.0","method":"tools/call","id":28,
 "params":{"name":"list_mini_sites",
           "arguments":{}}}

get_mini_site

Read one bio page in full: profile header, social icons, every content block, SEO metadata, theme and auto-pin settings. Long text is cut to a 300-character preview, and credentials are never returned.

Arguments

siteId Which bio page to act on. Omit it when the team has exactly one.

Returns

An object with id, slug, published, url, header, socials, meta, theme, autoPin, campaign and the blocks array.

Example

{"jsonrpc":"2.0","method":"tools/call","id":29,
 "params":{"name":"get_mini_site",
           "arguments":{}}}

get_mini_site_analytics

How a bio page performs: views, clicks, best links, visitor source, device and country, and AI-crawler reads, plus which published posts drove clicks. Every figure except the attribution rows is an all-time counter rather than a windowed one, so say so when reporting numbers.

Arguments

siteId Which bio page to act on. Omit it when the team has exactly one.

attributionDays Window in days for post-to-click attribution (1-90, default 30).

Returns

An object with viewsAllTime, clicksAllTime, topLinks, bySource, byDevice, byCountry, ai, attribution and attributionWindowDays.

Example

{"jsonrpc":"2.0","method":"tools/call","id":30,
 "params":{"name":"get_mini_site_analytics",
           "arguments":{"attributionDays":30}}}

add_mini_site_block

Add one block to a bio page: link, featured, product, event, pre-save, podcast episode, booking, opening hours, header, text, image or gallery. Required fields differ by type. This changes a publicly visible page straight away.

Arguments

siteId Which bio page to act on. Omit it when the team has exactly one.

type Type of block to add, for example link, product, event, hours or gallery.

... Plus the fields for that block type, for example url, title, price or startDate.

Returns

An object with the stored block, the new blockCount, and alreadyExisted when the same block was already present.

Example

{"jsonrpc":"2.0","method":"tools/call","id":31,
 "params":{"name":"add_mini_site_block",
           "arguments":{"type":"link","url":"https://example.com","title":"New single"}}}

update_mini_site_block

Patch one existing block: a link title or URL, a product price, an event date, opening hours, or the display order. Only the fields you pass change, and the block type cannot be changed. The response returns the block as stored, so any value the server rejected is visible.

Arguments

siteId Which bio page to act on. Omit it when the team has exactly one.

blockId Id of the block, as returned by get_mini_site.

... Plus the fields for that block type, for example url, title, price or startDate.

Returns

An object with the block as stored, the list of fields updated, and any fields ignored.

Example

{"jsonrpc":"2.0","method":"tools/call","id":32,
 "params":{"name":"update_mini_site_block",
           "arguments":{"blockId":"blk_7f3a","title":"Updated title"}}}

remove_mini_site_block

Remove one block from a bio page by its blockId, for example a finished tour date or a retired product link. Call get_mini_site first to find the id. This changes a publicly visible page straight away.

Arguments

siteId Which bio page to act on. Omit it when the team has exactly one.

blockId Id of the block, as returned by get_mini_site.

Returns

An object with removed, the blockId, and how many blocks remain.

Example

{"jsonrpc":"2.0","method":"tools/call","id":33,
 "params":{"name":"remove_mini_site_block",
           "arguments":{"blockId":"blk_7f3a"}}}

MCP Resources

Resources are read-only context the client can fetch via the MCP resources/read method. Claude pulls them at conversation start so it has account/team/brand context without you re-asking each session.

postnext://account/summary

Account email and handle (so Claude can confirm which account it's operating on), plan, AI credits used / limit, draft count, scheduled count, connected channel count. Counts capped at 100 each for fast load.

postnext://channels/connected

Same shape as list_connected_accounts result; exposed as a resource so Claude pulls it once at conversation start (no tool-call round-trip).

postnext://brand-profiles/active

The user's active brand profile (team default, falling back to first own profile). Returns only LLM-relevant fields: bio, expertiseAreas, personalityTraits, brandVoice, mainThemes, audienceSize, preferredHashtags.

postnext://teams/current

Current team metadata (teamId, teamName) plus totalTeamsAvailable count. Pair with list_teams + set_current_team to switch.

Named workflows

Slash-menu shortcuts that orchestrate multiple tools. Pick one and let your AI assistant walk through a multi-step task with confirmation before mutating anything.

/weekly-plan

Read brand profile, connected channels and queued posts, then propose 5-10 drafts spread Monday to Friday.

/draft-thread

Write a 5-10 post Twitter or Threads thread on a topic or URL you supply, in your brand voice.

/audit-queue

Walk the next 7 days of scheduled posts and flag duplicates, platform overload, and gaps.

/channel-sweep

Compare connected channels against the supported set and suggest which to connect or refresh.

Discovery and OAuth endpoints

Standards-compliant metadata so any MCP client can auto-configure.

  • GET /.well-known/oauth-protected-resource/api — RFC 9728
  • GET /.well-known/oauth-authorization-server — RFC 8414
  • GET /oauth/.well-known/openid-configuration — OIDC
  • POST /oauth/reg — Dynamic Client Registration (RFC 7591)
  • GET /oauth/auth — Authorize (PKCE-S256 required)
  • POST /oauth/token — Token exchange

Open source

Paste-ready recipes and a developer-facing reference live in our public docs repo. MIT-licensed; pull requests welcome. github.com/postnextio/postnext-mcp

Run your social channels from any AI assistant

Plan, draft, schedule, and audit posts across 7 platforms by chatting with Claude, ChatGPT, or Cursor. One secure connection, every PostNext feature.

×