Writing your first MCP server

Nov 9, 2026The avbbc desk

Most MCP servers exist because someone needed one endpoint their client did not have. Writing one is a small exercise, and the interesting decisions are not the code.

The shape of it

A server declares a name, registers tools with input schemas, and answers requests. In the TypeScript SDK that is a server object, a tool-registration call per tool, and a transport — stdio for local use.

## The decisions that matter
**How many tools.** Forty tools cost context on every request and make selection worse. Start with two or three, each doing one thing.
**Descriptions are prompts.** The tool description is what the model reads when deciding whether to call it. "Search notes" is weak; "Search notes by keyword. Read-only, returns at most 20 results." tells the model when to use it and what to expect.
**Return text, not structure you invented.** Content blocks are the contract. If your tool returns JSON, return it as a text block and say so in the description.
**What not to expose.** This is the real design work. A server that wraps a database can expose `query` or `delete_row`. One of those is a tool; the other is an incident waiting for a prompt injection.
## The part people get wrong
Errors. A tool that throws returns a protocol error the model may retry forever. Return a message the model can read: "No notes matched 'x'" is a result, not a failure.
Then test with the smallest case: does the client list the tool, does one call return what you expect, does a bad argument produce a readable message.
## Where to go next
Read [how to judge a server](/blog/evaluating-a-server/) — the checks you apply to other people's servers apply to yours, and one of them is whether the documentation says what it cannot do.