How to Build Your Own MCP Server (Step-by-Step)
Updated 2026-09-06 ยท guide ยท MCP, how-to, tutorial, server
Ready to turn this into a launch plan?
Get the Agent & SEO Launch Sprint for $299: a focused audit, a dated 14-day roadmap, and one follow-up implementation call.
You've wired an off-the-shelf MCP server into Claude or another agent, it worked, and now you have the itch: you want to build your own. Good instinct. The Model Context Protocol was designed to be small enough that a single developer can ship a useful server in an afternoon โ and most of the value in the ecosystem sits in the long tail of custom integrations nobody has built yet.
This is the step-by-step, from an empty directory to a running server your agent can actually call. No framework magic, no copy-paste black box โ just the spec, the tooling, and the decisions that actually matter.
If you're new to the protocol itself, start with what MCP servers are; this guide assumes you know the shape of the protocol and want to build.
What you're actually building
An MCP server is a program that speaks JSON-RPC 2.0 over stdio (or HTTP in the newer transport) and advertises three kinds of capabilities:
- tools โ actions the agent can call ("search the codebase", "send a Slack message")
- resources โ read-only data the agent can load ("the current project's README")
- prompts โ reusable prompt templates the agent can invoke
For your first server, implement tools only. Resources and prompts are easy to add later and rarely the reason you're building in the first place. One working tool beats three half-finished capabilities.
Step 1 โ Pick the SDK and scaffold
The official SDKs (Python and TypeScript) hide the JSON-RPC plumbing so you can focus on your tool's logic. Pick by your team's language, not by hype:
- Python โ
mcppackage, works with FastMCP for a concise@mcp.tool()decorator style. Best if your tool wraps Python libraries. - TypeScript โ
@modelcontextprotocol/sdk, best if your tool wraps an existing JS/TS service or an API you already call.
Scaffold a bare project and define one trivial tool first โ before adding real logic, prove the round trip works end to end.
Step 2 โ Define the tool interface before the implementation
MCP tools are defined by a name, a description, and a JSON Schema for their input. The description matters more than you'd think: it's what the agent reads to decide when to call your tool. Write it as if explaining to a capable colleague, not to a machine:
- What the tool does, in one sentence
- When to use it (and when not to)
- The shape of the input, with honest types
Then define the input schema explicitly. A typed schema (required fields, type: string|number|..., useful description on each field) is what turns your tool from guessable to reliable โ agents make far better calls against a well-described schema than a loose one.
Step 3 โ Implement the handler with correct error discipline
The handler is where most first-time servers fail, and almost always on errors. Follow these rules:
Step 4 โ Test the round trip like a user
- Return errors as data, not crashes. MCP has a structured error channel; your tool should return a clear message when it fails ("file not found: X") rather than throwing and leaving the agent guessing.
- Validate input before touching the outside world. Check required fields and types first; a schema that says
stringbut a handler that assumesnumberwill confuse the agent silently. - Set a timeout. External calls (APIs, shells, filesystem) should time out and return "timed out after 10s" โ an agent waiting forever on your tool is a broken agent.
- Never let secrets leak into tool output. The agent will repeat what it sees; sanitize outputs the same way you'd sanitize logs.
Before configuring your agent, test the server the way MCP clients actually talk to it:
- Run the stdio transport by hand: launch the server, feed it a JSON-RPC
tools/listrequest, confirm it responds with your tool's definition. - Call the tool directly with the exact JSON your agent would send, and verify the output shape.
- Test the failure paths: wrong input, missing file, API down. An agent that gets a clean error can recover; one that gets a crash cannot.
If your SDK ships a test client or inspector (the Python SDK's inspector tool is handy), use it โ it shows you exactly what the agent will see.
Step 5 โ Wire it into your agent and prove the value
Now the real test: configure your server in your agent client (Claude Desktop, Claude Code, or whatever you use) and run a task that requires the tool. Two checks matter:
- Does the agent discover and call the tool when the task needs it? If the description was good, it will โ and this is where a vague description fails loudly.
- Does the output actually help? A tool that "works" but returns output the agent can't use is worse than no tool. Iterate on the output shape until it's directly actionable.
This is the same discipline as testing an agent skill โ the test is a real task, not a unit test.
Step 6 โ Ship it the way other people will use it
If this server is just for you, stop at step 5. If others will use it, ship with the basics that make a server trustworthy in 2026:
The production checklist
- A README that says what it does and doesn't do. "Reads local markdown and answers questions about it" โ honest boundaries beat grand claims.
- A config snippet for the common clients, so a user goes from repo to working server in one paste.
- Least-privilege defaults. Request the narrowest permissions your tools need. If your server can read a directory, say so and default to that, not to the whole disk.
- A failure-mode note. Document the one or two ways it can misbehave and what the user should do. This is a trust signal โ see the security checklist for MCP servers for the full list of what "safe to run" means.
Hosting an MCP-backed agent has the same boundary discipline: see agent runtime deployment and hosting for API, worker, queue, secrets, and rollback design.
Before you call it done, run through:
Common mistakes
Bottom line
- [ ] Tools are discoverable and correctly described (agent calls them unprompted)
- [ ] Errors return as clean messages, never crashes
- [ ] External calls have timeouts
- [ ] Input validated before side effects
- [ ] No secrets in tool output or logs
- [ ] Least-privilege scope documented and enforced
- [ ] README with a working config snippet
- Building before proving the round trip. A trivial first tool that works end to end de-risks everything; jumping straight to your complex tool makes debugging miserable.
- Vague tool descriptions. The agent can't read your mind โ a tool called
run_querywith description "does things" will be called unpredictably. - Returning raw errors. Throwing exceptions instead of returning messages leaves the agent with a dead end instead of a recoverable path.
- Over-scoping the first server. Tools, resources and prompts, multiple transports, auth, logging โ in v1 you want one good tool on stdio. Add surface area when a user asks for it.
- Skipping the manual JSON-RPC test. Configuring your agent first and debugging through it is slow and confusing; talk to the server directly first.
Building an MCP server is the rare integration task that's genuinely approachable: a small spec, a solid SDK, and a clear path from empty directory to a working tool in an afternoon. Prove the round trip with one trivial tool first, describe your tools like you'd brief a colleague, return errors as recoverable data, and test against a real agent task before you ship. The next action this week: scaffold a project with the official SDK and get one toy tool answering tools/list by hand โ from there it's all additive.
Next: make sure the server you build is safe to run with the MCP security checklist.
FAQ
How long does it take to build a first MCP server?
A working tool on stdio is realistic in an afternoon with the official SDK โ the spec is deliberately small. Production hardening (auth, logging, timeouts, docs) is where the extra days go, and it's usually worth it.
Should I use an SDK or hand-roll the JSON-RPC?
Use the official SDK (Python or TypeScript). The protocol has enough edge cases in transports and lifecycle that hand-rolling buys you nothing but debugging time.
Do I need both a tool and a resource in my first server?
No. One well-built tool that solves a real problem beats a server that half-implements all three capability types. Add resources and prompts only when a user actually needs them.
Which transport should my server use โ stdio or HTTP?
Start with stdio; it's the default for desktop agents and the simplest to test by hand. Move to HTTP when you need to serve remote clients or multiple users, and only then invest in auth.
How do I know my server is actually good and not just working?
When an agent discovers and calls your tool on a real task without prompting, and the output directly resolves the task. That's the bar โ and it's why the real-task test in step 5 matters more than any unit test.
Ready to turn this into a launch plan?
Get the Agent & SEO Launch Sprint for $299: a focused audit, a dated 14-day roadmap, and one follow-up implementation call.