GuidesEngineering

How to Build an MCP Server

Shiplight AI Team

Shiplight AI Team

Updated on July 31, 2026

View as Markdown
Illustrated Shiplight blog cover: a small protocol server being assembled from a few well-labeled tool components.

Writing a server that speaks the Model Context Protocol takes an afternoon. Writing one an agent uses correctly takes longer, and the difference is almost entirely in decisions that are not about the protocol at all.

This covers the minimum implementation, then the part that actually determines whether it works: tool design.

The minimum

A server declares tools with names, descriptions and input schemas, then handles calls to them. Official SDKs exist for the common languages and handle the transport, so the code you write is close to the shape of a small RPC service.

Two transports matter. Stdio runs the server as a local subprocess of the client, which is the right default for developer tooling because it can reach the filesystem and the developer's running application without anything leaving the machine. HTTP is for remote servers shared across users.

Start with stdio. Ship the second when someone asks.

Tool design is the whole job

Everything below is what separates a server agents use from one they ignore.

Descriptions are prompt engineering

The description is how the model decides whether your tool fits the task in front of it. It is not documentation for a human who already chose the tool. It is the pitch.

"Runs a check" gets ignored. Say what the tool does, when to reach for it, and what comes back. If your tool is not being called, the description is the first thing to fix, and it is usually the only thing.

Fewer tools, better named

Twelve granular tools that mirror your internal API is a common mistake. The model has to choose among all of them on every turn, and selection accuracy falls as the list grows.

Design for tasks, not for your object model. One tool that does the thing a user wants beats four that must be composed in the right order.

Return small, structured responses

Every byte you return lands in the model's context and stays there. A tool that dumps a full API response spends context that other tools and the actual code need.

Return what is needed for the next decision. Structured beats prose, because the model parses it more reliably. If a result is genuinely large, return a summary plus a way to fetch detail on request.

This is the most common performance problem in practice, and it is invisible from the outside: the agent just gets slower and worse a few turns after using your tool.

Fail with information

An error saying what was expected and what arrived lets the model correct itself and retry. An error saying "failed" ends the attempt and the user sees "I was unable to do that."

Do not expose what should not be decided by a model

A tool the model can call is a tool it can call at the wrong moment. Deletions, payments, production configuration: either keep them out, or require an explicit confirmation argument the model cannot supply on its own.

Test it before an agent touches it

Debugging through an agent is miserable, because the model decides whether to call your tool, phrases the call, and reports back in prose that loses the actual error.

Connect MCP Inspector instead. It speaks the protocol directly, so you see the advertised tool list, call tools with parameters you choose, and read the raw response. Most problems resolve in a couple of minutes there and would take an hour through an agent.

The order that works: does the server start, does Inspector see the tools, does a tool work when called by hand, and only then look at the client config.

Should you build one at all

Worth building when the capability is specific to your organization, when several different agents need the same thing, or when there is no API to point at because the work is local.

Not worth building when a maintained server already does it. The ecosystem is large enough by 2026 that checking first is faster than writing.

For browser automation specifically, do not start from scratch. That problem has been solved carefully, including the part most people get wrong: returning structured accessibility snapshots rather than screenshots, which costs a fraction of the tokens and works with any reasoning model. See Playwright MCP.

One design note from our own server

Shiplight exposes browser verification and test generation over MCP, and the decision that mattered most was not a protocol one. It was that a verification which leaves no artifact is worth very little.

An agent can open a browser, confirm a flow works, and move on. That protects today. The tool is far more useful if the successful walkthrough is also written into the repository as a test that runs on every future change, because then today's check catches tomorrow's regression.

If you are building a server that verifies something, the design question worth asking early is what survives the session.

Frequently Asked Questions

1

What do I need to build an MCP server?

An SDK for your language, a transport (stdio for local developer tooling), and tool definitions with names, descriptions and input schemas. The protocol work is small.

2

Should I use stdio or HTTP?

Stdio for local developer tooling, since it can reach the filesystem and a locally running app without data leaving the machine. HTTP for remote servers shared across users.

3

Why does the agent ignore my tool?

Almost always the description. The model decides from that text whether the tool fits the task, so a vague description reads as irrelevant regardless of what the tool does.

4

How many tools should one server expose?

As few as will do the job. Selection accuracy falls as the list grows, so design tools around tasks rather than mirroring your internal API.

5

How do I debug it?

With MCP Inspector, not through an agent. It shows the raw tool list, lets you call tools directly, and returns the actual error instead of a prose summary.