Outpost

andrezani/outpost
0 starsMITCommunity

Install to Claude Code

This server doesn't publish a one-line install command. Follow the setup in the source repository.

Summary

Social media API and MCP server for AI agents that enables publishing to X, Instagram, LinkedIn, Reddit, Bluesky, and Threads from a single endpoint.

README.md

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 + agentHint so 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 endpointPOST /api/v1/publish posts 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 code
  • packages/mcp/ — canonical in-repo MCP package
  • packages/outpost-mcp-standalone/ — legacy standalone MCP repo imported for history/reference
  • apps/landing/ — static marketing site imported from the old outpost-landing repo

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 deploy automatically 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.

Related MCP servers

Browse all →