AI assistant connector (MCP)

Let an AI assistant plan, draft and report in ViralDashboard for you. The connector speaks the Model Context Protocol and runs every action through the same public API, with the same permissions, plan limits and credits.

Beta. The connector is enabled workspace by workspace while it is in beta. If a correctly configured key gets 403 “not enabled for this workspace yet”, write to [email protected] to join.

What it is

An MCP server is a single HTTPS endpoint an AI client can call to discover and use tools (actions), resources (read-only context) and prompts (ready-made workflows). ViralDashboard's server never works around the API: each tool call is one or more public API requests made as your key, so it can only do what that key could do over the API.

Endpointhttps://viraldashboard.io/mcp
MethodPOST only. GET and DELETE answer 405.
ProtocolMCP 2026-07-28 (stateless, no session). Clients still on the 2025-11-25 handshake are served too.
AuthenticationAuthorization: Bearer vd_live_… (or vd_test_…)

Who can use it

  • Workspaces on the Creator, Pro, Business, Agency and White-Label plans, while admitted to the beta.
  • You need an API key. Mint one in Settings → API & Webhooks → API Keys, and pick the scopes for the tools you want (table below). The secret is shown once.
  • The key acts as the person who minted it: it sees only the brands that person can access.

Connecting

Point any MCP client that supports the Streamable HTTP transport at the endpoint and send your key as a bearer token. A typical client configuration:

{
  "mcpServers": {
    "viraldashboard": {
      "type": "http",
      "url": "https://viraldashboard.io/mcp",
      "headers": { "Authorization": "Bearer vd_live_your_key_here" }
    }
  }
}

To check a key by hand, ask the server to describe itself:

curl https://viraldashboard.io/mcp \
  -H "Authorization: Bearer $VD_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -H "Mcp-Method: server/discover" \
  -d '{"jsonrpc":"2.0","id":1,"method":"server/discover","params":{"_meta":{
        "io.modelcontextprotocol/protocolVersion":"2026-07-28",
        "io.modelcontextprotocol/clientCapabilities":{}}}}'

Every request carries MCP-Protocol-Version and Mcp-Method, plus Mcp-Name on tools/call, resources/read and prompts/get; a header that disagrees with the body is rejected with 400. MCP clients set these for you.

Coming soon: one-click OAuth connectors for Claude and ChatGPT (sign in with ViralDashboard instead of pasting a key), and listings in their connector directories. Until then, connect with a key as above.

Tools and the scopes they need

A tool is listed only when the key holds all of its scopes. A key without them simply doesn't see the tool; mint a key with the scope to add it.

ToolScopesKindWhat it does
vd_list_workspace brands:read
accounts:read
Read List brands and connected accounts
vd_get_calendar posts:read Read Get the content calendar
vd_get_post posts:read Read Get one post
vd_get_performance analytics:read Read Get analytics performance
vd_list_inbox inbox:read Read List inbox conversations
vd_get_conversation inbox:read Read Get an inbox conversation
vd_list_media media:read Read List the media library
vd_list_feed_articles feeds:read Read List RSS feeds and their latest articles
vd_list_content_plans content:read Read List content plans
vd_list_reports reports:read Read List reports and schedules
vd_create_post posts:write Write Create a post (draft, schedule or publish now)
vd_update_post posts:write Write Edit a draft or scheduled post
vd_submit_post_for_approval posts:write Write Submit a draft for approval
vd_import_media_from_url media:write Write Import an image into the media library from a URL
vd_write_caption ai:write Write Write captions in the brand voice
vd_generate_image ai:write Write Generate an image into the media library
vd_reply_to_conversation inbox:write
inbox:read
Write Reply to an inbox conversation
vd_triage_conversation inbox:write Write Triage an inbox conversation
vd_schedule_plan_item content:write Write Turn a content-plan item into a post
vd_create_report reports:write Write Create an analytics report
vd_export_report reports:write Write Export a report
vd_refresh_account accounts:write Write Refresh a social account's login
vd_get_connect_link accounts:write Write Get a link to connect a social account
vd_get_job_status Read Check background work
vd_delete_post posts:write Destructive Delete a post from ViralDashboard
vd_disconnect_account accounts:write Destructive Disconnect a social account from a brand
vd_delete_webhook webhooks:write Destructive Delete a webhook endpoint
vd_hide_comment inbox:write
inbox:read
Destructive Hide a comment on the platform
vd_unhide_comment inbox:write Write Unhide a comment on the platform
vd_moderation_rules inbox:read Write Inbox moderation rules: list, audit, create (test mode)
vd_search_mentions listening:read Read Search social-listening mentions
vd_manage_bio_page linkinbio:write
linkinbio:read
Write Update a link-in-bio page
vd_automation_rules automation:read Destructive Posting automation rules: list, create, edit, pause, delete, run history
vd_evergreen automation:read Destructive Evergreen queue: recycle posts on a schedule
vd_bulk_schedule automation:read Write Bulk schedule posts from a CSV (preview first)

