Free · MIT licensed

content-distribution-mcp

An MCP server that publishes one piece of content to eight developer-community channels with idempotent state, per-subreddit anti-spam rules, and dual YAML or Notion backends. No LLM calls in the server. Your agent writes the copy, the MCP does the I/O.

Eight channels, three publish tiers

The server ships eight channel adapters. Five publish through native APIs; three use Playwright to pre-fill the compose form when the platform's API is paid, locked-down, or rate-limited to uselessness.

Channel Tier Notes
devto auto Forem API v1. Native canonical_url so your blog stays the SEO origin.
hashnode auto GraphQL. Native originalArticleURL field. Publication-scoped tokens.
github_discussions auto GraphQL per-repo. Footer link for canonical (no native field).
bluesky auto atproto SDK. Canonical link appended to post text. App-password auth.
reddit auto-gated Per-subreddit cooldown, 5/day global cap, self-promo ratio, flair resolution. Pre-flight refuses posts that would violate sub rules.
medium_browser manual Playwright pre-fill plus batched-tab UX. Operator clicks Publish; mark_live CLI records the URL.
linkedin_browser manual Personal feed and company-admin compose. Plain-text draft, copy-paste workflow, mark_live flip.
twitter_browser manual Free-tier API is unusable. Plain-text draft plus pre-filled compose URL, mark_live records the tweet.

What it gives your agent

Eight MCP tools. The agent calls publish or schedule with one content envelope plus per-channel variants. The MCP handles state, idempotency, retries, and platform quirks.

Tool Purpose
publish Immediate publish across the variants you supply. Idempotent on (content_id, channel): re-running with the same envelope is a no-op.
schedule Queue variants for schedule_at timestamps. Stored in the state backend until drain picks them up.
drain Fire any due scheduled posts. One-shot and cron-friendly. Skips items that are already live.
status Per-variant state for one content piece: pending, live, failed, needs_browser, with URLs and error context.
unpublish Best-effort delete on DEV.to and GitHub Discussions. Reddit is honor-system (no API delete). Browser channels are operator-driven.
hints Static per-channel metadata: character limits, tag vocabulary, canonical-URL support, recommended posting times. The agent decides what to do with them.
list_profiles Returns the Distribution Profiles configured in your backend (token sets, default tags, posting cadences).
list_subreddits Returns the curated Subreddit Catalog: name, rules, flair vocabulary, cooldown, allowed self-promo ratio.

What makes it different

Idempotent on (content_id, channel)

Every publish call claims a key in the state backend before hitting the API. Network blip on attempt 47? Re-run the same envelope, get the same URL back. No double-posts, no duplicate Reddit threads, no embarrassing retries.

Reddit anti-spam pre-flight

Per-subreddit cooldown, 5-posts-per-day global cap, 10-to-1 content-to-self-promo ratio, flair resolution against the live sub config. The MCP refuses the post before it offends the mods, not after.

Browser fallback where APIs are hostile

Medium's API is partner-only. LinkedIn's is enterprise-gated. Twitter's free tier is unusable. For those, the MCP writes a clean draft, opens the compose form with fields pre-filled via Playwright, and you click Publish. mark_live records the URL.

Zero LLM calls in the server

Grep src/ for "anthropic". You'll find nothing. The host process supplies copy, credentials, and decisions. The MCP supplies idempotent I/O. Works with any model, any host, any pipeline.

Dual backend: YAML local, Notion team

Solo developer? YAML files in ~/.distribution-mcp/, zero config. Agency or team? Three Notion databases for Distribution Profiles, Subreddit Catalog, and Post Log, with URL write-back to source tasks. Same Protocol, swap with one constructor argument.

Works in any MCP host

stdio or SSE transport. No Anthropic-specific code. Tested against Claude Code, n8n's MCP Client node, Cursor, and the plain mcp Python client. The skill that ships with the repo is optional; the protocol is universal.

Install in 3 steps

  1. Install the PyPI package (requires Python 3.11+) pip install content-distribution-mcp Optional extras for browser channels: pip install content-distribution-mcp[browser] then playwright install chromium. For Bluesky: pip install content-distribution-mcp[bluesky].
  2. Add the server to your MCP host config (.claude/mcp.json for Claude Code, equivalent for Cursor, n8n MCP Client node, etc.)
    {
      "mcpServers": {
        "content-distribution": {
          "command": "content-distribution-mcp",
          "args": ["serve"],
          "env": {
            "DEVTO_API_KEY": "...",
            "HASHNODE_API_KEY": "...",
            "BLUESKY_HANDLE": "you.bsky.social",
            "BLUESKY_PASSWORD": "app-password",
            "REDDIT_CLIENT_ID": "...",
            "REDDIT_CLIENT_SECRET": "...",
            "REDDIT_REFRESH_TOKEN": "..."
          }
        }
      }
    }
    Only the credentials for the channels you actually use need to be set. Browser channels (Medium, LinkedIn, Twitter) need no env vars; they run via Playwright on demand.
  3. Restart your MCP host. The eight content-distribution tools appear. From your agent, call publish with one content envelope and a variants list.

Works with Claude Code, Claude Desktop, Cursor, n8n via the MCP Client node, plain Python via the mcp client library, and any custom integration that speaks MCP over stdio or SSE. Full reference: the GitHub readme and spec.

FAQ

What does it cost?
The MCP is MIT-licensed and free. You pay only for your agent's model usage and any platform-specific costs on the channels themselves (most are free for non-paid posting; Reddit, DEV.to, Hashnode, Bluesky, GitHub Discussions all have free posting tiers).
Why not just use Buffer or Hootsuite?
Those are scheduling UIs for marketing teams. This is an MCP server for AI agents. Different shape: the agent generates per-channel copy in chat, calls publish once, and the MCP handles every platform's quirks (Reddit cooldowns, Bluesky's 300-char limit, Medium's missing API) in one round trip.
Do I need a Notion account?
No. The YamlBackend stores everything in four YAML files in ~/.distribution-mcp/. Zero configuration. The NotionBackend is for agency or team use; it provisions three databases and writes published URLs back to source tasks. Both implement the same Protocol; you swap with one constructor argument.
How does the Reddit anti-spam logic work?
Each subreddit in the catalog has a cooldown (e.g. one self-link per week), a flair vocabulary, and a content-to-self-promo ratio. Before posting, the MCP checks the Post Log for cooldown violations and the day's running count against the global 5-per-day cap. If the post would violate any rule, the adapter refuses with a structured error. The agent then either reschedules, picks a different sub, or asks you to relax the rule.
What does it not do?
It doesn't write copy. It doesn't pick subreddits for you (the agent does that against list_subreddits). It doesn't game algorithms. It doesn't run analytics. It doesn't auto-follow, auto-DM, or auto-reply. It does one job: take a finished piece of content plus per-channel variants and route them with idempotent state.

Want it wired into your distribution pipeline?

We use content-distribution-mcp daily to publish our own posts and tools across the developer-community channels. If you want it set up for your stack, integrated with your CMS, or a full agent pipeline built end to end, we can do that.

Get in touch