Tool reference

Content tools

All 14 content MCP tools with input shape, response shape, and example calls.

Fourteen tools drive the social content calendar — scheduling, recurring schedules, human review, campaigns/labels, and AI-assisted captions/hashtags.

All endpoints follow the pattern POST https://mcp.vlozi.app/tools/content.<name> with Authorization: Bearer ls_xxx. All responses use this envelope:

{ "data": <payload>, "error": null }   // success
{ "data": null,      "error": "..." }  // failure (with HTTP 4xx/5xx)

NOTE

Supported platforms: twitter, instagram, linkedin, facebook. A slot's status moves through draft → pending_review → scheduled → publishing → published (or partially_failed/failed) — approve_slot/reject_slot are the human-review gate between draft and scheduled; there is no separate "publish now" tool, since going live is always either immediate auto-schedule or the review gate.

Calendar

content.get_calendar

Get the content calendar for a date range.

Scope: content:slots.read

Input: { from: string, to: string, status?: string } (from/to required ISO datetimes)

Response: { slots: ContentSlot[] }, newest-scheduled first


content.get_slot

Get one slot with its per-platform delivery targets.

Scope: content:slots.read

Input: { id: string } (required)

Response: { slot: ContentSlot, targets: SlotTarget[] } — each target: { id, socialConnectionId, platformCaption, publishStatus, externalPostId, externalPostUrl, errorMessage, retryCount }

NOTE

Returns 404 if the slot doesn't exist or belongs to a different tenant.


content.list_connections

List connected social accounts.

Scope: content:connections.read

Input: none

Response: { connections: { id, platform, platformUsername, displayName, status }[] }status is active | expired | revoked | error

NOTE

Connections are set up through the dashboard's OAuth connect flow — no MCP tool creates one, only lists them.


content.list_campaigns

List content campaigns (groupings for related posts, e.g. a product launch).

Scope: content:campaigns.read

Input: none

Response: { campaigns: { id, name, color, status }[] }status is active | completed | archived


content.list_labels

List content labels.

Scope: content:labels.read

Input: none

Response: { labels: { id, name, color }[] }

Scheduling

content.schedule_content

Schedule a social post across one or more connections.

Scope: content:slots.write

Input:

Field Type Notes
caption string (required)
contentType "text" | "image" | "video" | "carousel" | "story" | "link" (required)
connectionIds string[] (required) 1–50 ids, each validated to belong to your workspace
scheduledAt string ISO datetime with offset; defaults to now + 1h
timezone string Default UTC
mediaIds string[] Max 10
linkUrl string
campaignId string
autoApprove boolean Default false

Response: { slotId: string, status: "scheduled" | "draft" }

IMPORTANT

autoApprove: true skips human review entirely — the slot lands directly in scheduled and a publish alarm is armed for scheduledAt. autoApprove: false (the default) leaves it as draft, awaiting approve_slot/reject_slot. Returns 400 if any connectionIds entry isn't a real connection in your workspace. If auto-approving and arming the schedule fails, the slot is demoted back to draft rather than left in a broken state — you'll get 500 with "Slot created but scheduling alarm failed — left as draft."

curl -X POST https://mcp.vlozi.app/tools/content.schedule_content \
  -H "Authorization: Bearer $VLOZI_API_KEY" \
  -d '{
    "caption": "We just shipped OAuth login for MCP clients.",
    "contentType": "text",
    "connectionIds": ["conn_xxx"],
    "scheduledAt": "2026-08-25T09:00:00+00:00",
    "autoApprove": true
  }'

content.create_recurring_schedule

Create a repeating template that spawns a new slot on every cron fire — unlike schedule_content, which creates exactly one slot immediately.

Scope: content:recurring.write

Input:

Field Type Notes
name string (required)
cronExpression string (required) Standard 5-field cron
timezone string (required) IANA
templateCaption string (required)
templateMediaIds string[] Max 10
targetConnectionIds string[] (required) 1–50 ids
autoSchedule boolean Default false — mirrors schedule_content's autoApprove for each generated slot

Response: { scheduleId: string }

NOTE

This creates the recurring template only — no slot exists yet until the cron actually fires and generates one from templateCaption/templateMediaIds/targetConnectionIds.


content.delete_slot

Delete a scheduled or already-published slot.

Scope: content:slots.write

Input: { id: string } (required)

Response: { slotId: string, deleted: true, platformWarnings: { target, platform, reason? }[] }

WARNING

Returns 409 if the slot is currently publishing — wait for it to finish first. If the slot was published, this also attempts to retract the live post on each platform; platformWarnings reports per-platform failures (a missing/expired connection, or the platform's API rejecting the delete). Not every platform supports deletion — Instagram's Graph API has no post-deletion endpoint at all (always warns), and LinkedIn has no delete support implemented. These warnings do not block deletion — the slot is removed from Vlozi's calendar regardless, so a "deleted" slot can still be live on Instagram/LinkedIn with only a warning to show for it.

Review

content.approve_slot

Approve a slot pending review, moving it to scheduled.

Scope: content:slots.approve

Input: { id: string, note?: string }

Response: { slotId: string, status: "scheduled" }

NOTE

Only works on a slot currently pending_review409 otherwise. Requires the slot to already have a scheduledAt set — 422 if not. This is the one human-review gate in the namespace; there's no separate "publish now" tool.


content.reject_slot

Reject a slot pending review, returning it to draft so it can be edited and resubmitted.

Scope: content:slots.approve

Input: { id: string, note: string } (note required — the rejection reason)

Response: { slotId: string, status: "draft" }

NOTE

Only works on a slot currently pending_review409 otherwise.

Campaigns & labels

content.create_campaign

Create a content campaign.

Scope: content:campaigns.write

Input: { name: string, color?: string, startDate?: string, endDate?: string } (name 1–200 chars; color hex, max 32 chars)

Response: { campaign: { id, name, status: "active" } }


content.create_label

Create a content label.

Scope: content:labels.write

Input: { name: string, color?: string } (name 1–100 chars; color hex, max 32 chars)

Response: { label: { id, name, color } }

NOTE

Returns 409 if a label with this name already exists (unique per workspace).

AI

content.generate_caption

AI-write a caption from a brief, tuned for a specific platform's length/style conventions.

Scope: content:slots.write

Input: { brief: string, platform?: "twitter" | "instagram" | "linkedin" | "facebook", tone?: string } (brief 1–2000 chars; tone max 100 chars)

Response: { caption: string, creditsCharged: number, model: string }

IMPORTANT

Charges a flat 5-credit fee, refunded automatically if generation fails. Returns 503 if no AI model key is configured, 402 if you're out of credits, 403 if the plan is inactive. Passing platform: "twitter" steers the model toward a strict under-280-character result.

curl -X POST https://mcp.vlozi.app/tools/content.generate_caption \
  -H "Authorization: Bearer $VLOZI_API_KEY" \
  -d '{"brief": "Announcing OAuth login support for MCP clients", "platform": "twitter", "tone": "excited"}'

content.suggest_hashtags

AI-suggest hashtags for a topic.

Scope: content:slots.write

Input: { topic: string, count?: number } (topic 1–2000 chars; count 1–15, default 8)

Response: { hashtags: string[], creditsCharged: number, model: string } — each entry prefixed with #, deduplicated

IMPORTANT

Charges a flat 3-credit fee, refunded automatically if generation fails. Same 503/402/403 error conditions as generate_caption.

MCP · Tool referenceEdit on GitHub