SocialKit speaks MCP, returns structured JSON, and is designed to live inside a loop. Score, rewrite, regrade, ship. No prompt gymnastics, no JSON-mode bandaids.
One HTTP endpoint, bearer auth, every SocialKit capability exposed as a tool. Drop the config into any MCP-aware client.
# Add the remote MCP server (recommended):
claude mcp add --transport http socialkit \
https://mcp.socialkit.sh \
--header "Authorization: Bearer $SOCIALKIT_KEY"
# Or add it to .mcp.json by hand:
# {
# "mcpServers": {
# "socialkit": {
# "type": "http",
# "url": "https://mcp.socialkit.sh",
# "headers": { "Authorization": "Bearer $SOCIALKIT_KEY" }
# }
# }
# }# ~/.cursor/mcp.json
{
"mcpServers": {
"socialkit": {
"type": "http",
"url": "https://mcp.socialkit.sh",
"headers": { "Authorization": "Bearer $SOCIALKIT_KEY" }
}
}
}# discovery is keyless: read the catalog before you sign up
curl https://mcp.socialkit.sh/tools/list
# tools: score_post, rewrite_post,
# validate_post, generate_post, plan_week,
# build_voice, create_brand,
# update_brand, delete_brand,
# create_voice, update_voice,
# delete_voice, create_post,
# update_post, delete_post,
# schedule_post, bulk_schedule,
# cancel_post, publish_post,
# refresh_metrics, list_posts,
# get_post, score_saved_post,
# get_post_metrics, get_post_scores,
# get_calibration, get_analytics,
# get_calendar, list_brands,
# list_voices, list_channels,
# get_accountscore_postGrade a post 0-100 with a per-dimension breakdown.rewrite_postVoice-preserving rewrite that returns before/after scores.validate_postPreflight a draft: structural errors + reach/voice warnings, no LLM call.generate_postGenerate 1-3 scored drafts from a brief, ranked best-first.plan_weekTurn a brief into a sequenced content plan.build_voiceDistill a reusable voice from sample posts; pass its id to generate/plan.generate_visualA finished post with rendered image masters, the judge's score, and a revisable spec.revise_visualRefine a generated visual post with freeform feedback; unaddressed parts hold verbatim.generate_carouselA full swipe deck in one frame family with per-slide roles, rendered and judged.revise_carouselRefine a generated deck with freeform feedback, slide by slide or as a set.create_brandCreate a brand to ground generation and posts; returns its id.update_brandPatch an existing brand; only the fields you pass change.create_voiceCreate a voice from explicit traits, do-nots, and exemplars; returns its id.update_voicePatch an existing voice; only the fields you pass change.create_postSave a draft so it can be scheduled or published; returns its id.update_postEdit a draft's text, brand, channel, or media; only the fields you pass change.delete_brandDelete a brand by id; future generation can no longer reference it.delete_voiceDelete a voice profile by id; future generation can no longer reference it.delete_postPermanently delete a post and any pending scheduled job; not mid-publish.schedule_postSchedule a saved draft to publish at a future time.bulk_scheduleCreate and schedule a whole planned week in one all-or-nothing call.cancel_postCancel a scheduled post so it won't publish.publish_postPublish a stored draft to its connected channel right now.refresh_metricsPoll the platform now and store a fresh engagement snapshot.list_postsList posts newest-first, filter by status, paginated.get_postFetch a single post by id with its current status and text.get_post_metricsRead a published post's engagement: latest snapshot plus history.get_post_scoresRead a post's recorded score history with full breakdowns.score_saved_postScore a stored post and record it, so it enters the score-vs-reality set.get_calibrationRead score-vs-reality: did predicted scores track actual engagement.get_analyticsAccount-wide engagement rollup, totals and per-platform.get_calendarSee scheduled and published posts within a time window.list_brandsDiscover brand ids to ground generation and posts.list_voicesDiscover saved voice ids to write in a distilled voice.list_channelsDiscover connected channel ids to bind posts to.get_accountConfirm which account and plan the API key is authenticated as.The server also ships prompts, the canonical workflows your client can surface directly. prompts/list returns them; prompts/get fills in your brief.
draft_and_gradeDraft from a brief, then score and rewrite until it clears a target.improve_postGrade an existing post and rewrite the weak dimensions; returns before/after.plan_and_draft_weekTurn a brief into a sequenced week, then draft and save each post.And resources, your account context as attachable, read-only JSON. resources/list enumerates them; resources/read returns the document so your model can ground a draft in your own brand and voice without a tool call.
socialkit://metaThe service contract: score version, supported platforms, media kinds, and dimension weights. Build a valid call without guessing.socialkit://accountIdentity, plan, and what this deployment can do (publish, metrics, channels).socialkit://brandsEvery brand: audience, themes, link policy. Ground a draft without discovery.socialkit://voicesSaved voices and their traits, so the writing matches a distilled voice.socialkit://channelsConnected channels and status, so the model knows what it can publish to.socialkit://calibrationScore-vs-reality dataset: which predicted scores actually translated to reach.The pattern that actually works: let your model draft freely, then use SocialKit as the judge and the rewriter. Three attempts is usually enough to land 80+.
import Anthropic from "@anthropic-ai/sdk";
const claude = new Anthropic();
// SocialKit is plain JSON over HTTPS. No SDK to install.
async function sk(path: string, body: unknown) {
const res = await fetch(`https://api.socialkit.sh/v1/${path}`, {
method: "POST",
headers: {
"content-type": "application/json",
authorization: `Bearer ${process.env.SOCIALKIT_KEY}`,
},
body: JSON.stringify(body),
});
if (!res.ok) throw new Error(`socialkit ${path}: ${res.status}`);
return res.json();
}
async function draftAndGrade(brief: string) {
let draft = await claude.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 800,
messages: [{ role: "user", content: `Write a LinkedIn post: ${brief}` }],
}).then(r => r.content[0].text);
for (let attempt = 0; attempt < 3; attempt++) {
const grade = await sk("score", { post: draft });
if (grade.overall >= 80) return { draft, grade };
const { rewrite, after } = await sk("rewrite", { post: draft });
draft = rewrite;
if (after.overall >= 80) return { draft, grade: after };
}
return { draft, grade: await sk("score", { post: draft }) };
}Your model writes from a brief. No scoring constraints.
/v1/score returns 0-100 with ranked signals.
/v1/rewrite fixes weak dimensions, keeps the voice, returns before and after.
Loop until score ≥ target or max attempts. Return both.
The same key reaches the visual engine: a brief and a brand kit go in, a finished post comes out with rendered image masters, the design judge's score, and a revisable spec. Your agent asks in plain words; the engine decides, renders, judges, and revises before answering. The full pipeline is on how it works.
# Slow call by API standards (tens of seconds to minutes).
# Always send an Idempotency-Key so a retry can't double-spend.
curl -X POST https://api.socialkit.sh/v1/generate-visual-v2 \
-H "Authorization: Bearer $SOCIALKIT_KEY" \
-H "Idempotency-Key: post-2026-07-27-a" \
-d '{
"businessContext": { "businessName": "Driftwood Roasters",
"brandKit": { ... } },
"seed": { "platform": "instagram", "idea": "the Tuesday roast" }
}'
# -> { masters: [{ aspectRatio: "4:5", imageUrl }, ...],
# caption, hashtags,
# score: { verdict: "SHIP", score: 95, ... },
# spec: { ...hand back to /v1/revise-visual-v2 } }A revision is one more call with the spec and freeform feedback, and it is surgical: the photo stays while the headline moves. Decks work the same way through /v1/generate-carousel-v2. One credit per successful call; a blocked result costs nothing.
MCP-native agents get the same power as tools: generate_visual, revise_visual, generate_carousel, and revise_carousel, annotated as credit-bearing and slow so a well-behaved agent knows what it is spending before it calls. Each artifact has its own page: images, carousels, and video (video powers Taka in production and is not on the public surface yet).
Different jobs get different models, and none of them touch the pixels. The edge isn't a secret ranker. It's what each model is told before it works, and what the code refuses to let them do.
Claude Opus decides what a visual post says: the brief, the angles, the copy. Then a vision pass of the same model judges the finished render against four hard gates and eleven weighted dimensions, with forced tool use so the verdict is typed JSON, not prose.
Claude Sonnet runs the text intelligence: scoring, drafts, rewrites, and week plans. It scores against a written evidence base of how each feed actually ranks, and it is re-graded after every rewrite, always.
When a brand has no usable photo, Gemini paints a name-free, text-free atmospheric scene. It never renders words: the text layer is composited by code, which is why warped glyphs and garbled logos are structurally impossible.
Where this goes next: a calibrated ranker trained on real outcomes, scoring dwell and reshare likelihood directly. That's on the roadmap, not in the box yet. We'd rather tell you what runs today than ship a number we can't stand behind.
We can route grading to your own judge or your own ranker. Tell us what you're optimizing for.