Postlore MCP server · for developers and AI agents

Connect Claude, ChatGPT or any AI agent to your social media

Postlore's hosted MCP server lets Claude, ChatGPT, Cursor or your own script plan, draft, schedule and publish posts to Instagram, TikTok, LinkedIn, YouTube, X, Facebook and more. Your agent finds open posting slots, writes in your brand voice, and scores drafts against what has actually worked for your accounts. It acts as you, within your plan, on every plan including Free.

Quick start

Pick the one that matches what you use. Each takes about two minutes.

1

claude.ai, ChatGPT, or any app that supports remote MCP servers

Add a custom connector (in claude.ai and ChatGPT it's under Settings → Connectors; ChatGPT may ask you to turn on developer mode first) and paste:

https://api.postlore.com/mcp

A Postlore window opens. Sign in, tick what the app may do (publishing starts unticked), optionally limit it to one workspace, and press Allow. You'll see it in Settings → Agents, where you can disconnect it.

2

Claude Code

Install the plugin (Claude Code 2.1.224 or later), which also adds two ready-made workflows: fill calendar gaps and a weekly content run.

/plugin marketplace add https://postlore.com/claude/marketplace.json
/plugin install postlore@postlore

Or add just the server. Claude Code opens the same sign-in page the first time it's used:

claude mcp add --transport http postlore https://api.postlore.com/mcp
3

Cursor, VS Code and other clients configured with JSON

Create an API key in Settings → Agents (the key is shown once, so copy it), then add:

{
  "mcpServers": {
    "postlore": {
      "url": "https://api.postlore.com/mcp",
      "headers": { "Authorization": "Bearer pl_live_…" }
    }
  }
}
4

Scripts, cron jobs, n8n and anything that speaks HTTP

Create an API key and call the tools directly. See Call the tools over HTTP.

To check it works, ask your agent: "List my Postlore workspaces." It should answer with your workspace names and connected platforms.

Things to ask

  • "Check my Postlore calendar for this week and draft posts for the empty prime slots."
  • "What worked best on my Instagram last week, and what should I post more of?"
  • "Turn this blog post into a LinkedIn post and an Instagram caption in my brand voice, score both, and save them as drafts."
  • "Set Autopilot to draft a post every Monday and Thursday at 9:30."
  • "Schedule the kelewele draft for my next prime Instagram slot."

Your agent picks the tools. For a calendar check it calls check_calendar, then generate_ideas and adapt_for_platforms to draft, score_draft to check each draft, and create_draft to save it. Nothing is published unless you allowed publishing.

Call the tools over HTTP

Every tool is also a plain HTTP endpoint: POST https://api.postlore.com/v1/tools/{tool} with the tool's arguments as a JSON body, and your API key (or OAuth access token) as a bearer token. Same tools, same permissions.

See which tools your key can use, with their input schemas

curl https://api.postlore.com/v1/tools \
  -H "Authorization: Bearer $POSTLORE_API_KEY"

Check the calendar

curl -X POST https://api.postlore.com/v1/tools/check_calendar \
  -H "Authorization: Bearer $POSTLORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"days": 7}'

Response

{
  "result": {
    "workspace_id": "201385ad-d832-44ba-b43f-2e59f0ee5bdf",
    "timezone": "Africa/Accra",
    "findings": [
      "Last post went out 3 days ago.",
      "1 post scheduled in the next 7 days.",
      "Tue, Sep 29, 6:00 PM GMT: prime instagram slot with nothing scheduled.",
      "Mon, Oct 5, 6:00 PM GMT: prime instagram slot with nothing scheduled."
    ],
    "open_prime_slots": [
      { "platform": "instagram", "slot_utc": "2026-09-29T18:00:00.000Z",
        "slot_local": "Tue, Sep 29, 6:00 PM GMT", "filled": false },
      { "platform": "instagram", "slot_utc": "2026-10-05T18:00:00.000Z",
        "slot_local": "Mon, Oct 5, 6:00 PM GMT", "filled": false }
    ],
    "filled_prime_slots": [],
    "scheduled_posts": [
      { "id": "b76a9e45-…", "platforms": ["instagram"],
        "scheduled_at": "2026-09-29T14:32:21.281Z", "content": "Schedule me" }
    ],
    "last_published_at": "2026-09-26T12:32:18.990Z"
  }
}

Times: best posting hours and days are always on the workspace's own clock (its timezone). slot_utc is the exact instant (use it for scheduled_at); slot_local is the same moment, written for people in the workspace's timezone.

Score a draft

curl -X POST https://api.postlore.com/v1/tools/score_draft \
  -H "Authorization: Bearer $POSTLORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"content": "New kelewele spot opening Friday #kelewele", "platforms": ["instagram"], "media_types": ["image"]}'

Response

{
  "result": {
    "score": 40,
    "strengths": ["short caption", "1 top hashtag"],
    "fixes": [
      "video posts perform best for this account",
      "Schedule for Monday 18:00",
      "Add #accrafood"
    ],
    "timezone": "Africa/Accra"
  }
}

Save it as a draft

curl -X POST https://api.postlore.com/v1/tools/create_draft \
  -H "Authorization: Bearer $POSTLORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"content": "Kelewele Friday is back", "platforms": ["instagram"], "idempotency_key": "kelewele-friday-1"}'

Response

{
  "result": {
    "post": {
      "id": "85f857a1-0eec-482f-a5f7-e29ff9cbb598",
      "status": "draft",
      "platforms": ["instagram"],
      "content": "Kelewele Friday is back",
      "created_by_agent": true,
      "compose_url": "https://postlore.com/dashboard/compose?draft_id=85f857a1-…",
      "…": "…"
    }
  }
}

If your account has more than one workspace, add "workspace_id" to each call (from list_workspaces), or create a key limited to one workspace and leave it out. The full machine-readable description is at /openapi.json (OpenAPI 3.1), ready to import into Postman, n8n or an agent framework.

Example: a weekly script

This finds the week's open prime slots, drafts a post for each in your brand voice, scores it, and saves it for you to review. Run it on a schedule. Re-running it doesn't create duplicates, because each draft uses an idempotency key tied to its slot.

Node 18+ — POSTLORE_API_KEY=pl_live_… node fill-gaps.mjs

// fill-gaps.mjs — draft posts for this week's open prime slots.
// Run weekly: POSTLORE_API_KEY=pl_live_… node fill-gaps.mjs
// Needs Node 18+. Use a key limited to one workspace, or pass workspace_id.

const KEY = process.env.POSTLORE_API_KEY
const API = `${process.env.POSTLORE_API_URL ?? 'https://api.postlore.com'}/v1/tools`

async function tool(name, args = {}) {
  const res = await fetch(`${API}/${name}`, {
    method: 'POST',
    headers: { Authorization: `Bearer ${KEY}`, 'Content-Type': 'application/json' },
    body: JSON.stringify(args),
  })
  const body = await res.json()
  if (!res.ok) throw new Error(`${name} failed: ${body.error.code}: ${body.error.message}`)
  return body.result
}

const calendar = await tool('check_calendar', { days: 7 })
console.log(calendar.findings.join('\n'))

for (const slot of calendar.open_prime_slots.slice(0, 3)) {
  const { ideas } = await tool('generate_ideas', { platforms: [slot.platform], count: 1 })
  const idea = ideas[0]
  const text = idea.draft ?? `${idea.hook}\n\n${idea.summary}`

  const { variants } = await tool('adapt_for_platforms', { content: text, platforms: [slot.platform] })
  const score = await tool('score_draft', {
    content: variants[0].content,
    platforms: [slot.platform],
    scheduled_at: slot.slot_utc,
  })

  // The idempotency key makes a re-run of this script safe: the same slot
  // returns the draft it already created instead of making a second one.
  const { post } = await tool('create_draft', {
    content: variants[0].content,
    platforms: [slot.platform],
    idempotency_key: `fill-gaps-${slot.platform}-${slot.slot_utc}`,
  })
  console.log(`${slot.slot_local} (${slot.platform}): score ${score.score ?? 'n/a'}, review at ${post.compose_url}`)
}

Python 3.8+ — pip install requests; POSTLORE_API_KEY=pl_live_… python fill_gaps.py

# fill_gaps.py — draft posts for this week's open prime slots.
# Run weekly: POSTLORE_API_KEY=pl_live_… python fill_gaps.py
# Needs Python 3.8+ and `pip install requests`.

import os
import requests

KEY = os.environ["POSTLORE_API_KEY"]
API = os.environ.get("POSTLORE_API_URL", "https://api.postlore.com") + "/v1/tools"


def tool(name, **args):
    res = requests.post(
        f"{API}/{name}",
        headers={"Authorization": f"Bearer {KEY}"},
        json=args,
        timeout=60,
    )
    body = res.json()
    if not res.ok:
        raise RuntimeError(f"{name} failed: {body['error']['code']}: {body['error']['message']}")
    return body["result"]


calendar = tool("check_calendar", days=7)
print("\n".join(calendar["findings"]))

for slot in calendar["open_prime_slots"][:3]:
    idea = tool("generate_ideas", platforms=[slot["platform"]], count=1)["ideas"][0]
    text = idea.get("draft") or f"{idea['hook']}\n\n{idea['summary']}"

    variant = tool("adapt_for_platforms", content=text, platforms=[slot["platform"]])["variants"][0]
    score = tool("score_draft", content=variant["content"], platforms=[slot["platform"]], scheduled_at=slot["slot_utc"])

    # Same idempotency key on a re-run returns the existing draft, not a duplicate.
    post = tool(
        "create_draft",
        content=variant["content"],
        platforms=[slot["platform"]],
        idempotency_key=f"fill-gaps-{slot['platform']}-{slot['slot_utc']}",
    )["post"]
    print(f"{slot['slot_local']} ({slot['platform']}): score {score.get('score')}, review at {post['compose_url']}")

Output

Last post went out 3 days ago.
1 post scheduled in the next 7 days.
Tue, Sep 29, 6:00 PM GMT: prime instagram slot with nothing scheduled.
Tue, Sep 29, 6:00 PM GMT (instagram): score 75, review at https://postlore.com/dashboard/compose?draft_id=…

Build your own client (OAuth)

Apps that act for other Postlore users should use "Sign in with Postlore" instead of asking for API keys. It's standard OAuth 2.1 with PKCE, as the MCP authorization spec describes, so MCP client libraries (including the official SDKs) handle it for you when you point them at https://api.postlore.com/mcp. If you're building it yourself, these are the steps:

# Connect a custom app with "Sign in with Postlore" (OAuth 2.1 + PKCE).
# Most MCP clients do all of this for you; follow it if you're building one.

# 1. Discover. /mcp answers 401 with a pointer to the metadata:
curl -si -X POST https://api.postlore.com/mcp | grep -i www-authenticate
curl -s https://api.postlore.com/.well-known/oauth-authorization-server

# 2. Register your app (skip this if your client_id is the HTTPS URL of a
#    Client ID Metadata Document — Postlore fetches it for you).
curl -s -X POST https://api.postlore.com/oauth/register \
  -H 'Content-Type: application/json' \
  -d '{"client_name": "My Agent", "redirect_uris": ["http://127.0.0.1:8765/callback"]}'
# → {"client_id": "plc_…", ...}
CLIENT_ID=plc_…

# 3. PKCE: a random verifier and its SHA-256 challenge.
VERIFIER=$(openssl rand -base64 48 | tr -d '=+/\n' | cut -c1-64)
CHALLENGE=$(printf '%s' "$VERIFIER" | openssl dgst -sha256 -binary | openssl base64 | tr '+/' '-_' | tr -d '=')

# 4. Send the user's browser here. They sign in, choose what your app may do
#    and which workspace, and come back to your redirect URI with ?code=…&state=…&iss=…
echo "https://api.postlore.com/oauth/authorize?response_type=code&client_id=$CLIENT_ID\
&redirect_uri=http%3A%2F%2F127.0.0.1%3A8765%2Fcallback&code_challenge=$CHALLENGE\
&code_challenge_method=S256&state=xyz&scope=workspace%3Aread%20insights%3Aread%20drafts%3Awrite\
&resource=https%3A%2F%2Fapi.postlore.com%2Fmcp"
CODE=…   # from the redirect; check that iss is https://api.postlore.com

# 5. Exchange the code (form-encoded). Codes work once and expire in 10 minutes.
curl -s -X POST https://api.postlore.com/oauth/token \
  -d grant_type=authorization_code -d client_id=$CLIENT_ID -d code=$CODE \
  -d code_verifier=$VERIFIER -d redirect_uri=http://127.0.0.1:8765/callback \
  -d resource=https://api.postlore.com/mcp
# → {"access_token": "pl_oat_…", "expires_in": 3600, "refresh_token": "pl_ort_…", "scope": "…"}

# 6. Use the access token like an API key, on /mcp or /v1/tools.
curl -s https://api.postlore.com/v1/tools -H "Authorization: Bearer $ACCESS_TOKEN"

# 7. Refresh before it expires. Refresh tokens rotate: store the new one.
#    Reusing an old refresh token disconnects the app.
curl -s -X POST https://api.postlore.com/oauth/token \
  -d grant_type=refresh_token -d client_id=$CLIENT_ID -d refresh_token=$REFRESH_TOKEN

# 8. Disconnect.
curl -s -X POST https://api.postlore.com/oauth/revoke -d token=$REFRESH_TOKEN
  • Redirect URIs must be https, http on localhost/127.0.0.1 (any port), or an app-specific scheme.
  • Access tokens last an hour. Refresh tokens last 60 days and change every time you use one.
  • The user can disconnect your app at any time in Settings → Agents; its tokens stop working immediately.

Tool reference

Arguments are shown as the JSON body for /v1/tools/{tool}; MCP clients send the same object. workspace_id is optional on every tool when the connection is limited to one workspace or the account has only one.

Find what to post

check_calendarneeds workspace:read, insights:read

Start here. Your proven best posting slots in the coming days that have nothing scheduled, and how long since your last post.

{ "days": 7 }
get_performance_contextneeds insights:read

What has worked for this account: best hours and days, hashtags, caption length and media type. Creator plan and above.

{}
list_top_postsneeds insights:read

Your best-performing posts from more than 30 days ago, good material to recycle. Creator plan and above.

{}
list_postsneeds workspace:read

Posts by status, platform or date, newest first, with analytics.

{ "status": "published", "from": "2026-09-22T00:00:00Z", "limit": 20 }

Draft

get_brand_voiceneeds workspace:read

Your brand's about, tone, audience, key messages, do's and don'ts, as sections and as full text.

{}
generate_ideasneeds drafts:write

Post ideas in your voice, grounded in what has performed plus local news and trends. Uses AI allowance.

{ "platforms": ["instagram"], "topic": "new menu", "count": 3 }
adapt_for_platformsneeds drafts:write

One piece of content rewritten as a native post for each platform. Uses AI allowance.

{ "content": "New menu drops Friday", "platforms": ["instagram", "linkedin"] }
generate_hashtagsneeds drafts:write

Proven, market-specific and trending hashtags. Uses AI allowance.

{ "content": "New menu drops Friday", "platform": "instagram", "market": "Accra" }
score_draftneeds insights:read

0-100 against your account's winning patterns, with the specific fixes. Instant, no AI allowance. Creator plan and above.

{ "content": "New menu drops Friday #kelewele", "platforms": ["instagram"], "media_types": ["video"], "scheduled_at": "2026-10-06T18:00:00Z" }
coach_draftneeds drafts:write

Written coaching on a draft from an editor who knows your results. Uses AI allowance.

{ "content": "New menu drops Friday", "platforms": ["instagram"], "goal": "sales" }

Save, schedule, publish

create_draftneeds drafts:write

Save a draft for review. Returns compose_url, which opens it in Postlore.

{ "content": "New menu drops Friday", "platforms": ["instagram"], "idempotency_key": "menu-2026-10-06" }
update_draftneeds drafts:write

Edit a draft. Does not schedule or publish.

{ "post_id": "…", "content": "New menu drops Friday 🌶️" }
schedule_postneeds posts:schedule

Schedule a draft. At least 15 minutes ahead unless the connection can publish. Paid plans.

{ "post_id": "…", "scheduled_at": "2026-10-06T18:00:00Z", "idempotency_key": "sched-menu-1" }
publish_postneeds posts:publish

Publish now. In workspaces that require approval, a team member's post goes to review instead.

{ "post_id": "…", "idempotency_key": "pub-menu-1" }

Account

list_workspacesneeds workspace:read

Your workspaces with connected platforms, plan, posts left this month and timezone.

{}
get_autopilotneeds workspace:read

Your Autopilot settings.

{}
set_autopilotneeds autopilot:write

Turn Autopilot on or off and set its schedule (days 0=Sunday..6, time in the workspace timezone). Owner only, Starter and above.

{ "enabled": true, "cadence_days": [1, 4], "cadence_time": "09:30" }

Drafting tools report the AI allowance they used, so an agent can stop before running out:

{
  "result": {
    "usage": { "action": "adapt.generate", "used": 3, "limit": 600, "remaining": 597, "warning": "none" },
    "variants": [ { "platform": "instagram", "content": "…", "characters": 118, "notes": "…" } ]
  }
}

Your brand voice and performance patterns are also MCP resources an app can attach to a conversation: postlore://workspace/{id}/brand-voice and postlore://workspace/{id}/performance.

Permissions

You choose what each connection can do when you sign in or create a key. Publishing is always off unless you tick it. An agent only sees the tools its permissions allow.

  • workspace:read Read workspaces and posts: brand voice, post list, plan usage.
  • insights:read Read insights: best times, top posts, performance.
  • drafts:write Write drafts: generate ideas and captions, create and edit drafts.
  • posts:schedule Schedule posts: at least 15 minutes ahead.
  • posts:publish Publish immediately: posts go live on your accounts right away.
  • autopilot:write Manage Autopilot: change your autopilot schedule.

Safety and limits

  • Drafts are always safe. Nothing goes live unless the connection can publish.
  • Posts an agent schedules must be at least 15 minutes out, unless it can publish, so you can catch mistakes.
  • A connection can only edit a post that's already scheduled or in review if it can schedule, and one due within 15 minutes only if it can publish.
  • In workspaces that require approval, a team member's agent sends posts for review instead of publishing.
  • Posts an agent creates show an "Agent" badge in your calendar, and everything it changes is recorded.
  • A connection can be limited to one workspace.
  • Your plan's limits apply as usual: posts per month, scheduling, and AI allowance.
  • Requests per minute per connection: 30 on Free, 60 on Starter, 300 on Creator and Pro, 600 on Agency.

Errors and retries

Over HTTP, errors use the status code below and this body. Over MCP, the tool result is marked as an error with the same JSON.

HTTP/1.1 400 Bad Request

{
  "error": {
    "code": "workspace_required",
    "message": "This account has several workspaces. Pass workspace_id (see list_workspaces)."
  }
}
codeHTTPWhat to do
insufficient_scope403The connection lacks a permission. Reconnect, or create a key, with it.
workspace_required400The account has several workspaces. Pass workspace_id, or use a key limited to one workspace.
plan_required403The feature needs a higher plan. Performance insights and scoring are Creator and above.
schedule_too_soon403Schedule at least 15 minutes ahead, unless the connection can publish.
invalid_request400An argument is missing or invalid. The message says which.
not_found404The post or tool doesn't exist, or this connection can't use it.
in_progress409A request with the same idempotency_key is still running. Retry shortly.
publish_failed422Publishing failed on every platform. Open the post in Postlore.
platform_auth_expired—In publish_post failures: a social account needs reconnecting in Postlore.
rate_limited429Too many requests. Wait a few seconds and retry.

Retrying safely: create_draft, schedule_post and publish_post accept an idempotency_key (any unique string, 8-100 characters). Send the same key when you retry and you get the first result back instead of a second post. Keys are remembered for 24 hours.

Frequently asked questions

What is the Postlore MCP server?
MCP (Model Context Protocol) is the open standard AI apps use to connect to tools. Postlore's hosted MCP server at https://api.postlore.com/mcp lets Claude, ChatGPT, Cursor or any MCP client use your Postlore account: check your content calendar, draft posts in your brand voice, score them against what has worked for you, and schedule or publish.
Can Claude or ChatGPT post to Instagram, TikTok or LinkedIn for me?
Yes. Connect your social accounts in Postlore, then connect Claude or ChatGPT to Postlore, and your agent can draft, schedule and publish to them. Publishing stays off unless you allow it when you connect the agent.
Which social platforms can my AI agent post to?
Every platform you connect in Postlore: Instagram, Facebook, Threads, TikTok, X (Twitter), LinkedIn, YouTube, Pinterest, Reddit, Bluesky, Google Business Profile and Telegram.
Is it free?
Agent access is included on every plan, including Free. Your plan's usual limits apply: on Free that is 6 posts a month and no scheduling; paid plans add scheduling, more posts and performance insights.
Is it safe to let an AI agent use my social accounts?
You decide what each agent can do when you connect it (read, draft, schedule or publish) and can limit it to one workspace. Publishing is off by default, an agent must schedule at least 15 minutes ahead unless it can publish, everything it changes is recorded, and you can disconnect it at any time in Settings, Agents.
Do I need to write code?
No. In claude.ai or ChatGPT you paste one URL and sign in, and in Claude Code it is one command. If you do want to script it, the same tools are available over plain HTTP with an OpenAPI description.
Does it work with agents that don't support MCP?
Yes. Every tool is also an HTTP endpoint, POST https://api.postlore.com/v1/tools/{tool}, described in OpenAPI 3.1 at https://api.postlore.com/openapi.json, so n8n, automation tools, scripts and agent frameworks can use it too.

For machines