DEV Community

PipepostDev
PipepostDev

Posted on • Originally published at dev.to

Pipepost v0.8.0: LinkedIn + X posting from any MCP client

Pipepost is an MCP server that lets your AI assistant publish content end-to-end: SEO scoring, multi-platform publishing, and social broadcast. v0.8.0 adds the two surfaces that were missing — LinkedIn and X — so an MCP client can now reach all the developer-relevant networks without leaving the conversation.

What's in v0.8.0

linkedin_post

Posts to LinkedIn via the /v2/ugcPosts endpoint. On first call, Pipepost looks up your person URN from /v2/userinfo and caches it back to your config so subsequent calls skip the round trip. 3000 character limit enforced before the API call so you don't burn quota on a malformed post.

linkedin_post text="Shipping is the only feature that compounds."
Enter fullscreen mode Exit fullscreen mode

x_post

Single tweet or reply-chained thread via X v2 /tweets. OAuth 1.0a HMAC-SHA1 signing built in (the X v2 API still requires it for user-context writes). 280 grapheme limit per post — graphemes, not chars, so emoji don't overcount.

x_post text="One. Idea. Per. Tweet."
x_post posts=["thread starts here", "second tweet replies", "third closes"]
Enter fullscreen mode Exit fullscreen mode

The setup friction problem

LinkedIn and X both have OAuth flows that bury you in a forest of scopes, redirect URIs, and token exchanges. v0.8.0 ships scripts/linkedin-auth.mjs to collapse the LinkedIn flow into a single command:

LINKEDIN_CLIENT_ID=xxx LINKEDIN_CLIENT_SECRET=yyy pnpm run linkedin:auth
Enter fullscreen mode Exit fullscreen mode

It spins up a local HTTP server, opens your browser to LinkedIn's consent page, captures the redirect, exchanges the code for an access token, fetches your person URN, and prints a ready-to-paste setup command for Pipepost. No copy-pasting tokens between tabs.

Why a thread chainer

X's API doesn't have a "post a thread" endpoint — you post each tweet individually with reply.in_reply_to_tweet_id pointing at the previous one. x_post accepts a posts array and chains the replies for you, aborting cleanly if any post fails (so you don't end up with a half-published thread).

What I learned about both APIs while building this

LinkedIn: the modern way to identify yourself is OpenID Connect (openid profile scopes, /v2/userinfo returns the sub field, your URN is urn:li:person:<sub>). The old /v2/me endpoint requires the deprecated r_liteprofile scope. Use the new path.

LinkedIn (cont): posting from a company page requires w_organization_social instead of w_member_social, which gates behind LinkedIn Marketing Developer Platform approval (usually 1–4 weeks). v0.8.0 supports personal posting today; company posting will land when MDP approval comes through.

X: the v2 /tweets endpoint accepts JSON bodies but you sign the URL parameters (none, in this case) — the JSON body itself is NOT part of the signature base string. This trips up everyone implementing OAuth 1.0a for v2. The x.ts module in this repo handles it.

X (cont): encodeURIComponent does not percent-encode !, *, ', (, ) — but RFC 3986 (and OAuth 1.0a) requires them encoded. The signature will be wrong if you skip this. There's a one-line rfc3986() helper in the source.

Get it

npm install -g pipepost-mcp@0.8.0
Enter fullscreen mode Exit fullscreen mode

Or via the MCP Registry. Source on GitHub.

Pipepost is built in the open. If you ship MCP servers and want to compare notes on these patterns, the issues tracker on GitHub is open.

Top comments (0)