All guides

Claude Code line · stop 02 of 16 · 25 min · members

Build your first MCP server: the smallest one that does something useful

What an MCP server really is, the smallest one that does something useful, and how to point Claude at it.

Free with an account

Sign in to read.

Membership is free: an account opens all 86 script pages. The Lab, Studio Canvas and the paid guides need the $99 pass, paid once. Already signed in on this browser? The page opens by itself.

01

What it is

A way to give an agent a tool you wrote.

Not a plugin system, not an integration. A small process that exposes functions.

The concept is simpler than the terminology suggests. You write a small program that advertises a set of functions with described inputs. The agent reads that list, decides when one is relevant, calls it, and receives the result.

That is the whole idea. Everything else — the transport, the schema format, the handshake — is plumbing that a library handles.

What it buys you is that the agent can now do something specific to your work: query your own data, drive an application you use, run a process only you have. Without it, the agent is limited to files and shell commands.

02

Before you build

Ask whether a shell command would do.

Most things people build servers for are already reachable.

An agent can already run commands and read files. If your capability is available as a CLI, it is available already, and a server adds nothing but maintenance.

A server earns its place when:

  • The capability is not exposed as a command — an application's internal API, a live session, a scripting interface.
  • The interaction is stateful, and a fresh process each time would lose that state.
  • Raw output needs shaping into something an agent can use without reading a wall of text.

That last one is underrated. A server whose job is returning a compact, structured answer instead of a hundred lines is doing real work even when the underlying command exists.

03

The smallest useful one

One function, one clear description.

Start with a single tool and get the loop working end to end.

Pick one thing. Register it with a name, a description, and a typed input. Return a short result.

@server.tool()
def project_status(name: str) -> str:
    """Return the current status of a project by name.
    Use when asked what state a project is in."""
    ...
    return summary

The description is the important part and it is written for a reader deciding whether to call it, not for a developer reading source. Say what it does and when to use it. A vague description means the tool is either never called or called at the wrong moment.

Get one tool working before adding a second. The first one is where all the setup problems appear.

04

Registering it

Point the agent at it, then verify from the other side.

Most first-time failures are configuration rather than code.

Add the server to your agent's configuration with the command that launches it, then restart the session so it is picked up.

Verify by asking the agent what tools it can see, rather than by asking it to do the thing. If the tool is not listed, no amount of prompting will invoke it, and you are debugging the wrong layer.

Common causes when it does not appear: the process exits immediately, a dependency is missing in the environment the agent launches it from, or the path in the configuration is relative when it needed to be absolute.

05

Designing the returns

Return what an agent can act on, not what a human would read.

This is where most servers are badly designed.

The instinct is to return everything relevant. That fills the conversation with material and forces the agent to parse prose.

Return the specific answer, compactly. Where output could be large, return a summary plus a way to fetch detail — a count, a list of identifiers, an option to request one item in full.

Errors deserve the same care. 'Failed' is unusable. 'Project not found; available: a, b, c' lets the agent correct itself in one step instead of asking you.

06

Keeping it small

A server with forty tools is worse than one with six.

Every tool description costs context in every session where the server is loaded.

Tool lists are loaded whether or not they are used. A large server imposes that cost on every session, including all the ones where it is irrelevant.

Expose the operations you actually invoke. Combine related ones behind a single tool with a mode parameter rather than exposing every variation separately.

Review it occasionally and delete what you have not called. The good version of a personal server is small, specific, and describes itself well enough that the agent reaches for it at the right moment without being told.