postbaseCAUTION
Open-source social media scheduler with an MCP server: post to X, LinkedIn, Bluesky, Mastodon, TikTok and YouTube, or let your AI do it.
Overview
From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.
The social scheduler even your AI can run.
Postbase is an open-source, MCP-native social media scheduler. Connect your channels, compose and schedule posts, and Postbase publishes them across every channel on time — from a clean dashboard, or straight from the AI tools you already work in.
- MCP-native — Claude, ChatGPT, Cursor, Claude Code and other MCP clients can
draft and schedule posts through the hosted server at https://mcp.postbase.so/mcp (OAuth sign-in) or the `@postbasehq/mcp` npm package (API key). There's a REST API too.
- Built-in AI agent — a chat in the app that drafts posts and schedules them
once you confirm.
- Self-host free, or use the [hosted cloud](https://www.postbase.so/pricing) —
same product either way.
Channels: X, LinkedIn, Bluesky, Mastodon, TikTok, YouTube · Instagram, Facebook and Threads coming soon.
Docs: docs.postbase.so
Tech stack
- Next.js (App Router) + TypeScript + Tailwind
- Supabase — Postgres, Auth, Storage
- Vercel Cron — scheduled-publishing poller
- `@postbasehq/mcp` — MCP server (npm)
Getting started
npm install cp .env.example .env.local # fill in your Supabase (and later, platform) keys npm run dev
Apply the database schema in supabase/migrations/ (via the Supabase SQL editor or the CLI). To run the scheduled publisher locally (polls the publish endpoint):
npm run poll # in a second terminal
In production, a Vercel Cron job hits /api/cron/publish every minute (vercel.json), so no separate worker is needed.
MCP server
Add Postbase to your AI client and let an agent schedule posts for you. The MCP server lives in its own repo: [postbasehq/mcp](https://github.com/postbasehq/mcp) (published as `@postbasehq/mcp` on npm). Tools: list_channels,
d3b536be5faeOBSERVED · 2026-10-10Connect
Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.
claude mcp add postbase --env ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} --env API_KEY_PEPPER=${API_KEY_PEPPER} --env CRON_SECRET=${CRON_SECRET} --env GITHUB_TOKEN=${GITHUB_TOKEN} -- npx -y [email protected]{
"mcpServers": {
"postbase": {
"command": "npx",
"args": [
"-y",
"[email protected]"
],
"env": {
"ANTHROPIC_API_KEY": "${ANTHROPIC_API_KEY}",
"API_KEY_PEPPER": "${API_KEY_PEPPER}",
"CRON_SECRET": "${CRON_SECRET}",
"GITHUB_TOKEN": "${GITHUB_TOKEN}"
}
}
}
}Exposed tools (13)
4 read · 9 write · 0 destructive.
| Tool | Risk | Description |
|---|---|---|
ask_user | read | Ask the user one question with tap-to-answer options. They can also type their own answer. End your turn after calling this. |
cancel_post | write | Cancel a scheduled post (reverts it to a draft) by its id. |
draft_post | write | Show the user a post draft they can save to Postbase or schedule. Does not post anything. |
generate_image | write | Generate an image from a text description to attach to a post. Returns a URL. Only use when the user wants visual content. Takes a few seconds. |
list_channels | read | List the user |
list_posts | read | List the user |
list_scheduled | read | List the user |
propose_post | write | Propose a post or thread for the user to review and schedule. This does NOT publish or schedule — it shows the user an editable preview card with a Schedule button. Always use real channel_ids from list_channels. Provide |
remember | write | Save what you know about the user and their business, shared with all their bots. Pass the complete note (it replaces the old one); a short factual brief. |
run_sweep | write | Check your listening sources now for anything new. Its summary and findings are shown to the user as their own message. |
save_listen_setup | write | Save (or replace) what you listen for, where, and when, and start the schedule. Pass the complete setup. |
set_identity | write | Name yourself and record your job, once the user has said what they want you to do. |
set_status | write | Pause or resume your scheduled listening. |
Trust audit
CAUTIONgrade B · trust 81/100 Install with care. The audit found things worth knowing before you trust its output.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | FAIL |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | PASS |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- declared (1 observation(s))
- Network
- declared (5 observation(s))
- Shell
- none-observed
- Dependencies
- not all pinned
- Secrets in source
- found
Findings (17)
DATABASE_URL=postgresql://postgres:[email protected]:5432/postgres
page.hash = createHash("sha1").update(`${page.title}\n${page.description}\n${text.replace(/\s+/g, " ")}`).digest("hex");import { updatePost } from "../../actions";expect(urlProblem("https://169.254.169.254/latest")).toMatch(/private/);expect(urlProblem("https://metadata.google.internal/x")).toMatch(/private/);"evil.nip.io": ["169.254.169.254"],
"metadata.google.internal",
["internal address", "https://169.254.169.254/latest/meta-data/"],
expect(urlProblem("https://127.0.0.1/a.png")).toMatch(/private/);expect(urlProblem("https://169.254.169.254/latest")).toMatch(/private/);["internal address", "https://169.254.169.254/latest/meta-data/"],
"https://169.254.169.254/latest",
mediaRows = [{ storage_url: "https://169.254.169.254/latest/meta-data/", type: "image/png" }];@anthropic-ai/sdk, @aws-sdk/client-s3, @aws-sdk/s3-request-presigner, @sentry/nextjs, @supabase/ssr, @supabase/supabase-js, @vercel/analytics, framer-motion
The `accessJwt` only lasts a few minutes. For a long-running app, refresh it with `com.atproto.server.refreshSession`. For scheduled posting, we simply create a fresh session right before each post.
Exchange the code at `POST https://api.x.com/2/oauth2/token` with the verifier, and store both tokens. Refresh the access token with `grant_type=refresh_token` before it expires. The refresh response
2. Open **AI & API** and create an API key. Name it "n8n" so you know where it's used. The key is shown once, so copy it now.
Gates applied: no_behavioural_pass.
d3b536be5faefull audit observations/trust-audit/mcp-server/postbasehq__postbase.json · Report an issue / request a re-scanAudit history
Every audit this server has had. A grade with a past is a grade somebody is still checking.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-10 | d3b536be5fae | CAUTION | B | 81 | first audit |
Questions
What is the postbase MCP server?
Open-source social media scheduler with an MCP server: post to X, LinkedIn, Bluesky, Mastodon, TikTok and YouTube, or let your AI do it.
What tools does postbase expose?
13 in total: 4 read-only, 9 that write, and 0 that can delete or overwrite. Every one is listed on this page with its risk.
Is postbase safe to connect to an agent?
With care. The audit graded it B (81/100) and found 17 things worth knowing before you trust this server, listed below with the exact line each was found on.
What credentials does postbase need?
It reads ANTHROPIC_API_KEY, API_KEY_PEPPER, CRON_SECRET, GITHUB_TOKEN, HIGGSFIELD_API_KEY, LINKEDIN_CLIENT_SECRET, META_APP_SECRET, NEXT_PUBLIC_SUPABASE_ANON_KEY, OPENAI_API_KEY, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY and REDDIT_CLIENT_SECRET from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.
How current is this page?
The grade is for one exact copy of the source (d3b536be5fae), read on 2026-10-10. The repository is watched and re-audited when it changes.