Content Distribution MCP
The Content Distribution MCP server enables publishing a single piece of content across multiple platforms with automatic adaptation, idempotency, scheduling, and state management. Here's what you can do:
Publish immediately — Send content variants to multiple channels at once (DEV.to, Hashnode, GitHub Discussions, Reddit, Bluesky, LinkedIn, Medium, Twitter). Idempotent: re-running with the same content ID and channel returns cached results without re-posting.
Schedule future posts — Queue variants with a
schedule_atdatetime for deferred delivery; immediate variants are published right away and scheduled entries are stored locally in YAML.Drain the scheduled queue — Fire all scheduled posts due at or before a given time boundary. Safe to run from cron; already-published pairs are automatically skipped.
Check publish status — Inspect the current state (published, queued, errored) of any content piece across all channels, filterable by content ID and/or channel. Read-only, no external calls.
Unpublish posts — Best-effort deletion of a live post on a target platform (e.g., DEV.to performs a soft delete; platforms without a delete API return a failure indicator gracefully).
Get per-channel hints — Retrieve metadata for any channel: character limits, Markdown support flags, tag vocabulary, and CTA placement rules. Useful for composing valid variants before publishing.
List configured profiles — Discover all credential-backed distribution profiles configured in the local YAML backend.
List subreddits — Browse the Subreddit Catalog with cooldown windows, flair vocabulary, and last-posted timestamps, optionally filtered by profile.
Enables publishing content to Bluesky with automatic adaptation to platform-specific constraints such as character limits and formatting.
Allows publishing articles to DEV.to with automatic adaptation to platform-specific constraints including formatting and tag vocabularies.
Enables publishing content to GitHub Discussions with automatic adaptation to platform-specific constraints.
Allows publishing articles to Hashnode with automatic adaptation to platform-specific constraints.
Enables publishing content to Medium via browser fallback, returning a compose URL for manual posting when direct API is unavailable.
Allows publishing content to Reddit with automatic adaptation, enforcement of subreddit rules, and support for flairs and cooldowns.
content-distribution-mcp
Publish your content everywhere—without rewriting for every platform.
A MCP server that distributes a single piece of content across 8+ channels (DEV.to, Hashnode, GitHub Discussions, Reddit, Bluesky, LinkedIn, Medium, Twitter) with automatic platform-specific adaptation, idempotent publishing, per-community anti-spam rules, and centralized state management.
The Problem It Solves
Creating and publishing content at scale is friction-heavy:
Different formats: Reddit strips formatting, Twitter has character limits, DEV.to supports embeds and rich media. Each needs customized copy.
Platform rules: Subreddits enforce cooldowns and flair requirements. Communities have posting patterns and automoderator gates. LinkedIn suppresses external links.
State chaos: Which posts went live where? What if a publish fails halfway? Did that Reddit post get auto-removed by spam filters?
This MCP handles distribution complexity. Write your core message once, generate platform-specific variants, publish everywhere safely.
Related MCP server: Pipepost
How It Works
Your agent generates channel-specific copy variants (rewritten titles, trimmed text, platform-appropriate tags, audience-matched tone).
This MCP publishes each variant with idempotency, OAuth, API retries, and scheduling—enforcing platform constraints automatically.
You control which platforms get what. The MCP returns per-channel hints (character limits, tag vocabularies, cooldowns) but leaves creative decisions to you.
No LLM calls inside. No walled-in agents. Just a clean API for multi-platform content distribution at scale.
Install
npx @automatelab/content-distribution-mcpOr add it permanently to your MCP host.
Wire into your MCP host
Claude Code — add to .claude/mcp.json:
{
"mcpServers": {
"content-distribution": {
"command": "npx",
"args": ["-y", "@automatelab/content-distribution-mcp"]
}
}
}Claude Desktop — add to claude_desktop_config.json:
{
"mcpServers": {
"content-distribution": {
"command": "npx",
"args": ["-y", "@automatelab/content-distribution-mcp"]
}
}
}n8n — use the MCP Client node, point it at npx @automatelab/content-distribution-mcp over stdio.
Cursor / Windsurf / any MCP host — same npx -y content-distribution-mcp pattern.
Configure credentials
The server reads credentials from a Distribution Profile stored in ~/.distribution-mcp/profiles.yaml:
# ~/.distribution-mcp/profiles.yaml
default:
credentials:
DEV_TO_API_KEY: "your-devto-api-key"
HASHNODE_TOKEN: "your-hashnode-token"
HASHNODE_PUBLICATION_ID: "your-pub-id"
GITHUB_TOKEN: "ghp_..."
GITHUB_DISCUSSION_REPO: "owner/repo"
REDDIT_CLIENT_ID: "..."
REDDIT_CLIENT_SECRET: "..."
REDDIT_USERNAME: "..."
REDDIT_PASSWORD: "..."
BLUESKY_IDENTIFIER: "you.bsky.social"
BLUESKY_PASSWORD: "..."
subreddits:
- ClaudeAI
- LocalLLaMAOnly set credentials for channels you intend to use. LinkedIn, Medium, and Twitter/X return needs_browser with a compose URL — no credentials needed.
MCP tool surface
Eight tools, dot-notation names form a navigable tree (post.*, channel.*, profile.*, subreddit.*). Every tool declares an outputSchema (callers can type-check responses) and MCP annotations (read-only / destructive / idempotent / open-world hints). No LLM calls inside the server.
Tool | Purpose |
| Immediate publish; idempotent on |
| Queue variants for |
| Fire all scheduled posts due now — run from cron |
| Per-channel state for a content piece or channel |
| Best-effort delete (DEV.to sets unpublished; others vary) |
| Per-channel metadata: char limits, Markdown support, tag vocab |
| Names of configured distribution profiles |
| Subreddit Catalog: cooldowns, flair vocab, last-posted |
v2.2.0 breaking change. Tools were renamed from flat names (
publish,schedule, ...) to dot-notation (post_publish,post_schedule, ...). Update any prompts, agent skills, or n8n nodes that referenced the old names.
Channels
Channel key | Tier | Auth |
| Auto |
|
| Auto |
|
| Auto |
|
| Auto-gated |
|
| Auto |
|
| Browser fallback | returns |
| Browser fallback | returns |
| Browser fallback | returns |
Example agent call
// post_publish tool
{
"content": {
"id": "n8n-webhook-setup@2026-05-20",
"title": "How to set up an n8n webhook",
"body_md": "...",
"tags": ["automation", "n8n", "tutorial"],
"canonical_url": "https://yourblog.com/n8n-webhook-setup",
"author": "You"
},
"variants": [
{
"channel": "devto:main",
"title": "How to set up an n8n webhook",
"body": "...",
"tags": ["automation", "n8n", "tutorial", "devops"],
"canonical_url": "https://yourblog.com/n8n-webhook-setup",
"extras": {}
},
{
"channel": "reddit:ClaudeAI",
"title": "Built a webhook automation with n8n",
"body": "Here's how I set it up...",
"tags": [],
"extras": { "flair": "Project" }
}
],
"profile_name": "default"
}Idempotency
Re-running post_publish with the same content.id + channel pair returns the existing live_url immediately without making another platform API call. Safe to retry on failure.
Scheduling
Variants with schedule_at (ISO-8601 with timezone, e.g. "2026-05-21T09:00:00+00:00") are stored in ~/.distribution-mcp/scheduled.yaml and fired on the next post_drain call. Run drain from cron:
# fire due posts every 5 minutes
*/5 * * * * npx -y content-distribution-mcp drainOr call the post_drain MCP tool directly from an agent.
Environment variables
Variable | Default | Purpose |
|
| State backend ( |
|
| Directory for YAML state files |
Requirements
Node.js 18 or later
Architecture
Agent (Claude Code / n8n / Cursor / any MCP host)
│ generates per-channel copy, calls MCP tools
▼
content-distribution-mcp (this package, stdio transport)
│ no LLM calls — pure I/O
├── adapters/ devto · hashnode · github-discussions · reddit · bluesky · browser
└── backends/ yaml (post log · profiles · schedule queue · subreddit catalog)Works with any MCP client
No Anthropic-specific code anywhere. Verify:
grep -ri "anthropic" node_modules/content-distribution-mcp/dist/ # returns nothingPart of the AutomateLab stack
agency-os — control plane
content-distribution-mcp — this package
automatelab.tech — blog and tutorials
License
MIT
Available Tools
8 toolschannel_hintsStatic per-channel metadataARead-onlyIdempotent
Return static per-channel metadata: character limits, Markdown support flags, tag vocabulary, and CTA placement rules. Side effects: read-only; no external HTTP calls; no auth needed. Fully deterministic — returns compile-time adapter constants. Use channel_hints before composing a variant body to understand channel constraints; use post_publish or post_schedule once you have a valid variant.
| Name | Required | Description | Default |
|---|---|---|---|
| channel | Yes | Channel platform name, e.g. 'devto', 'reddit', 'hashnode', 'bluesky'. Use the platform prefix only, not the full 'platform:account' form. |
Output Schema
| Name | Required | Description |
|---|---|---|
| tag_vocab | No | Canonical tag vocabulary; omitted when the channel accepts free-form tags. |
| max_length | No | Max post length in characters; omitted when the channel has no limit. |
| browser_only | Yes | True when posting requires the browser-fallback flow (no public API). |
| cta_placement | Yes | Where the CTA block lands on this channel. |
| supported_md_features | Yes | Markdown features the channel renders, e.g. 'links', 'code_blocks'. |
| canonical_url_supported | Yes | Whether the channel honours canonical_url natively. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and closed-world, so the safety profile is covered. The description still adds non-obvious context: no external HTTP calls, no auth required, and deterministic compile-time adapter constants, which tells the agent results can be cached and need no credentials.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, zero padding, and the core purpose plus returned fields are front-loaded before side effects and routing guidance. Every sentence carries distinct information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-value documentation is not required, yet the description still sketches the payload shape. Combined with explicit side-effect and sequencing notes, the definition is complete for a single-param lookup tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single 'channel' parameter is well documented with examples and the platform-prefix caveat. The description adds no additional parameter meaning, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb+resource ('Return static per-channel metadata') and enumerates exactly what comes back: character limits, Markdown support flags, tag vocabulary, CTA placement rules. It also implicitly separates itself from the post_* siblings by scoping itself to static, pre-composition data.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit sequencing guidance: 'use channel_hints before composing a variant body' and 'use post_publish or post_schedule once you have a valid variant.' Names the alternatives and the condition that selects them, so an agent can route correctly without inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
post_drainFire all scheduled posts due nowAIdempotent
Fire all scheduled posts due at or before the given time boundary. Side effects: makes external HTTP requests for each due entry; writes results to the YAML backend. Idempotent — already-published (content.id, channel) pairs are skipped; no-op when no entries are due. Safe to call from cron. Use post_drain on a recurring schedule to flush the queue; use post_publish or post_schedule to add new content; use post_status to inspect results after drain runs.
| Name | Required | Description | Default |
|---|---|---|---|
| now | No | ISO-8601 datetime boundary, e.g. '2026-05-21T09:00:00Z'; defaults to current UTC time when omitted. |
Output Schema
| Name | Required | Description |
|---|---|---|
| results | Yes | Per-variant results, one entry per input variant in the same order. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (openWorldHint, idempotentHint, destructiveHint=false), and the description adds real operational context beyond them: external HTTP requests per due entry, YAML backend writes, the exact idempotency key ('already-published (content.id, channel) pairs are skipped'), and the no-op case. Cron-safety is also disclosed explicitly.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the action, then side effects, then routing. Every sentence carries distinct information (what it does, what it touches, when to pick it over alternatives) with no repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained. For a single-optional-parameter trigger tool, the description supplies the side effects, idempotency semantics, failure-relevant behavior, and sibling routing an agent needs to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single 'now' parameter already documents its ISO-8601 format and default behavior. The description only echoes 'the given time boundary' without adding format or edge-case detail, so the schema does the heavy lifting and the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource with precise scope: 'Fire all scheduled posts due at or before the given time boundary.' The routing sentence separates it from post_publish/post_schedule (adding content) and post_status (inspecting results), so an agent can distinguish it from every sibling without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly says when to use it ('on a recurring schedule to flush the queue') and names the alternatives for adjacent jobs ('use post_publish or post_schedule to add new content; use post_status to inspect results'). Both the trigger and the exclusions are stated, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
post_publishPublish variants to one or more channels immediatelyAIdempotent
Publish one or more channel variants immediately. Side effects: makes external HTTP requests to each channel platform; writes publish state to the local YAML backend; requires valid credentials in the named profile. Idempotent on (content.id, channel) — re-running with the same IDs returns cached state without re-posting. Use post_publish for immediate-only delivery; use post_schedule when any variant needs a future schedule_at; use post_drain to flush a previously built queue.
| Name | Required | Description | Default |
|---|---|---|---|
| content | Yes | Content piece to publish: stable id (idempotency key), title, body_md, tags, and optional cover_image / canonical_url / cta_block / author fields. The id + channel pair is the deduplication key — the same id will not be re-posted. | |
| variants | Yes | One or more channel-specific publish targets. Each entry specifies the channel slug (e.g. 'devto:main', 'reddit:ClaudeAI'), the adapted title and body, optional schedule_at for future delivery, and channel extras such as flair. Use channel_hints to check per-channel constraints before composing. | |
| profile_name | Yes | Name of the distribution profile (credentials store). Use profile_list to discover available names. |
Output Schema
| Name | Required | Description |
|---|---|---|
| results | Yes | Per-variant results, one entry per input variant in the same order. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by disclosing concrete side effects: outbound HTTP requests to each channel platform, writes to the local YAML publish state, and a requirement for valid credentials in the named profile. It also states the exact idempotency key (content.id, channel) and that re-runs return cached state without re-posting, which is far more specific than the generic idempotentHint=true annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four tight sentences, each earning its place: purpose, side effects, idempotency semantics, and sibling routing. Front-loaded with the action and scope before the caveats.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need no explanation, and the description still covers mutation scope, auth prerequisites, idempotency, and alternatives. Nothing an agent needs to invoke this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the nested objects are richly documented, so the schema carries the parameter burden. The description only points to helper tools (channel_hints, profile_list) rather than adding syntax or format meaning beyond the schema, making the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (publish), resource (channel variants), and immediacy constraint in the first sentence. The immediacy qualifier distinguishes it cleanly from post_schedule and post_drain without needing the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes: use post_publish for immediate-only delivery, post_schedule when any variant needs a future schedule_at, post_drain to flush a built queue. Names the alternatives and the condition that selects each, so no inference is required.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
post_scheduleSchedule variants for future publishingAIdempotent
Enqueue channel variants with schedule_at for future publishing; variants without schedule_at are published immediately. Side effects: writes entries to the local YAML schedule store; makes external HTTP requests for any immediately-published variants; requires credentials in the named profile. Idempotent on (content.id, channel). Use post_schedule when any variant needs a future publish time; use post_publish for all-immediate delivery; use post_drain to process the scheduled queue later.
| Name | Required | Description | Default |
|---|---|---|---|
| content | Yes | Content piece to publish: stable id (idempotency key), title, body_md, tags, and optional cover_image / canonical_url / cta_block / author fields. The id + channel pair is the deduplication key — the same id will not be re-posted. | |
| variants | Yes | One or more channel-specific publish targets. Each entry specifies the channel slug, the adapted title and body, and optionally schedule_at (ISO-8601 with timezone) for future delivery. Variants without schedule_at are published immediately; variants with schedule_at are queued for post_drain. Use channel_hints to check per-channel constraints. | |
| profile_name | Yes | Name of the distribution profile (credentials store). Use profile_list to discover available names. |
Output Schema
| Name | Required | Description |
|---|---|---|
| results | Yes | Per-variant results, one entry per input variant in the same order. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnly=false, openWorld=true, idempotent=true, destructive=false. The description goes well beyond that by disclosing concrete side effects (writes to the local YAML schedule store, external HTTP calls for immediately-published variants), a credential requirement via profile_name, and the precise idempotency key (content.id, channel).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four tight sentences, front-loaded with the core behavior, then side effects, then routing to siblings. Every sentence carries distinct information — no filler or repetition of the title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 3-parameter mutation tool with nested objects, an output schema, and rich annotations, the description covers purpose, side effects, prerequisites, idempotency, and sibling routing. An agent has everything needed to invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents content, variants, channel, schedule_at, extras, etc. in detail. The description restates the schedule_at/immediate split but adds no format or override semantics beyond what the schema provides; baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('enqueue channel variants with schedule_at for future publishing') and immediately clarifies the boundary condition that variants lacking schedule_at publish immediately. This distinguishes it cleanly from post_publish and post_drain without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly gives when-to-use ('any variant needs a future publish time') and names both alternatives with their selecting conditions: post_publish for all-immediate delivery and post_drain to process the scheduled queue later. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
post_statusRead publish state for content piecesARead-onlyIdempotent
Return publish state for content pieces. Filters by content_id, channel, or both; returns all entries when neither is given. Side effects: read-only; no external HTTP calls; no auth needed. Deterministic given unchanged backend state. Use post_status to inspect what has been published, what is queued, or what errored; use post_publish, post_schedule, or post_drain to change state.
| Name | Required | Description | Default |
|---|---|---|---|
| channel | No | Filter to a specific channel slug, e.g. 'devto', 'reddit:ClaudeAI'; omit to return state for all channels. | |
| content_id | No | Filter to a specific content piece by its stable ID; omit to return state for all content. |
Output Schema
| Name | Required | Description |
|---|---|---|
| results | Yes | Publish-log entries matching the filter. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, and the description adds meaningful extra context beyond them: no external HTTP calls, no auth required, deterministic given unchanged backend state. This is exactly the kind of behavioral detail the schema and annotations don't convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with the return/filter behavior, then side effects, then sibling routing. No redundant or filler content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema covering return values and annotations covering safety, the description adds the scoping, side-effect, and routing details an agent needs. Nothing essential to correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds the combined-filter semantics ('content_id, channel, or both; returns all entries when neither') that clarify how the two optional params interact, slightly exceeding what the schema states per-field.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Return publish state for content pieces') and defines the filtering scope (content_id, channel, or both; all entries otherwise). It clearly separates itself from the mutating siblings it names (post_publish, post_schedule, post_drain).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit use cases ('inspect what has been published, what is queued, or what errored') and routes the agent to the correct alternative tools for state changes. The when-to-use vs when-to-change distinction is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
post_unpublishRetract a published post (best-effort)ADestructive
Best-effort delete of a published post on the target platform. Side effects: makes an external HTTP DELETE or update request; DEV.to sets published=false (soft delete); platforms without a delete API return success=false without error. Non-idempotent — calling on an already-deleted URL may return a platform 404. Use post_unpublish to retract a live post; use post_status first to obtain the live_url; use post_publish to re-publish after an unpublish.
| Name | Required | Description | Default |
|---|---|---|---|
| channel | Yes | Channel slug the post was published to, e.g. 'devto', 'hashnode', 'reddit:ClaudeAI'. | |
| live_url | Yes | URL of the live published post to retract, e.g. 'https://dev.to/user/post-slug'. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | Yes | Platform error message; null on success. |
| success | Yes | Whether the retract succeeded on the platform side. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructive, non-idempotent, and open-world, but the description adds substantial context beyond them: it describes the actual side effect (external HTTP DELETE or update request), platform-specific behavior (DEV.to soft-deletes via published=false; platforms lacking a delete API return success=false without error), and the non-idempotent 404 case. This is exactly the behavioral detail structured fields cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action, then side effects, then usage routing. Every clause carries distinct information — no filler, no repetition of the title or schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-value explanation is unnecessary; the description instead covers the risk profile an agent needs (soft delete, silent success=false, 404 on repeat). Complete for a destructive cross-platform tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with clear per-parameter descriptions (channel slug, live_url format), so the schema already carries parameter meaning. The description references live_url via post_status but adds no syntax or format detail beyond the schema, making the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Best-effort delete of a published post on the target platform') and immediately frames the scope as retracting a live post. An agent can distinguish it from post_publish, post_status, and post_schedule without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent: use this to retract a live post, use post_status first to obtain the live_url, and use post_publish to re-publish afterward. It names both the prerequisite and the reverse operation, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
profile_listList configured distribution profilesARead-onlyIdempotent
Return all distribution profile names configured in the YAML backend. Side effects: read-only; no external HTTP calls. Deterministic given backend state. Use profile_list to discover available profiles before calling post_publish, post_schedule, or subreddit_list; then pass the chosen name as profile_name.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| profiles | Yes | Configured distribution profile names. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, openWorldHint=false, and destructiveHint=false, so the safety profile is covered. The description adds genuinely new context beyond them: no external HTTP calls and deterministic results given backend state, which tells the agent the call is cheap and stable to repeat. It does not cover item shape, but the output schema handles that.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the return value, then side effects, then usage, all in a compact block. The 'read-only' note mildly duplicates the readOnlyHint annotation, costing a little redundancy, but the rest of the sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a no-arg list tool with a full annotation set and an output schema, the description supplies everything needed: what it returns, where it reads from, determinism, and how the result feeds other tools. Return-value detail is correctly left to the output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4. The description still helpfully explains the role of the value it produces (profile names, consumed as profile_name elsewhere) without inventing parameter semantics that don't exist.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Return all distribution profile names') and scopes it to the 'YAML backend', which clarifies it is not scanning external systems. An agent can distinguish it from the post_* siblings, which perform actions rather than enumerate profiles.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly tells the agent when to use it ('to discover available profiles before calling post_publish, post_schedule, or subreddit_list') and what to do with the result ('pass the chosen name as profile_name'). This is a full when-to-use plus downstream wiring, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
subreddit_listList Subreddit Catalog entriesARead-onlyIdempotent
Return all subreddits in the Subreddit Catalog with cooldown windows, flair vocabulary, and last-posted metadata. Optionally filtered to subreddits allowed by the named profile. Side effects: read-only; no external HTTP calls. Deterministic given backend state. Use subreddit_list to select a subreddit and obtain flair IDs before composing a reddit: channel variant; pass flair in variant.extras.flair.
| Name | Required | Description | Default |
|---|---|---|---|
| profile_name | No | Optional profile name to filter subreddits to those allowed by that profile; omit to return the full catalog. |
Output Schema
| Name | Required | Description |
|---|---|---|
| subreddits | Yes | Subreddit Catalog entries matching the filter. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false and openWorldHint=false. The description goes beyond that by adding 'no external HTTP calls' and 'Deterministic given backend state,' which are useful operational guarantees. It does not cover error/empty-catalog behavior, so it is not exhaustive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with what is returned, then the optional filter, then the intended workflow. Slightly redundant with the annotations ('Side effects: read-only') but overall dense and without filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-value explanation is not strictly required, yet the description still names the key returned fields. Combined with the workflow guidance and the single fully-documented parameter, an agent has what it needs; only edge behavior (empty catalog, invalid profile_name) is unaddressed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so profile_name's filtering semantics are already fully documented in the schema. The description restates the same filter behavior (subreddits allowed by the named profile) without adding format, matching, or precedence detail beyond the schema, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Return all subreddits in the Subreddit Catalog') and enumerates the payload fields (cooldown windows, flair vocabulary, last-posted metadata). It is clearly distinguishable from the post_* and profile_list siblings, which operate on posts and profiles rather than the subreddit catalog.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to use it: 'Use subreddit_list to select a subreddit and obtain flair IDs before composing a reddit: channel variant' and where to put the result (variant.extras.flair). It also states the optional profile filter and that omitting it returns the full catalog, leaving no ambiguity about invocation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
16 tool updates
v2.1.1- Added
channel_hints - Removed
drain - Removed
hints - Removed
list_profiles - Removed
list_subreddits - Added
post_drain - Added
post_publish - Added
post_schedule - Added
post_status - Added
post_unpublish - Added
profile_list - Removed
publish - Removed
schedule - Removed
status - Added
subreddit_list - Removed
unpublish
8 tool updates
v2.1.0- First observed
drain - First observed
hints - First observed
list_profiles - First observed
list_subreddits - First observed
publish - First observed
schedule - First observed
status - First observed
unpublish
TDQS
Scored across 8 tools
Each tool maps to a distinct action or data source, and descriptions explicitly distinguish publish, schedule, drain, status, and unpublish flows. No two tools appear interchangeable.
The five mutating/state tools use a clear post_* prefix, but the read-only metadata tools use noun-first names such as profile_list, subreddit_list, and channel_hints. This creates two naming families, though the overall scheme remains readable and mostly predictable.
Eight tools is well-scoped for a content-distribution workflow covering immediate publishing, scheduling, queue draining, status inspection, unpublishing, and channel/profile discovery. No tool feels redundant.
Core lifecycle is covered: publish, schedule, drain, status, unpublish, plus profile, channel, and subreddit metadata. Notable gap: no explicit cancel or edit operation for scheduled queue entries, and no content-listing tool, though most workflows can work around these.
Maintenance
Related MCP Connectors
Publish and schedule content across supported platforms, with publishing state and per-platform adaptation. Built by AutomateLab. Product and documentation: https://automatelab.tech/products/mcp/content-distribution-mcp/
Schedule and analyze posts on 12 networks, incl. Bluesky, Mastodon and Telegram, from any AI agent
1A free social media scheduler your AI tools can post through — LinkedIn, Bluesky, Mastodon, YouTube.
Draft, schedule, and analyze content for Substack, Medium, LinkedIn, X, Bluesky, and Threads.
Related MCP Servers
- FlicenseNot gradedqualityNot gradedmaintenanceAn MCP server that repurposes text or URL content into platform-optimized posts for Twitter, LinkedIn, Instagram, and newsletters using AI. It enables users to automatically transform articles and blog posts into engagement-ready social media threads and professional captions.-
- AlicenseAqualityCmaintenanceCross-publishes a single markdown draft to 5 CMS platforms (dev.to, Hashnode, Ghost, WordPress, Medium) and 4 social networks (Bluesky, Mastodon, LinkedIn, X) from any MCP client, with built-in SEO scoring, schema.org JSON-LD, and canonical URL handling so cross-posts compound search rankings instead of competing.2967 npm5MIT
- AlicenseAqualityCmaintenanceAutomateLab n8n MCP helps AI agents generate and lint workflows, diagnose failed executions, and manage live n8n instances. Product and documentation: https://automatelab.tech/products/mcp/n8n-mcp/12107 npm14MIT
- AlicenseNot gradedqualityDmaintenanceCampaign-driven social engagement MCP server for authentic developer community interaction (Dev.to, Bluesky, Twitter, Reddit) with a streamlined scout-draft-strike pipeline minimizing LLM round trips.MIT