mcp-content-ops
# mcp-content-ops
An MCP server that lets an agent work with CMS content. The tools are the boring part —
search, read, create a draft, set a field, publish. What took the thinking is what happens
before any of them run.
Most content MCP servers we have looked at hand the model an API client and a credential with
whatever permissions the integration account happens to have, which in a CMS is usually
everything. The demo works. Then someone asks the agent to "tidy up the product pages" and it
publishes forty drafts, because nothing in the system ever said it could not.
## The scoping
Four gates, in order, and none of them live in the tool schema:
1. **Argument validation** against the published schema. Unknown properties are rejected rather
than dropped — a model that invents an argument has misunderstood the tool, and dropping it
quietly hides that.
2. **Deny by default.** Writes are off unless config turns them on. There is no permissive
default anywhere in `Policy`.
3. **Type and field allowlists.** A type being readable does not make it writable, and a
writable type does not make every field on it writable.
4. **Structured audit** of every call, allowed or refused, with the reason.
The type a call is judged against comes from the stored item, never from the arguments. Letting
the caller assert what kind of thing it is editing is letting the caller pick which policy
applies.
A refused call comes back as a normal tool result with `isError` set, not a JSON-RPC error. The
model should see why it was refused and adapt; a protocol error means the client is broken,
which is a different conversation.
## Running it
```
pip install -e ".[dev]"
python -m content_ops.server policy.example.json
pytest -q
```
The CMS behind it is an in-memory stub in `cms.py` — four methods, swap it for your content API.
## What it does not do
No delete tool, on purpose. No resources or prompts, only tools. No auth: this is a stdio server
and the trust boundary is the process that launched it. The schema validator covers the subset
our own tool schemas use rather than all of JSON Schema.
## Why not use an SDK
The MCP Python SDK is fine and for a larger server it is the right call. This one implements
three methods over stdio, and the wire format is small enough that a dependency moving at the
pace the SDKs currently move was the bigger risk.
TDQS
Scored across 5 tools
The tools are mostly distinct: search, get, create, update, publish. Minor overlap: get_content vs search_content could be confused but descriptions clarify one is for exact retrieval and the other for substring search.
All tool names follow a consistent verb_noun pattern (search_content, get_content, create_content, update_content_field, publish_content). The action verbs are clear and uniform.
5 tools is well-scoped for a content operations server. Each tool covers a distinct lifecycle step: search, read, create, update, publish. No redundancy or excess.
Covers basic search/read/create/update/publish workflow, but missing delete_content (or archive), and possibly list/summary operations. Update is limited to one field at a time, which may be restrictive, but the core workflow is covered.