How to build an MCP server
Last verified: July 2026· MCP
MCP turns the messy, one-off work of wiring an AI assistant into your systems into a standard integration. Instead of building a bespoke connector for every client, you build one server that any MCP-compatible client can talk to. This guide is for engineers who want to ship one: when it's worth building versus reusing an existing server, what the moving parts actually are, how a minimal Python server is structured, how to test it against a real client, and what changes when it has to run in production. The protocol is young but the shape is stable, and the mistakes worth avoiding are the ones around scope, auth, and blast radius — not the SDK.

When you should build one — and when you shouldn't
MCP is a real open standard introduced by Anthropic in late 2024. An MCP server exposes capabilities — tools, resources, and prompts — to an MCP client such as Claude Desktop, Claude Code, or Cursor, over JSON-RPC. The value is standardisation: build the integration once, and any compliant client can use it, instead of re-implementing a connector per assistant.
The first question is whether you should build at all. There is a growing ecosystem of existing servers for common systems — filesystems, popular databases, GitHub, and so on. If an official or well-maintained server already covers your system, use it. Building your own is worth it when the integration is specific to your domain: your internal APIs, your data model, your business actions, your access rules. That is exactly the surface no off-the-shelf server can know about.
The second question is whether an MCP server is even the right shape. MCP shines when a human-in-the-loop or agentic client needs to discover and call your capabilities dynamically across a session. If what you actually need is a fixed, deterministic pipeline that always runs the same steps, a plain script or service is simpler and easier to reason about. Reach for MCP when the calling pattern is open-ended and you want the model to choose which tool to use and when.
The pieces of an MCP server
An MCP server exposes three primitives. Tools are actions the model can invoke — query a database, file a ticket, call an internal API. Each tool has a name, a description, and a typed input schema, and it returns a result. Resources are readable data the client can pull into context — a file, a record, a document — addressed by URI. Prompts are reusable, parameterised templates the client can surface to the user, useful for encoding a standard workflow.
Tools are where most of the design effort goes, because the model decides whether and how to call them based on the name, description, and schema you write. Treat those as the interface: a clear description and a precise input schema are the difference between a tool the model uses correctly and one it misuses. Keep each tool doing one well-defined thing rather than exposing a single do-everything endpoint.
Underneath sits the transport. stdio runs the server as a local subprocess of the client, communicating over standard in/out — this is the default for local, single-user setups and the easiest to start with. HTTP transport runs the server as a networked service, which is what you want for a shared, remote, or multi-user deployment. The protocol underneath both is JSON-RPC: the client discovers your capabilities, then calls them, and your server responds.
A minimal Python server
The official Python MCP SDK removes almost all of the boilerplate. Conceptually, a minimal server is short: you create a server instance, register at least one tool, and start it on a transport. Registering a tool means giving it a name, a human-readable description, and an input schema (the SDK lets you derive the schema from typed function arguments), then writing the handler that runs when the tool is called and returns a result.
So the whole shape of a first server is: define one tool — say, a function that takes a typed argument, does the work (query a store, hit an API), and returns text or structured data; let the SDK expose its schema from the argument types and docstring; and run the server over stdio so a local client can launch it. That is genuinely all a working server needs — everything else is adding more tools, resources, and prompts in the same pattern.
The discipline here is to keep handlers thin and honest. A handler should validate its inputs, do one thing, and return a clear result or a clear error — the model reads error messages and will adapt to them, so a descriptive failure is more useful than a stack trace. Avoid side effects the caller can't see, and don't let a single tool quietly reach across half your infrastructure.
Testing it and connecting a client
You want two feedback loops. The first is direct: exercise the server without a model in the way, so you can confirm it lists the tools you expect and that calling a tool with known inputs returns what it should. Because the protocol is JSON-RPC over a transport, you can drive it programmatically or with the SDK's own tooling — this is where you catch schema mistakes and handler bugs cheaply, before a client is involved.
The second loop is end-to-end: register the server with a real client and watch the model use it. For a stdio server, that means adding it to the client's MCP configuration — pointing Claude Desktop, Claude Code, or Cursor at the command that launches your server. Then give the model a task that should trigger your tool and observe whether it discovers the tool, picks it, and calls it with sensible arguments. If it doesn't, the fix is almost always in the tool's name, description, or schema rather than the code.
This second loop is also your usability test. The model is your user, and how it reads your descriptions tells you whether the interface is clear. Ambiguous tool names, overlapping tools, or under-specified schemas show up immediately as the model hesitating, guessing arguments, or calling the wrong thing.
Hardening for production
A server that reads a local file for one developer and a server that executes actions against production systems for a team are different risk profiles. The moment your server can do something consequential, three concerns become non-negotiable. Authentication and authorisation: the server must know who is calling and what they're allowed to do — the AI client is not a trust boundary, so identity and permissions have to be enforced server-side, especially over HTTP transport. Scoping: give each tool the narrowest access it needs, so a compromised or misused tool has a small blast radius rather than the keys to everything.
The third is auditability. Because a model chooses when and how to call your tools, you need a durable record of what was called, by whom, with what arguments, and what happened — both to debug behaviour and to answer the security question of what the assistant actually did. Treat every tool that writes or acts as you would a privileged API endpoint: validate inputs, rate-limit, and prefer explicit, reversible actions over broad ones.
This is the part where a quick prototype and a shippable server diverge, and it's the work we focus on in our MCP server builds: taking a server from "it works on my machine against Claude Desktop" to something with real auth, least-privilege scoping, audit logging, and a deployment story your security team will sign off on. The SDK gets you a working server in an afternoon; the hardening is what makes it safe to point at production.
How to build and ship an MCP server
- 1Step 1
Scope the tools
Decide the specific actions, data, and prompts worth exposing, and confirm no existing server already covers them.
- 2Step 2
Scaffold with the SDK
Create a server instance with the official Python (or TypeScript) MCP SDK so the protocol plumbing is handled for you.
- 3Step 3
Implement a tool + schema
Register one tool with a clear name, description, and precise input schema, and write a thin handler that does one thing and returns a clear result.
- 4Step 4
Run over stdio and connect a client
Start the server on stdio, register it in Claude Desktop, Claude Code, or Cursor, and watch a real model discover and call it.
- 5Step 5
Add auth, scoping, and audit
Enforce identity and permissions server-side, give each tool least-privilege access, and log every call before exposing anything consequential.
- 6Step 6
Package and document
Package the server for its deployment target (local command or HTTP service) and document its tools so both humans and models know what each does.
Frequently asked questions
How do I create an MCP server in Python?
Use the official Python MCP SDK. Create a server instance, register a tool by giving it a name, description, and typed input schema plus a handler function, then run it over stdio so a local client can launch it. The SDK handles the JSON-RPC protocol, so your code is just the tools, resources, and prompts you choose to expose.
Can I build my own MCP server?
Yes. MCP is an open standard with official SDKs, and building a server for your own systems is the intended use. It's most worthwhile when the integration is specific to your domain — your internal APIs, data model, and access rules — since no off-the-shelf server can know those. If an existing server already covers a common system, reuse it instead.
When should I build an MCP server?
Build one when an AI client needs to discover and call your capabilities dynamically across a session, and no existing server covers your system. If a maintained server already exists for your target, use it. And if you only need a fixed, deterministic pipeline, a plain script or service is simpler than MCP — reach for MCP when the calling pattern is open-ended.
What MCP server development tools and examples exist?
The core tools are the official Python and TypeScript SDKs, which handle the JSON-RPC protocol and schema generation, and MCP-compatible clients — Claude Desktop, Claude Code, and Cursor — to test against. The community also maintains reference servers for common systems like filesystems and databases, which are worth reading as working examples before you write your own.
What is MCP server development, and who develops MCP servers?
MCP server development is building the program that exposes your tools, resources, and prompts to an AI client over the Model Context Protocol. It's typically done by the engineers who own the system being integrated — backend, platform, or AI-engineering teams — because writing good tools requires knowing the domain, the data model, and the access rules the server must enforce.
What the community is debating
- Model Context Protocol — HN · 872 points · 258 comments
- Show HN: mcp-agent – build effective agents with MCP — HN · 80 points · 28 comments
- Donating MCP and establishing the Agentic AI Foundation — HN · 288 points · 145 comments
Community: r/mcp