Articles/Detail

Building an MCP Server People Actually Use

17/07/2026 (edited)
Tech
1565 Words
8Min read

Most MCP servers are an API wearing a new hat.

Someone takes the endpoints they already have, wraps them in the protocol, ships it, and calls it AI-ready. Then they are surprised when no customer’s AI can actually drive the thing without falling over.

The protocol was the easy part. The hard part is the shape. And the shape is where almost everyone gets it wrong.

I have built one that people use to let their own AI create things in the product without ever touching the interface. Here is what I learned about the difference between an MCP server that exists and one that works.

First, what this actually is

Quick grounding, because the acronym does a lot of hiding.

Model Context Protocol is a standard that lets a language model discover a set of tools and call them. An MCP server is your software, exposed as those tools.

The payoff is real. A customer points their own AI at your server, and now their AI can do things in your product directly. Create a record. Look something up. Take an action. No human clicking through screens. The customer’s assistant just does it, on their behalf, in your software.

That is the promise. A product a machine can operate, not just a person. And it is exactly as good as the tools you expose, which is the whole game.

An API is for a developer. This is for a model

Here is the mental switch that changes everything.

An API is written for a developer. A human who reads the docs, notices the auth section, sees the example payload, and writes code against it deliberately. They have time. They can experiment. They can email you when it is confusing.

An MCP server is written for a language model. It does not read your docs. It reads the tool name and the description, right there in the moment, and it decides. It has no manual. It cannot ask you a question. It gets one look and one shot.

That reader is completely different, so the surface has to be completely different. The endpoints underneath might be identical. What sits on top is not an API. It is a set of instructions to a capable stranger who will act immediately on whatever you wrote.

Once you internalise who the reader is, every design decision falls out of it.

Keep the toolbox small

The first mistake is too many tools.

The instinct is to expose everything. Every endpoint, every option, every flag, one tool each. Now the model faces forty tools and has to pick the right one from a wall of near-duplicates. It picks wrong. It picks the powerful one when it needed the simple one. It gets lost.

A small, sharp toolbox beats a big one every time. A handful of tools that each do something a user would actually recognise as a task. Not “call this endpoint with these twelve parameters.” More like “create the thing,” “find the thing,” “change the state of the thing.”

Every tool you add makes every other tool harder to choose. Treat the count as a budget you are reluctant to spend. If two tools overlap, you have given the model a coin to flip, and it will flip it at the worst moment.

Name and describe for a stranger with no context

The tool name is not a label. It is the entire pitch.

The model chooses a tool almost entirely on its name and its one-line description. So write them as if to a competent stranger who has no idea what your product is. Plain words. What it does, when to use it, what it needs.

Not exec_v2. Not handleCreate. Say what happens in language a person would use to describe the outcome. The name is doing the model’s job of understanding for it, so make it carry the weight.

And the description is where you put the judgement the model cannot have. When to reach for this tool. When not to. What it will refuse to do. You are not documenting the tool, you are coaching the reader through a decision it has to make instantly, alone.

Write it, then read it back cold. If a stranger could not tell exactly when to use this tool from the name and the sentence under it, neither can the model.

One tool, one clear job

Each tool should do one thing you could describe in a short sentence.

The moment a tool does three things depending on which parameters are set, you have built a puzzle. The model has to reason about combinations. Set this but not that. Pass this only when the other thing is present. Every conditional is a place to trip.

Split it. A tool that does one clear thing is a tool a model picks correctly and calls correctly the first time. Boring, single-purpose tools compose beautifully. Clever, multi-mode tools fail in ways that are hard to even reproduce.

This is the same discipline as writing a good function. Small, named for its effect, no surprising side channels. The difference is that your caller cannot read the source to figure out the surprises. It only has the name and the description, so the surprises have nowhere to hide except in production.

When it breaks, break usefully

Here is the part that separates a toy from a tool. What happens when something goes wrong.

A normal API can throw a stack trace and a 500. A human developer will read it, sigh, and fix their code. A model cannot do that. Hand a model a stack trace and it is stuck, because it has nothing to act on.

So the errors have to be recoverable. When a call fails, the message that comes back should tell the model what to do next, in words. The date was in the wrong format, here is the format. That name is already taken, try another. You are missing a required field, here is which one.

Do that, and something quietly brilliant happens. The model reads the error, understands it, corrects itself, and calls again. It recovers without a human ever seeing it. A good error message turns a failure into a retry. A bad one turns it into a support ticket.

I spend more design time on the failure paths than the happy path, because the happy path mostly takes care of itself. The failures are where a model either recovers gracefully or gets stranded, and that is the difference customers actually feel.

Auth that fits an agent, not just a person

Someone’s AI is going to hold a credential and act as them. Sit with that for a second.

That changes how you think about access. The AI acts on the customer’s behalf, so it must be scoped to exactly what that customer can do and nothing more. Not a master key. Not broad access because it was easier to wire up. The blast radius of a leaked or misused credential has to be the customer’s own account, and only theirs.

Get this wrong and you have handed an autonomous actor keys to things it was never meant to touch. Get it right and the AI is simply the customer, working faster. Scope tight, default to least privilege, and assume the credential will one day end up somewhere you did not intend. Design for that day now.

The line money does not cross

The last rule is the one I will not bend on.

Reads are free. Reversible actions can run all day. Look things up, create drafts, change states you can change back. Let the model move.

But anything that moves money, and anything that cannot be undone, stops. It routes to a human, or it sits behind an explicit confirmation that a person gives. The server will happily prepare the action. It will not complete the irreversible part on its own.

This is not timidity. An MCP server that can spend money unsupervised is not a productivity feature. It is an incident waiting for a date. The whole value of letting a customer’s AI drive your product is that it moves fast on the safe majority. You protect that value by making sure the dangerous minority always meets a human first.

Fast on the reversible. Gated on the irreversible. That single line is what makes the rest of it safe to ship.

The shape, in one breath

Strip it all back and a good MCP server is not complicated. It is a small set of single-purpose tools, named and described so a stranger could use them, that fail with instructions instead of stack traces, scoped to exactly one customer’s reach, with a hard stop wherever money or permanence is involved.

None of that is about the protocol. The protocol is a few days of work. All of it is about respecting who the reader is: a capable model, acting alone, in the moment, with no manual and no way to ask.

Build for that reader and people will point their AI at your product and let it work. Build for a developer who is not coming, and you have shipped an API in a new hat, and it will sit there unused while you wonder why.

The protocol makes it possible. The shape makes it used.

Back to articles
End of Post