Skip to main content
Glama
pokakrisztian2

postlayer-connect

README.md
# postlayer-connect

**Let your AI post to your socials β€” an open MCP server for LinkedIn, X, Bluesky, Mastodon, Reddit, and more.**

`postlayer-connect` is a local [Model Context Protocol](https://modelcontextprotocol.io) server. Point any MCP client at it β€” Claude Desktop, Claude Code, Cursor, ChatGPT desktop β€” connect your social accounts with **your own** app credentials, and your assistant can publish posts and read analytics for you.

- Runs 100% locally. Your tokens never leave your machine.
- Uses **your** developer apps and **your** accounts. No middleman API, no per-post fees.
- Tokens are encrypted at rest (AES-256-GCM) in a local file.
- MIT licensed. Fork it, audit it, extend it.

```
you: "post this to LinkedIn and X: shipping day. the open MCP social server is live πŸš€"
AI:  βœ… posted to linkedin (id 7…)   βœ… posted to x (id 18…)
```

---

## 30-second quickstart

**1. Add it to your MCP client.** No install step β€” `npx` fetches and runs it.

Claude Desktop / Claude Code β€” add to your `claude_desktop_config.json` (or `.mcp.json`):

```json
{
  "mcpServers": {
    "postlayer-connect": {
      "command": "npx",
      "args": ["-y", "postlayer-connect"],
      "env": {
        "LINKEDIN_CLIENT_ID": "your_id",
        "LINKEDIN_CLIENT_SECRET": "your_secret"
      }
    }
  }
}
```

Only add the credentials for the platforms you want. Bluesky and Nostr need **none** β€” you connect them with an app password / key. The server boots fine with an empty `env` and tells you what each platform needs.

**2. Restart your client and ask it to connect an account:**

> "List the social platforms postlayer supports."
> "Connect my Bluesky β€” my handle is `you.bsky.social` and here's an app password."

**3. Post:**

> "Post 'hello world from my AI' to Bluesky."

That's it.

---

## Supported platforms

**Works now** β€” register your own app (a 5-minute, free, self-serve process), paste the keys, done. Bluesky and Nostr need no app at all.

| Platform | Connect with | What you register | Post analytics you get back |
|---|---|---|---|
| **LinkedIn** | OAuth | [LinkedIn app](https://www.linkedin.com/developers/apps) | likes, comments |
| **X / Twitter** | OAuth 1.0a | [X developer app](https://developer.x.com/en/portal/dashboard) (Read+Write) | impressions, likes, reposts, quotes, bookmarks, clicks |
| **Reddit** | OAuth | [Reddit app](https://www.reddit.com/prefs/apps) (type: web app) | score, comments, crossposts |
| **Mastodon** | OAuth | app on your instance (Preferences β†’ Development) | favourites, boosts, replies |
| **Bluesky** | App password | *nothing* β€” Settings β†’ App Passwords | likes, reposts, replies, quotes |
| **Nostr** | Private key (nsec) | *nothing* | β€” (no canonical analytics) |
| **Discord** | Bot token | [Discord app](https://discord.com/developers/applications) β†’ Bot | reaction count |
| **Telegram** | Bot token | @BotFather | β€” (Bot API exposes none) |
| **Threads** | OAuth | [Meta / Threads app](https://developers.facebook.com) | views, likes, replies, reposts, quotes |

> Threads works for you + testers in dev mode. Scaling it to *other* people's accounts needs Meta App Review.

**Needs your own approved app** β€” the connector code is complete and correct, but these platforms only allow programmatic posting through a developer app that has passed their review. Get your app approved, flip one env flag, and it works.

| Platform | Blocker | Flip when approved |
|---|---|---|
| **Instagram** | Meta App Review + Business Verification | `INSTAGRAM_APP_APPROVED=true` |
| **TikTok** | Content Posting API audit | `TIKTOK_APP_APPROVED=true` |
| **YouTube** | Google OAuth verification (sensitive scopes) + quota | `YOUTUBE_APP_APPROVED=true` |

Until then these tools return an honest, specific "here's exactly what to submit" message β€” never a fake success.

---

## The MCP tools

| Tool | What it does |
|---|---|
| `list_platforms` | Every platform, its status, the credentials it needs, and the analytics it returns. |
| `connect_account` | Start a connect. OAuth platforms return a URL to open in your browser; credential platforms (Bluesky, Nostr, Discord, Telegram) take the fields inline. |
| `list_accounts` | Show your connected accounts and their ids. |
| `post` | Publish text + optional media (local file path or URL) to an account. Per-platform `settings` (e.g. Reddit `{subreddit, title}`). |
| `get_analytics` | Normalized analytics for one post. A metric that's missing means the platform doesn't expose it β€” never a faked zero. |

### Example prompts

- *"Post this to LinkedIn and X, and attach `~/Desktop/launch.png`."*
- *"Submit this as a text post to r/SideProject with the title 'I built an open MCP social server'."*
- *"How did my last LinkedIn post do?"* (feed it the post id `post` returned)
- *"Connect my Mastodon on mastodon.social."*

---

## How the OAuth connect works (local)

Because this server runs locally with no public URL, it starts a tiny loopback listener to catch the OAuth redirect.

1. Register **`http://localhost:8790/callback`** as an authorized redirect URL in each OAuth app you create.
2. Call `connect_account` β†’ it returns an authorize URL.
3. Open it, approve, and the browser redirects back to the local listener, which exchanges the code and saves the account automatically.

Change the port with `POSTLAYER_OAUTH_PORT` (and `POSTLAYER_OAUTH_HOST`) if 8790 is taken β€” just register the matching URL.

---

## Configuration

Set these in your MCP client's `env` block, or in a `.env` file in the working directory (auto-loaded). See [`.env.example`](./.env.example) for the full list.

| Var | Purpose |
|---|---|
| `POSTLAYER_ENC_KEY` | Passphrase used to encrypt stored tokens (AES-256-GCM). **Recommended.** Generate with `openssl rand -base64 32`. If unset, a random key is generated once and saved (0600) in the data dir. |
| `POSTLAYER_DATA_DIR` | Where tokens + the key live. Default `~/.postlayer-connect`. |
| `POSTLAYER_OAUTH_PORT` / `POSTLAYER_OAUTH_HOST` | Local OAuth redirect listener. Default `localhost:8790`. |
| Per-platform app keys | e.g. `LINKEDIN_CLIENT_ID`, `X_API_KEY`, `REDDIT_CLIENT_ID`, … (see `.env.example`). |

### Where your tokens are stored

Connected-account tokens are written to `~/.postlayer-connect/tokens.json`. The secret fields (access + refresh tokens, app passwords, signing keys) are **encrypted at rest**; the file is created `0600`. Nothing is ever sent anywhere except directly to the platform's own API.

---

## Run it yourself / develop

```bash
git clone https://github.com/<you>/postlayer-connect
cd postlayer-connect
npm install
npm run build
node dist/index.js   # boots on stdio, prints its status to stderr
```

Node 20+. The server speaks MCP over stdio, so run it through an MCP client rather than typing at it directly.

---

## Want it fully managed + learning what works for you?

`postlayer-connect` is the open, run-it-yourself core. If you'd rather not manage apps and tokens β€” and want a system that **schedules, approves, and learns which posts actually perform** β€” that's [**Postlayer**](https://postlayer.io).

---

## License

MIT Β© 2026 Chris Poka / Designpulse. See [LICENSE](./LICENSE).

TDQS

A4.3/5.0

Scored across 5 tools

Disambiguation5/5

Each tool has a clear, distinct purpose: account connection, account listing, platform listing, posting, and analytics. No overlap or ambiguity between them.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern in snake_case (e.g., connect_account, list_accounts), with 'post' being a short but imperative verb, maintaining stylistic consistency.

Tool Count5/5

With 5 tools covering the core workflows of account connection, posting, and analytics, the count is well-scoped for the server's purposeβ€”neither too few nor too many.

Completeness3/5

The tool surface covers essential operations but lacks tools for disconnecting accounts, deleting or editing posts, and listing published posts, which are notable gaps for a social media management server.

Maintenance

ActivityStale
ResponsivenessNo issues