Topic hub
Building and maintaining MCP servers
How a program gives a language model tools, data, and prompts through the Model Context Protocol, from both sides of the wire, from the first message to a server that keeps working as it changes.
The problem
A language model on its own can only produce text. To check the weather, read a file, or add a calendar entry, the app around it has to run real code and hand the result back. Before the Model Context Protocol (MCP), every app wired up every integration its own way, so a tool built for one assistant did not work in another.
MCP is a shared contract for that wiring. A server offers tools, data, and prompt templates. A host (the app a person uses) runs one client per server and lets the model use what the servers offer. Write a server once and any MCP host can use it. Write a host once and any MCP server plugs in.
This cluster covers both sides: what goes over the wire, how to design a server a model can use well, how to build one in Python, how a client and host drive it, how to keep it secure, and how to keep it working as it and the protocol change. It is written against the 2026-07-28 revision of the specification, which made the protocol stateless: no handshake, no sessions, every request self-contained. Follow the "Before this" links down until you reach something you already know, then read back up.
The pipeline
Every page points back to this picture of a server's life.
| Stage | Question it answers | Techniques that live here |
|---|---|---|
| 1. Speak the protocol | What does an MCP message look like, and how do two sides agree on a version? | Anatomy of an MCP request, Version negotiation |
| 2. Design the surface | Which tools, resources, and prompts should the server offer, with what schemas, and when does it need to ask for more input? | Designing tools, Resources and prompts, Multi round-trip requests |
| 3. Build and connect | How does a Python server run, and how do a client and host reach it? | Building a server in Python, Transports: stdio and Streamable HTTP, Building a client, The host loop |
| 4. Secure it | Who may call the server, and what can go wrong when a model is the caller? | Authorization for remote servers, Security threats and defenses |
| 5. Test and ship | How do you know it works, and how does it run somewhere other than your laptop? | Testing MCP servers, Deploying remote servers |
| 6. Maintain it | How does it change without breaking the clients that depend on it, and how do you see what it is doing? | Evolving a server without breaking clients, Observability and operations |
Stages 2 and 6 are where most of the long-term cost sits. A tool with a vague description gets called at the wrong times by every model that ever sees it, and a careless rename breaks every client that was built against the old name. Neither shows up as a crash on your own machine.
Which page for which job
You have never seen MCP before. Read Anatomy of an MCP request, then Designing tools, then Building a server in Python. That is the shortest path to a server that runs.
You are building a host or an agent that uses servers. Start at Building a client and The host loop, then read Security threats and defenses before anything you build reads untrusted data.
Your server works locally and now has to run for other people. Transports, then Authorization for remote servers, then Deploying remote servers.
People already depend on your server. Evolving a server without breaking clients and Version negotiation, with Testing MCP servers for the snapshot test that catches accidental breaking changes.
The model keeps calling the wrong tool, or calling the right one badly. That is a design problem, not a code problem: Designing tools, then the "How language models use tools" prerequisite underneath it.
The basics underneath
None of these needs more than first-year college material and a little programming.
| You need | For |
|---|---|
| JSON | The text format of every message. |
| Processes and standard streams | How a host launches a local server and talks to it over stdin and stdout. |
| HTTP basics | How a remote server receives requests and streams responses. |
| Python essentials for MCP | Type hints, decorators, and async, which every sample uses. |
| JSON-RPC | The request, response, and error shapes MCP is built on. |
| JSON Schema | How a tool says what arguments it accepts and what it returns. |
| How language models use tools | What "the model calls a tool" actually means, and why descriptions matter so much. |
| OAuth basics | Tokens, scopes, and the authorization code flow behind remote-server auth. |
| API contracts and versioning | Which changes keep a promise to other programs and which break it. |
| Trust boundaries and threat models | How to think about untrusted input when the reader is a model. |
Conventions used across this cluster
- Spec revision 2026-07-28. Where older revisions behaved differently, a page says so in one sentence starting "Older servers". Roots, Sampling, and Logging are deprecated in this revision; pages mention them only to say what replaces them.
- Roles: the host is the app the person uses, a client is the host's connection to one server, a server offers tools, resources, and prompts, and the model is the language model inside the host.
- Code is Python with the official MCP SDK, version 2. Every sample ran before it was published, and each shows the command that runs it and the output it printed. Python attribute names are snake_case (
input_schema) while the wire format is camelCase (inputSchema). - Wire messages are shown as pretty-printed JSON with field names exactly as the specification spells them.
- No shared running example yet. Each page uses a small illustration of its own (a unit converter, a notes store, a weather lookup). The server, client, and testing pages share one unit-converter server so the later pages have something real to drive.
Recommended software
Names only, no links: names stay stable and download pages do not.
| Job | Pick | Why | Also fine |
|---|---|---|---|
| Writing servers and clients | The official MCP Python SDK (package mcp, version 2) |
Speaks the 2026-07-28 revision and still serves older clients. Builds schemas from type hints. | The official SDK for TypeScript, or for another language you already use |
| Poking at a server by hand | MCP Inspector | Connects to a server over stdio or HTTP and lets you list and call everything it offers, with the raw messages visible. | A short script using the SDK's client |
| Using a server from a real assistant | Any MCP host, such as Claude Desktop, Claude Code, or VS Code | Shows how a model actually picks and calls your tools. | Any other host that supports MCP |
| Python environments | uv | Creates the virtual environment and installs the SDK in one step. | Python's built-in venv and pip |
| Testing | pytest with pytest-asyncio | The SDK's client is async, and these run async tests directly. |
How to read this cluster
The learning path below is sorted so that each row depends only on the rows above it. If you already write Python and know HTTP, skip to Anatomy of an MCP request. If you only build hosts, the server-building pages are still worth a skim: most host bugs are a misunderstanding of what the server promised.
Learning path
Each row depends only on rows above it. Read top to bottom, or jump to a technique and follow its "Before this" links downward.
- prerequisiteJSONThe text format every MCP message is written in: objects, arrays, strings, numbers, booleans, null, and nesting.
- prerequisiteHTTP basicsRequests and responses, methods, headers, status codes, and streamed responses: the parts of HTTP a remote MCP server uses.
- prerequisiteProcesses and standard streamsWhat a running program is, and how stdin, stdout, and stderr let one program talk to another through pipes.
- prerequisitePython essentials for MCPJust enough Python to read and run every sample in this cluster: functions, type hints, decorators, async and await, and virtual environments.
- prerequisiteJSON SchemaHow a schema describes what valid JSON looks like, so a model knows what arguments a tool takes and a server can reject bad ones.
- prerequisiteHow language models use toolsWhat actually happens when a chat model 'calls a tool': tool descriptions in the context, structured output, and the host doing the real work.
- prerequisiteJSON-RPCThe request, response, notification, and error shapes MCP borrows: ids, methods, params, results, and error codes.
- prerequisiteOAuth basicsAccess tokens, scopes, the authorization code flow with PKCE, issuers and audiences: the vocabulary MCP authorization is built from.
- prerequisiteAPI contracts and versioningWhat a contract between two programs is, which changes keep it and which break it, and how version numbers and deprecation windows signal the difference.
- prerequisiteTrust boundaries and threat modelsHow to reason about who and what you trust, where data crosses from untrusted to trusted, and what an attacker could do at each crossing.
- techniqueAnatomy of an MCP requestHost, client, and server roles, and what every MCP request and result carries in the stateless 2026-07-28 protocol: method, params, _meta, and resultType.
- techniqueTransports: stdio and Streamable HTTPThe two ways messages travel: a local child process over stdin and stdout, or a remote endpoint over HTTP POST with optional streamed responses, plus long-lived subscriptions.
- techniqueDesigning toolsNaming, describing, and shaping a tool so a model picks it correctly and calls it with valid arguments: input and output schemas, structured content, and errors.
- techniqueResources and promptsThe two primitives besides tools: resources expose data the host can read by URI, and prompts are reusable templates a person picks, plus caching and completion for both.
- techniqueVersion negotiationHow a client and server that speak different protocol revisions find one they share, per request, and how a 2026-era server still serves older handshake-based clients.
- techniqueAuthorization for remote serversHow a remote MCP server decides who may call it: OAuth 2.1 with the server as a resource server, discovery of the authorization server, client registration, and token checks.
- techniqueBuilding a server in PythonA complete MCP server with the official Python SDK: registering tools, resources, and prompts on MCPServer, schemas from type hints, and running it over stdio.
- techniqueMulti round-trip requestsHow a stateless server asks for more input mid-call: returning input_required, the client gathering answers through elicitation, and the retry that completes the request.
- techniqueBuilding a clientThe other side of the wire in Python: connecting to a server, discovering what it offers, calling tools, handling input_required, and caching list results.
- techniqueDeploying remote serversRunning a server somewhere other than a laptop: why the stateless protocol suits serverless and load-balanced hosting, where state lives instead, and long-running work.
- techniqueTesting MCP serversHow to know a server works before a model touches it: unit tests for handlers, an in-process client for protocol tests, schema contract tests, and an interactive inspector.
- techniqueObservability and operationsSeeing what a running server is doing: logs on stderr, OpenTelemetry trace context in _meta, progress and cancellation, error codes worth alerting on, and the per-request log level.
- techniqueThe host loopHow a host turns MCP tools into a working assistant: translating tool definitions for a model, running the call-and-answer loop, and keeping a person in control.
- techniqueEvolving a server without breaking clientsChanging tools, schemas, and resources after people depend on them: which changes are safe, how to deprecate, how to tell clients the list changed, and how to follow the spec's own revisions.
- techniqueSecurity threats and defensesWhat goes wrong when a model is the caller: prompt injection through tool results, poisoned tool descriptions, confused deputies, over-broad permissions, and the defenses on each side.