mcp-server-design · git:20260914.0426f9e · 2026-09-14 · sha256 b3378d103887ac20

mcp-server-design git:20260914.0426f9eA

Immutable. This exact content is served forever at /api/v1/blob/b3378d103887ac20.

---
name: mcp-server-design
description: "Decide whether to build an MCP server, which protocol primitives to expose, and how to design tools an agent can actually use. Covers transports, language choice, and the tools/resources/prompts split."
lastReviewed: 2026-09-13
---

# Design an MCP Server

The design decides whether the server is usable. Everything after it is typing.

## Should This Be a Server?

Check whether one already exists. The
[servers directory](https://github.com/modelcontextprotocol/servers) lists
reference and community implementations, and most vendors with an API now ship
one.

Build your own when you are wrapping an internal API, or a third-party service
whose published server does not cover what you need. Wrapping a public API that
already has a maintained server means inheriting its maintenance burden for no
new capability.

Before designing tools, answer one question in a sentence: **what task should an
agent be able to finish that it cannot finish today?** If the answer is "call our
API", the design will drift into a thin HTTP proxy with fifty tools and no shape.

## What a Server Can Expose

Three primitives, distinguished by who decides to use them.

| Primitive | Controlled by | Use for |
| --- | --- | --- |
| **Tools** | The model | Actions the agent chooses: query, create, update |
| **Resources** | The host application | Addressable data read by URI: files, records, logs |
| **Prompts** | The user | Reusable templates a person invokes deliberately |

Most servers ship tools and stop. If everything you expose is a tool, check
whether some of it is reference data. A resource the host reads directly costs no
tool call and no round trip through the model.

Two further capabilities invert the usual direction of control. **Sampling** lets
the server ask the client for a model completion, so it can reason without
shipping its own API key. **Elicitation** lets the server ask the user for input
mid-operation. Both are in the
[specification](https://modelcontextprotocol.io/specification/); confirm your
target host supports them before designing around either.

## Choose a Transport

| Transport | Use case | Consequences |
| --- | --- | --- |
| **stdio** | Local, single user, desktop | No network, no auth, no hardening needed |
| **Streamable HTTP** | Remote, multi-tenant | Needs auth, host validation, and a deployment story |

Start with stdio unless the server must be reachable over a network. Converting
later is mostly a transport swap; tool definitions do not change. Choosing HTTP
first means paying for `mcp-server-hardening` before you have anything working.

## Choose a Language

| Language | Best for | Package |
| --- | --- | --- |
| **TypeScript** | General servers, broadest client compatibility | `@modelcontextprotocol/sdk` |
| **Python** | Data and ML pipelines | `mcp` (FastMCP) |
| **C#/.NET** | Existing .NET services | `ModelContextProtocol` |

Pick the language your service already runs in. An MCP server is a thin adapter
over logic you have; rewriting that logic in a different language to match an SDK
is the expensive way to get a worse result.

## Designing Tools

**Prefer coverage to cleverness.** When uncertain, expose the API surface rather
than guessing which workflows an agent will want. Add workflow tools once you can
see what agents actually attempt — which is what `mcp-server-testing` produces.

**Name for discovery.** A consistent prefix and an action verb:
`github_create_issue`, `github_list_repos`. An agent selects tools by reading
names and descriptions. A vague name is a tool that never gets called.

**Describe when, not just what.** "Lists repositories" tells an agent what the
tool does. "Lists repositories the authenticated user can push to; use before
creating a branch" tells it when to reach for this one instead of a neighbour.

**Return focused data.** Paginate, filter, let the caller narrow. A tool
returning a megabyte of JSON burns the agent's context and usually answers a
question nobody asked.

**Write errors an agent can act on.** `Error: check API key, verify endpoint, or
reduce page size` is recoverable. `Request failed` ends the attempt.

### Annotations

Declare these so hosts can reason about safety before calling:

| Annotation | Meaning |
| --- | --- |
| `readOnlyHint: true` | Does not modify state |
| `destructiveHint: true` | Makes irreversible changes |
| `idempotentHint: true` | Safe to retry |
| `openWorldHint: true` | Reaches an external system |

A destructive tool without `destructiveHint` is how an agent deletes something
while believing it was browsing.

## Composes With

- [mcp-server-build](../mcp-server-build/SKILL.md) — implement the design
- [mcp-server-testing](../mcp-server-testing/SKILL.md) — evaluations tell you
  which workflow tools are worth adding

## Would Revise If

- The protocol adds a primitive beyond tools, resources, and prompts, making the
  three-row table incomplete.
- A transport beyond stdio and Streamable HTTP reaches general availability.
- Teams following "prefer coverage" ship servers with so many tools that agents
  cannot choose among them, which would mean the advice needs a ceiling.