Building a Social Publishing MCP Server: What We Learned
We get asked a fair amount, mostly by other builders, how we approached designing ReplyNodes' MCP server. Some of it was straightforward; some of it we got wrong on the first pass. Notes below.
Start from workflows, not from your data model
The obvious first instinct is to expose your existing REST resources as MCP
tools 1:1 — get_post, create_post, update_post, delete_post. We
tried that early on and it produced a tool surface that was technically
complete and practically useless: an agent given create_post has no idea
it's supposed to check character limits per platform, or that this
particular channel requires approval before anything goes live.
The fix was designing tools around the actual workflow steps — draft_post
(handles per-channel formatting), request_approval (only callable on
drafts, routes to the right reviewer), publish_post (only callable on
approved drafts, or on channels configured for auto-publish) — rather than
around database operations. See
Agent-native vs. API-first: what's actually different
for the reasoning behind this, and the full tool list in the
API reference.
Put guardrails in the tool, not in documentation
Early versions had a publish_post tool with a docstring warning "only call
this after approval is granted for approval-required channels." That's a
prompt-injection-shaped hole waiting to happen, and also just unreliable —
models don't reliably follow docstring caveats under all conditions. We
moved the check server-side: publish_post returns an error if the channel
requires approval and none exists, full stop. The agent can't be talked
into skipping it because there's no code path that allows it. Full detail
in Approval workflows for AI-generated social content.
Keep the tool count small and the descriptions precise
We initially over-decomposed — separate tools for get_channel_by_id,
get_channel_by_name, list_all_channels, list_active_channels. Most
agents did fine picking the right one, but it added surface area for
mistakes and made the tool list harder to reason about. Consolidating into
fewer tools with clear parameters (list_channels(status?: "active" | "all"))
reduced errors without losing functionality.
Test with the agents your users will actually connect
MCP is a standard, but agents differ in how aggressively they call tools, how they handle tool errors, and how much they retry. We test against Claude Code, ChatGPT, and a couple of other MCP clients specifically, rather than assuming "MCP-compliant" means "behaves identically everywhere." If you're building your own MCP server, this is worth doing before you ship — see our documentation for the tool schemas we settled on, or read about what MCP actually is if you're earlier in the process than we were.