Skip to content
Reading with an AI assistant?View as MarkdownOpen in ClaudeOpen in ChatGPT

Guides

Connect an AI agent to social media (MCP)

Connect an AI agent to social media through SkedCast's remote MCP (Model Context Protocol) server, so it can read across your workspace (posts, clients, accounts, analytics, reports, best-times, library, and webhooks) and act on it — compose and edit posts, reschedule / cancel / retry deliveries, import media, and manage webhooks — with your permission, over a single OAuth-protected endpoint.

Browse docs

6 min read

Connect an AI agent to social media via MCP: the endpoint#

PropertyValue
EndpointPOST https://api.skedcast.com/mcp
TransportStreamable HTTP
AuthOAuth 2.1 bearer token (audience-checked)
Discovery/.well-known/oauth-protected-resource

Add the server to your AI client#

Point your MCP-capable client (Claude Desktop, IDEs, agents) at the endpoint below. The client runs the OAuth flow for you — it discovers the authorization server from the protected-resource metadata, registers itself (DCR), and opens a browser for you to sign in and consent. No manual app setup.

json
{
  "mcpServers": {
    "skedcast": {
      "url": "https://api.skedcast.com/mcp"
    }
  }
}
Example MCP client config.

Available tools#

ToolScopeTypeDescription
list_scheduled_postsposts.readreadList the workspace's posts (queue, drafts, published) newest-first, with optional status / client / platform filters and free-text search (q) over captions, per-platform overrides, client names and account handles.
list_post_targetsposts.readreadList individual post DESTINATIONS (one row per platform account) with optional status / client / account / platform / free-text filters and a SCHEDULE-time window — the tool for "what publishes on this date". Carries total and totalPosts, so a caller can tell a full page from a complete set.
get_postposts.readreadGet one post with its per-platform variants and fan-out targets.
list_clientsclients.readreadList the workspace's client groups (brands / influencers).
list_accountsaccounts.readreadList connected social accounts, optionally filtered by client or platform.
get_analytics_overviewanalytics.readreadReach / impressions / engagement plus a per-platform rollup over a date window.
get_post_analyticsanalytics.readreadPer-post performance (complements get_analytics_overview): one post’s lifetime per-target breakdown by postId, or a keyset page of per-post rows with filters.
get_account_analyticsanalytics.readreadOne channel’s totals and daily series, plus the two things no other tool carries: profile-level activity (profile views, link taps, video plays) and follower demographics.
list_library_assetsmedia.readreadList content-library (DAM) assets with optional kind / folder / label / client / status / search filters. Filter status: "transcoded" for assets that are actually publishable; every row also carries status, publishable and ready.
get_capabilitiesposts.readreadThe per-platform composing rulebook: caption and hashtag limits, media rules per kind (counts, formats, file-size ceiling, duration bounds, aspect ratios), post types, native-scheduling window, default cadence, first-comment support, and the variants[].overrides keys each platform requires or accepts. Read it before composing instead of discovering a limit by failing a publish.
get_agencyagency.readreadThe current workspace profile — name, plan, app mode, settings, and the caller’s role.
list_reportsreports.readreadList the workspace's saved analytics report definitions.
get_best_timesbesttimes.readreadWorker-derived best posting times (strongest-first), optionally by client / platform.
list_approvalsapprovals.readreadList the workspace's approval queue (pending and decided requests), newest-first, with optional status / post filters.
get_posting_limitsaccounts.readreadAnti-ban posting limits (cadence): one account by socialAccountId, or every active channel plus the tenant bypass flag when omitted.
get_quotaaccounts.readreadAdaptive quota pool: your scarce-bucket budget (guaranteed slice, used, burst headroom, tomorrow’s guarantee tonight, reset clock) — read before planning a batch.
list_campaignscampaigns.readreadList the workspace's campaigns (named post groupings), optionally filtered by client / status.
decide_approvalapprovals.decidewrite ⚠Approve, reject, or request changes on a pending approval request (approve releases the gated post for publishing). A write action — confirm with the user before calling.
validate_postposts.composereadDry-run a compose request and get the per-platform verdict WITHOUT writing anything — same arguments as create_post, no post row and no draft. Returns { valid, platforms[], estimatedCostUsd }. Does not run cadence or quota admission, so valid: true means the shape is acceptable, not that a publish cannot later be deferred.
revise_postposts.composewrite ⚠Change the CONTENT of an already-scheduled post — caption, media, cover, alt text, per-platform overrides — without disturbing its destinations. Send only what you are changing. Refuses, naming them, when a destination has already published or is about to. An edit to an APPROVED post returns it to review. A write action — confirm with the user before calling.
create_postposts.composewrite ⚠Compose a post and fan it out across the selected accounts (or save it as a draft). Retry-safe: retrying with identical arguments replays the original result instead of creating a duplicate. Note: two publish-now calls with byte-identical content and targets are treated as the same post and coalesced permanently — to intentionally publish the same content twice, vary the content or use distinct scheduled times. For platform-specific settings (e.g. YouTube privacy, TikTok privacy level, Pinterest board, Telegram chat), set variants[].overrides. That same object carries firstComment: a reply posted automatically once the destination goes live, so a "link in the comments" post needs no manual follow-up. Supported on X, LinkedIn, YouTube, Instagram, Facebook, Threads, Telegram and Bluesky (not TikTok or Pinterest); spell it exactly firstComment. Overrides are free-form — an unrecognised key is accepted and silently ignored — and the comment is best-effort: if it fails the post still publishes and nothing is reported, so confirm on the published post. A write action — confirm with the user before calling.
create_posts_bulkposts.composewrite ⚠Create up to 50 posts in one call. Each item is exactly the arguments of create_post, so a bulk item carries every override a single post does (per-platform caption, title, cover, per-asset alt text, first comment, per-platform settings). Items are created one after another, each on its own: one failing never rolls back the others, and the result lists every item in order with its post id or its error. Retry-safe: retrying with identical arguments creates nothing twice. Pass validateOnly:true to check every item without writing anything. It counts one request-budget unit per item. This creates real outbound content — confirm with the user before calling. Requires the posts.compose scope.
update_postposts.composewrite ⚠Replace a draft post in place — its content, media, targets, and schedule. Only draft posts can be updated, and this never publishes (use publish_draft for that). Platform-specific settings live in variants[].overrides, same as create_post, including firstComment. A write action — confirm with the user before calling.
publish_draftposts.composewrite ⚠Publish or schedule an existing DRAFT post in place — same arguments as update_post plus the draft id; schedule decides now or later. Runs the same checks as create_post (platform validation, approval policy, quota, pacing); a client that requires approval gets the post submitted for review instead. The post keeps its id. This puts real content on connected accounts — confirm with the user before calling.
import_mediamedia.managewrite ⚠Ingest an external image / video into the content library by URL — the file must already be reachable at a public URL. For bytes you already hold (an image you just rendered, or a local file) use upload_media instead. A write action — confirm with the user before calling.
upload_mediamedia.managewrite ⚠Upload a LOCAL image / video into the content library and get back a media id for create_post. Sends the file inline (≤18 MiB) or returns a presigned URL for larger files. A write action — confirm with the user before calling.
reschedule_postposts.composewrite ⚠Move a pending post target to a new time (absolute scheduledAt or relative shiftMinutes). A write action — confirm with the user before calling.
bulk_post_target_actionposts.composewrite ⚠Reschedule, retry or cancel up to 5000 post targets in one call — the batch form of reschedule_post / retry_post / cancel_post. Returns { jobId, accepted, skipped, skippedReasons? }; a skipped target is reported, never silently dropped. A write action — confirm with the user before calling.
cancel_postposts.composewrite ⚠Cancel a still-pending post target before it publishes. A write action — confirm with the user before calling.
retry_postposts.composewrite ⚠Re-queue a failed or rate-limited post target so it publishes again. A write action — confirm with the user before calling.
set_post_recycleposts.composewrite ⚠Set, update, or disable a post's evergreen recycle settings (interval / times / end date / max recycles). A write action — confirm with the user before calling.
shift_campaigncampaigns.managewrite ⚠Move a whole campaign's pending schedule by a relative number of minutes. A write action — confirm with the user before calling.
list_webhookswebhooks.readreadList the workspace's outbound webhook endpoints (url, subscribed events, active flag; secret masked).
create_webhookwebhooks.managewrite ⚠Register an outbound webhook endpoint for HMAC-signed event deliveries. Subscribe to any subset of the full 40-event catalog — see /developers/webhooks, or the webhooks block in openapi.json, for the complete list with payload fields. Returns the signing secret once. A write action — confirm with the user before calling.
delete_webhookwebhooks.deletewrite ⚠Delete an outbound webhook endpoint by id (deliveries cascade). A write action — confirm with the user before calling.
create_clientclients.managewrite ⚠Create a new client group (a brand or influencer whose accounts are managed together). A write action — confirm with the user before calling.
create_connect_inviteaccounts.connectwrite ⚠Mint a shareable self-connect link so a client can connect the requested platforms themselves; returns the link and its expiry. A write action — confirm with the user before calling.
get_webhookwebhooks.readreadRead one webhook endpoint — URL, subscribed events, active state, consecutive failures, and when/why it was auto-disabled. The signing secret is never returned here.
list_webhook_deliverieswebhooks.readreadThe delivery log for one endpoint — each attempt with its event type, response status, error and timing. How you find out WHY an endpoint stopped receiving.
update_webhookwebhooks.managewrite ⚠Change an endpoint’s URL, event list, or active state — including re-enabling one auto-disabled after repeated failures. The event list REPLACES the previous one. A write action — confirm with the user before calling.
test_webhookwebhooks.managewrite ⚠Send a webhook.test delivery and report the outcome, proving an endpoint is reachable and verifying signatures without waiting for a real event. Performs a real outbound request — confirm with the user before calling.
rotate_webhook_secretwebhooks.managewrite ⚠Mint a new signing secret and return it ONCE — it is not readable again. The previous secret keeps verifying for a short overlap so the customer can redeploy without dropping deliveries. A write action — confirm with the user before calling.
get_campaigncampaigns.readreadRead one campaign in full — name, description, status, colour, date range, owning client and post counts.
create_campaigncampaigns.managewrite ⚠Create a campaign — a named group of posts with an optional client, colour and date range. Posts are added with assign_to_campaign. A write action — confirm with the user before calling.
update_campaigncampaigns.managewrite ⚠Change a campaign’s name, description, status, colour or date range. A write action — confirm with the user before calling.
delete_campaigncampaigns.managewrite ⚠Delete a campaign. The posts in it are NOT deleted — they lose the grouping and keep their own schedules. A write action — confirm with the user before calling.
assign_to_campaigncampaigns.managewrite ⚠Add up to 500 existing posts to a campaign. Grouping only — no post’s content or schedule changes. A write action — confirm with the user before calling.
unassign_from_campaigncampaigns.managewrite ⚠Remove posts from a campaign. Grouping only — the posts and their schedules are untouched. A write action — confirm with the user before calling.
get_clientclients.readreadRead one client group in full — name, type, approval policy, posting rules, brand voice and default timezone.
update_clientclients.managewrite ⚠Change a client’s name, type, approval policy, posting rules, brand voice or default timezone. A write action — confirm with the user before calling.
delete_clientclients.managewrite ⚠Archive a client group. OWNER ONLY — a Manager holding the clients.manage scope cannot do this. A write action — confirm with the user before calling.
get_post_targetposts.readreadRead a single fan-out destination in full — status, scheduled time, platform, account, published permalink and external id, and its failure reason when it failed.
get_post_recycleposts.readreadRead one post’s evergreen re-posting configuration and the worker’s bookkeeping. Returns null when the post is not enrolled.
get_accountaccounts.readreadRead one connected social account in full — platform, handle, display name, avatar, status (including whether it needs re-authorisation) and owning client.
get_approvalapprovals.readreadRead one approval request with the gated post’s preview and roll-up, so a reviewer can see what they are deciding on before calling decide_approval.
get_media_assetmedia.readreadRead one content-library asset in full — filename, kind, size, dimensions, duration, folder, labels, alt text, pipeline status, and the publishable/ready flags plus the per-platform readiness map.
get_client_analyticsanalytics.readreadOne client group’s analytics — totals, a per-platform breakdown and a time series. A different projection from get_analytics_overview filtered by client.
get_reportreports.readreadRead one report definition with its run history — each run’s status, window, and whether an export is available.
download_report_exportreports.readreadGet a time-limited download URL for one completed report run’s export file. The URL expires — fetch it when you are ready to use it.
clear_post_recycleposts.composewrite ⚠Turn OFF evergreen re-posting for a post. Idempotent. Already-scheduled recycled copies are not retracted — cancel those separately. A write action — confirm with the user before calling.

Generated from the live MCP catalog — always current.

Discovery URLs#

URLPurpose
https://api.skedcast.com/mcpMCP endpoint (POST; GET returns 405)
/.well-known/oauth-protected-resourceResource metadata + scopes (RFC 9728)
/.well-known/oauth-authorization-serverAuthorization-server metadata (RFC 8414)
/.well-known/jwks.jsonPublic keys for token verification
mcpaiclaude

FAQ

Which AI clients can connect?
Any client that speaks the Model Context Protocol over Streamable HTTP with OAuth — including Claude and a growing list of agent frameworks and IDEs.
Can the agent post without my approval?
Read tools run freely within your granted scopes. The write tools (create_post, import_media) are flagged so your MCP host asks you to confirm before they run, and they still can't exceed your role.

Ready to broadcast everywhere?

Sign up free — no credit card. You land on the Free plan, and you can start a one-time 7-day Studio trial from your workspace whenever you are ready. Connect your first accounts, import a batch, and watch one post fan out across every platform.