Resources

Read-only context an assistant can load before it acts. Read with resources/read.

URIScopeContents
vd://brands/{brand_id}/voice brands:read How a brand sounds: industry, target audience, content topics, values, products and services, and its voice profile (at most 2000 characters). This is the context ViralDashboard's own AI writes with; use it to keep anything you draft on-voice. Brand ids come from vd_list_workspace.
vd://brands/{brand_id}/kit brands:read A brand's visual identity from its brand kit: colours as {name, hex}, fonts, and logo URLs. `configured` is false when the brand has no kit yet. Brand ids come from vd_list_workspace.
vd://account/plan account:read The workspace's plan and usage, read-only: plans held, enabled features, usage and remaining room for every plan limit (including posts this month), the AI credit balance, AI capacity pools, and X posts used vs. included. Check it before suggesting work that needs a feature or uses credits. It can't be changed from here: never offer to upgrade or buy; an owner does that in Billing.
vd://capabilities any key What ViralDashboard can do on each social platform right now: connect, publish (post and media types), analytics, inbox read, comment and DM replies, private replies, hiding and deleting comments, and listening. Every unsupported cell carries the reason. Only plan or propose actions a platform supports, and tell the user the reason when it doesn't.

Prompts

PromptArgumentsWhat it does
weekly_plan brand_id (required)
week_start
goals
Plans a week of on-brand posts for one brand from its voice, kit and recent performance, only in formats each connected platform supports, and saves them as drafts. Nothing is published.
client_report brand_id (required)
period (required)
format
Writes a client-ready performance summary for one brand and period: totals compared with the previous period, insights, top posts and a short narrative. Can also export a formatted report file.
inbox_triage brand_id (required)
limit
Goes through a brand's open inbox conversations: classifies intent and urgency, proposes status, assignee, tags and priority, and drafts replies in brand voice. Replies are only sent after the user confirms each one, and never where the platform can't take a reply.

The confirm step

Anything that reaches the outside world or can't be undone — publishing now, replying to someone, hiding a comment, deleting or disconnecting — is never done on the first call. The first call runs every check, changes nothing, and returns:

{
  "status": "confirmation_required",
  "preview": { "…": "what will happen" },
  "confirm_token": "…",
  "expires_in_seconds": 300
}

The assistant shows the preview to you, and only if you agree calls the tool again with the same arguments plus confirm_token. A token works once, for those exact arguments, for the key that asked for it, and expires after 5 minutes. Anything else returns confirmation_invalid. Drafts never need confirming.

Test keys are dry runs

With a vd_test_… key, reads return live data and every write is a dry run: it passes through every scope, brand, plan and validation check and then stops, returning "status": "dry_run" with what would have happened. Nothing is created, sent or charged. Use a test key to try a workflow safely, and a live key to do it.

Retries are safe

Every write carries an idempotency key. If the assistant repeats a call with identical arguments (after a dropped connection, say), it gets the original result back instead of a second post or a second charge. To do the same thing twice on purpose, pass a new idempotency_key argument.

Errors

Connection-level

These come back as an HTTP status with a JSON-RPC error, before any tool runs:

StatusMeansFix
401Missing, invalid, revoked or expired key (with a WWW-Authenticate header).Check the key, or mint a new one.
403The workspace isn't admitted to the beta yet, its plan doesn't include the connector, or a browser Origin isn't allowed.Ask to join the beta, or an owner can upgrade in Billing.
404The connector is switched off.Try again later.
400Unsupported protocol version, or headers that don't match the body.Update the client.
429Too many requests (see rate limits).Wait for Retry-After seconds.
503The ViralDashboard API is switched off, so tools can't run.Try again later.

Tool errors

