Outpost
Social media API and MCP server for AI agents. Publish to X, Instagram, LinkedIn, Reddit, Bluesky, and Threads from a single endpoint.
Post to X, LinkedIn, Instagram, Reddit, Bluesky, and Threads — from any AI agent — with a single API call. Outpost understands agent needs: structured errors with agentHint, MCP native integration for Claude Desktop/Cursor, and per-org credential isolation (the thing Postiz literally cannot do).
<!-- tags: social-media, mcp, multi-platform, agents, publish, ai-agents, oauth, webhooks -->
---
One-Liner Quickstart
# Self-host with Docker (Postgres + Redis included):
git clone https://github.com/andrezani/outpost Outpost && cd Outpost && cp .env.example .env && docker compose up -d && docker compose exec app npm run seed:admin
Then post to any platform: ``bash curl -X POST http://localhost:3000/api/v1/publish \ -H "X-API-Key: sa_xxx" \ -H "Content-Type: application/json" \ -d '{"platform":"x","accountId":"<id>","content":{"text":"Hello from Outpost!"}}' ``
---
Why Outpost
- Agent-native errors — every failure returns
code+agentHintso your LLM knows exactly what to do - MCP server included — works natively in Claude Desktop, Cursor, and any MCP-compatible agent
- Multi-tenant OAuth — each org connects their own social accounts (not shared credentials like Postiz)
- One unified endpoint —
POST /api/v1/publishposts to any platform, same request shape - 6 platforms, all working — X (Twitter), LinkedIn, Instagram, Reddit, Bluesky, Threads
---
Stack
| Layer | Technology | |-------|-----------| | Framework | NestJS 11 (TypeScript) | | Database | PostgreSQL 16 via Prisma | | Cache | Redis 7 | | Auth | API Key (X-API-Key or Authorization: Bearer) | | MCP | stdio transport (Claude Desktop, Cursor) |
---
Monorepo map
This repository is now the canonical Outpost monorepo:
./— NestJS API, Prisma schema, Docker infra, and core product codepackages/mcp/— canonical in-repo MCP packagepackages/outpost-mcp-standalone/— legacy standalone MCP repo imported for history/referenceapps/landing/— static marketing site imported from the oldoutpost-landingrepo
The old standalone GitHub repos are legacy sources only. New agent work should happen in this repo on dev.
---
Quick Start
Prerequisites
- Node.js 18+
- Docker (for Postgres + Redis)
1. Install
git clone https://github.com/andrezani/outpost Outpost
cd Outpost
npm install
npx prisma generate
2. Configure environment
cp .env.example .env
# Edit .env — DATABASE_URL and social platform credentials
3. Start infrastructure
docker compose up -d
4. Run migrations + seed
npx prisma migrate dev
5. Start
npm run start:dev
---
API Reference
Authentication
All endpoints (except POST /organizations and GET /health) require an API key:
X-API-Key: sa_xxx
# or
Authorization: Bearer sa_xxx
Create your organization + get an API key: ``bash curl -X POST http://localhost:3000/organizations \ -H "Content-Type: application/json" \ -d '{"name": "My Org"}' ``
---
POST /api/v1/publish
Publish a post to any platform.
curl -X POST http://localhost:3000/api/v1/publish \
-H "X-API-Key: sa_xxx" \
-H "Content-Type: application/json" \
-d '{
"platform": "x",
"accountId": "clxxx",
"content": {
"text": "Hello from Outpost! 🤖"
}
}'
Success response: ``json { "success": true, "postId": "1234567890", "platform": "x", "url": "https://x.com/user/status/1234567890", "publishedAt": "2026-03-25T03:35:00.000Z" } ``
Failure response (agent-parseable): ``json { "success": false, "error": { "code": "RATE_LIMITED", "message": "X rate limit exceeded", "agentHint": "Retry after 2026-03-25T03:45:00Z. Rate limit resets every 15 minutes.", "retryAfter": "2026-03-25T03:45:00Z" } } ``
Error codes:
| Code | Meaning | |------|---------| | AUTH_EXPIRED | Token expired — reconnect account | | AUTH_INVALID | Token revoked — full re-auth needed | | RATE_LIMITED | Platform rate limit hit | | ORG_QUOTA_EXCEEDED | Monthly free tier (100 posts) exhausted | | CONTENT_TOO_LONG | Text exceeds platform limit | | CONTENT_POLICY | Platform rejected for policy violation | | MEDIA_TOO_LARGE | Media file too large | | MEDIA_TYPE_UNSUPPORTED | Platform doesn't support this media type | | ACCOUNT_NOT_FOUND | accountId not found in org | | PLATFORM_ERROR | Generic platform-side error | | PLATFORM_DOWN | Platform API unavailable | | SUBREDDIT_REQUIRED | Reddit post missing subreddit | | SUBREDDIT_NOT_FOUND | Subreddit doesn't exist |
---
GET /api/v1/platforms
List all platforms + capabilities. Call this before composing content.
curl http://localhost:3000/api/v1/platforms -H "X-API-Key: sa_xxx"
GET /api/v1/platforms/:platform/capabilities
Check a specific platform's text limits, media types, rate limits.
curl http://localhost:3000/api/v1/platforms/x/capabilities -H "X-API-Key: sa_xxx"
---
Account Management
# List connected accounts
GET /api/v1/accounts
# Connect X via OAuth
POST /api/v1/accounts/connect/x
Body: { "redirectUri": "https://yourapp.com/callback" }
→ Returns: { "authUrl": "...", "state": "...", "instructions": "..." }
# OAuth callback
POST /api/v1/accounts/connect/x/callback
Body: { "code": "...", "state": "..." }
# Connect Bluesky (app password)
POST /api/v1/accounts/connect/bluesky
Body: { "handle": "user.bsky.social", "appPassword": "xxxx-xxxx-xxxx-xxxx" }
# Disconnect account
DELETE /api/v1/accounts/:id
# Check rate limits
GET /api/v1/accounts/:id/rate-limits
---
Webhooks
Get notified when posts succeed or fail:
# Register webhook
POST /api/v1/webhooks
Body: { "url": "https://your-agent.com/hook", "events": ["post_published", "post_failed"] }
Payload: ``json { "event": "post.published", "postId": "1234567890", "platform": "x", "url": "https://x.com/user/status/1234567890", "timestamp": "2026-03-25T03:35:00.000Z" } ``
Delivery: 3 retries with exponential backoff (1s → 5s → 30s). HMAC-SHA256 signed.
---
MCP Server (Claude Desktop / Cursor)
Outpost ships a built-in MCP server — use it with Claude Desktop, Cursor, or any MCP-compatible agent.
Step 1: Build the MCP server ``bash npm run build ``
Step 2: Add to your MCP config:
Claude Desktop (~/.claude_desktop_config.json): ``json { "mcpServers": { "outpost": { "command": "node", "args": ["/path/to/Outpost/dist/mcp/mcp-server.js"], "env": { "OUTPOST_API_KEY": "sa_xxx", "OUTPOST_BASE_URL": "http://localhost:3000" } } } } ``
Cursor (.cursor/mcp.json in your project or ~/.cursor/mcp.json globally): ``json { "mcpServers": { "outpost": { "command": "node", "args": ["/path/to/Outpost/dist/mcp/mcp-server.js"], "env": { "OUTPOST_API_KEY": "sa_xxx", "OUTPOST_BASE_URL": "http://localhost:3000" } } } } ``
Once published to npm, use npx instead: ``json { "mcpServers": { "outpost": { "command": "npx", "args": ["-y", "@outpost/mcp-server"], "env": { "OUTPOST_API_KEY": "sa_xxx" } } } } ``
Build first: npm run build
MCP Tools available:
| Tool | Description | |------|-------------| | publish_post | Publish to any platform | | list_accounts | List connected accounts | | check_platform_capabilities | Get text limits, media types, rate limits | | check_rate_limits | Current rate limit status for an account | | list_all_platform_capabilities | All platforms at once | | get_post_status | Check status of a published post |
---
Platform OAuth Setup
Each platform requires its own developer app. Add credentials to .env.
| Platform | Auth method | Setup URL | |----------|------------|-----------| | X (Twitter) | OAuth 2.0 PKCE | developer.twitter.com | | Reddit | OAuth 2.0 | reddit.com/prefs/apps | | Instagram | Meta OAuth | developers.facebook.com | | LinkedIn | OAuth 2.0 | linkedin.com/developers | | Threads | Meta OAuth | Same Meta app as Instagram | | Bluesky | App password | No setup needed — user provides app password |
⚠️ Instagram/Threads: Use the "Other/legacy" Meta app type, NOT the new use-case wizard (it auto-attaches deprecated scopes that get rejected).
⚠️ X OAuth: Add your callback URL to the Twitter developer app or OAuth will silently fail.
---
Self-Host with Docker
Deploy the full stack (app + postgres + redis) in 5 commands:
# 1. Clone the repo
git clone https://github.com/andrezani/outpost Outpost && cd Outpost
# 2. Copy and fill in credentials
cp .env.example .env
# Edit .env — add your social platform client IDs/secrets
# 3. Start everything
docker compose up -d
# 4. Seed your admin org + get API key
docker compose exec app npm run seed:admin
# 5. Open Swagger playground
open http://localhost:3000/api
The app container runs
prisma migrate deployautomatically on startup. Postgres and Redis data persist in named Docker volumes across restarts.
---
Development
# Run in watch mode
npm run start:dev
# TypeScript check (must be 0 errors before committing)
node node_modules/typescript/bin/tsc --noEmit -p tsconfig.json
# Regenerate Prisma client after schema changes
npx prisma generate
# Run tests
npm test
Pre-commit hook runs prisma generate + tsc --noEmit automatically.
---
License
MIT — see LICENSE.






