What We Learned Building an MCP Server for a CMS
We built a 30-tool MCP server for our CMS. Here's what we learned about tool count, batching, and token cost along the way.

Draftbase's MCP server ships 30 tools. The real lessons weren't about the CMS: every tool is prompt real estate, batching beats create-then-patch, and every workaround an agent has to discover on its own should be written into the tool description instead.
We built an MCP server for Draftbase (apps/mcp). It lets an agent like Claude manage content the same way a person does, through the API. Thirty tools now, covering templates, entries, media, and MDX components. Most of what we got wrong on the way there wasn't about the CMS. It was about the token budget of the agent calling it.
Tool Count Is a Cost, Not a Feature
Our first instinct was to expose the backend one-to-one. Every REST endpoint became a tool. That's the wrong model. Every tool we register adds its full schema and description to every conversation an agent has with the server. That's true whether the tool gets called or not. A CMS has dozens of endpoints; not all of them earn a permanent seat in every prompt.
We ended up close to a one-to-one mapping anyway. list_templates, create_template, update_template, delete_template, and the same four-shape pattern repeated for entries, media, and MDX components. But we got there on purpose, not by default. Each tool's description carries real instructions, not just a name. list_entries's description tells the model that long field values truncate at 300 characters. It also names get_entry as the way to fetch the full value. That's cheaper than the model discovering the truncation by trial and error, burning a wasted round trip to find it out.
Batching Beats Create-Then-Patch
create_template takes every field definition in one call. Name, fields, and an optional title field, all at once. We considered a create-then-patch flow instead, where an agent creates an empty template and adds fields one at a time. We rejected it. A content model with fifteen fields would cost fifteen extra round trips. Each one is a full request and response cycle through the model. One well-designed call reaches the same end state directly. The tool's own description says as much. "Define all fields up front rather than creating then patching." We didn't leave that lesson to be learned by trial. We put it in the schema the model reads first.
The same logic drove batch_delete_entries and batch_set_entry_status. Deleting fifty entries one at a time isn't just slow. It risks hitting the API's own rate limit mid-batch. A rate-limited agent then has to figure out backoff and retry logic on its own. One call with an array of ids reports success or failure per id and never touches the limit.
What We Got Wrong
We shipped confirm_media as a required step after uploading an asset. Get a presigned URL, upload to it, then call confirm_media to attach alt text and tags. In practice, that third call fails more often than it should. The asset gets reprocessed into a different storage key than the one the upload targeted. The id returned by get_upload_url stays valid regardless, so the workaround is simple: skip confirm_media and use that id directly. But we shipped a required-feeling step that isn't actually required. Every agent that hits the failure has to find the workaround on its own, instead of the tool description just saying so upfront. That's a description we should fix, not a workaround callers should have to reinvent.
The Secret-Scrubbing Tax
submit_feedback runs every text field through a pattern first. It redacts anything shaped like an API key, a JWT, or a bearer token, before it reaches our logging pipeline. That's not free. It's a regex scan on every feedback payload, just in case a caller pastes a snippet with a live credential in it. We added it because agents debugging an integration paste whatever's in front of them, credentials included. A support ticket is not where those belong. It's a small cost per call. It's a real one if feedback volume ever gets large enough for the regex to show up in a profile.
Tool Granularity, Revisited
The real lesson wasn't about MCP specifically. It's the same one that applies to any API a model calls directly. Every tool is prompt real estate. Every round trip is a wasted turn, if the call could have been shaped bigger. And every workaround an agent has to discover on its own is one we should have written into the tool's description instead. Our MCP server ships thirty tools now. The number matters less than whether each one earns its place.
Ship content that's built to be found
Draftbase generates schema, structured data, and a fast MDX editor for every post.
Frequently asked questions
How many tools does the Draftbase MCP server have?
Thirty, covering templates, entries, media, and MDX components.
Why does tool count matter for an MCP server?
Each tool adds its schema and description to every chat, even when unused. More tools mean a bigger prompt every time.
Why does create_template take all fields in one call?
A create-then-patch flow costs one round trip per field. One call reaches the same result directly.
Why do entries have batch tools?
Deleting or updating many entries one at a time can hit a rate limit. One batch call reports success per row instead.
What went wrong with the media upload flow?
The confirm step often fails because the asset gets a new storage key. The upload's own id still works, so that step can be skipped.
Samer is a software engineer and entrepreneur, founder of Draftbase and Ezi Home Services, building technology that simplifies home services. Passionate about software, APIs, automation, and creating products that solve real-world problems.