A tool that can't do what was asked returns a normal result with isError: true. Its structuredContent.error carries the public API's code, type and message unchanged, plus a remediation written for the assistant and whether a retryable retry can help:

{
  "isError": true,
  "structuredContent": { "error": {
    "code": "limit_reached", "type": "invalid_request_error", "http_status": 402,
    "message": "…", "remediation": "…", "retryable": false, "details": { }
  } }
}

A resource that can't be read returns a JSON-RPC error with the same object in data.error. A resource that doesn't exist, or that you can't access, is -32602.

Codes

CodeWhat the assistant is told to doRetry?
unauthorized Reconnect the connector, or check the API key. No
insufficient_scope This key is missing a scope this tool needs. Mint a key with that scope in Settings → API keys. No
test_mode_write_forbidden Test keys are read-only. Use a live key to write. No
brand_forbidden You don't have access to this brand. Call vd_list_workspace for the brands you can use. No
forbidden Not allowed on this resource (for example, the conversation is not in this brand). No
feature_not_available The workspace plan doesn't include this feature. An owner can upgrade in Billing; don't offer to do it here. No
limit_reached A plan limit is reached. Free up capacity, wait for the reset (posts reset monthly), or an owner can upgrade in Billing. No
insufficient_credits Not enough AI credits. An owner can top up in Billing. No
storage_limit_exceeded Media storage is full. Delete media in the app or upgrade storage. No
payload_too_large The file is over the size limit (10 MB images, 50 MB video). No
unsupported_media_type Use JPEG, PNG, GIF or WebP images, or MP4/MOV video. No
invalid_media_url The URL must be public HTTPS and reachable; private and internal addresses are blocked. No
invalid_feed_url The URL must be public HTTPS and reachable; private and internal addresses are blocked. No
invalid_webhook_url The URL must be public HTTPS and reachable; private and internal addresses are blocked. No
invalid_site_url The URL must be public HTTPS and reachable; private and internal addresses are blocked. No
invalid_account Pick accounts connected to this brand (see vd_list_workspace). No
invalid_credentials Connect this platform in the app (Settings → Social accounts). No
oauth_required Connect this platform in the app (Settings → Social accounts). No
not_oauth_platform This platform is connected with credentials in the app, not with a link. No
interactive_setup_required This platform needs interactive setup in the app (Settings → Social accounts). No
platform_unavailable This platform isn't open for connection right now. No
authorize_failed The platform refused to start authorization. Try again later. Yes
reconnect_required The account's login expired. The user must reconnect it (vd_get_connect_link). No
platform_capability_unavailable The platform can't do this right now; the message says why. Don't retry. No
moderation_paused Automation is switched off for this brand, so comments can't be hidden. A person can switch it back on in the app (Automation → Auto-Replies); don't retry until then. No
platform_error The platform refused the action; the message is its reason. Fix what it says (often a missing permission: reconnect the account), then try once more. No
idempotency_conflict The same request is still running. Wait a few seconds and retry with the same arguments. Yes
idempotency_error This idempotency_key was already used with different arguments. Use a new key. No
rate_limited Rate limit reached. Retry after the number of seconds in retry_after. Yes
invalid_request Fix the fields listed in details.errors and call again. No
not_found It doesn't exist or isn't visible to you. No
post_not_editable Published posts can't be edited. Create a new post instead. No
post_not_draft Only drafts can be submitted for approval. No
post_not_pending Only posts pending approval can be approved or rejected. No
generation_failed The AI returned nothing and the credits were refunded. To try again, call with a new idempotency_key (an identical call replays this failure). No
evergreen_max_reached The entry has republished as many times as max_republishes allows. Raise max_republishes (action "update"), then resume it. No
confirmation_invalid Call the tool again without confirm_token to get a fresh preview, and ask the user again. No
handle_expired That job handle is unknown or expired. Start the action again if needed. No
internal_error Something failed on our side and it has been logged. Retry once, then stop. Yes

The API's own codes are described in Errors.

Rate limits

  • The connector accepts up to 120 requests a minute per key. Over that, it answers 429 with Retry-After.
  • Each tool call also counts against the key's hourly API rate limit, once for every API request it makes (a tool that lists brands and their accounts makes one request per brand). A tool that hits that limit returns rate_limited with retry_after.
  • AI tools spend the workspace's AI credits, exactly as the API does.

Support

Questions, beta access or a bug: [email protected].