How to Build an MCP Server: A Developer's Guide
Picking an SDK, defining your first tool, choosing a transport, and testing it before a real agent ever touches it — the practical steps from an empty folder to a working MCP server.
Building an MCP server means three things: register a tool with a clear name and description, pick a transport (stdio for local use, Streamable HTTP for remote), and test it with the official MCP Inspector before pointing a real agent at it. The official SDKs cover ten languages and share one conformance suite, so the language choice matters less than the design of the tools themselves — narrow, well-described, and few in number beats one flexible tool that tries to do everything. This guide walks through each step with a working code example, plus the transport and design decisions that most tutorials skip.
Do You Actually Need to Build One?
Before writing any code, it's worth checking whether the server you're about to build already exists. By mid-2026, public registries were tracking roughly 9,400 distinct MCP servers, up 38% in just four months from about 6,800 at the end of 2025 (Digital Applied, 2026). For common categories — CRMs, databases, search, calendars — the odds a compatible server already exists are high, and connecting to one takes minutes instead of days. What Is an MCP Server? covers how the protocol works end to end if you want the fundamentals first; this guide assumes you already know what an MCP server is and want to build one, usually because you're exposing something proprietary — an internal API, a specific dataset, a product catalog — that nothing public covers yet.
Pick a Language and SDK
MCP isn't tied to one language. The Model Context Protocol organization, governed by the Linux Foundation, maintains official SDKs for TypeScript, Python, Java, Kotlin, C#, Go, PHP, Ruby, Rust, and Swift, all built against the same conformance test suite — a server written in any of them speaks the identical wire protocol. In practice, most new servers are written in Python or TypeScript, mainly because both ship high-level, decorator-based APIs that turn a plain function into a fully-described MCP tool in a few lines. If your existing backend is already in Java, Go, or Rust, there's no protocol-level reason to switch languages just to add an MCP server — the SDK for your stack already exists.
The Three Things a Server Exposes
An MCP server exposes some combination of three primitives — tools (functions the agent can call), resources (data it can read), and prompts (reusable instruction templates). What Is an MCP Server? covers all three in depth; in practice, the vast majority of servers — including the one you're about to build — expose tools almost exclusively, since that's what lets an agent take an action instead of just reading a static blob.
Build a Minimal Server, Step by Step
The shape of a minimal server is the same across SDKs: create a server instance, register one or more tools, then run it. Here's a complete, working example in Python using the official SDK's high-level API:
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("product-search")
@mcp.tool()
async def search_products(query: str, max_price: float | None = None) -> str:
"""Search for purchasable products matching a query.
Args:
query: What the user is looking for, e.g. "wireless earbuds"
max_price: Optional upper price bound in USD
"""
results = await run_search(query, max_price)
return format_results(results)
if __name__ == "__main__":
mcp.run(transport="stdio")
Four things are doing real work here: the @mcp.tool() decorator, which registers the function and generates its JSON schema from the type hints; the docstring, which becomes the tool's description — the text the agent actually reads to decide when to call it; the type hints, which define which arguments are required versus optional; and mcp.run(), which starts the server on whichever transport you pick. Run it, and it's a working MCP server. The rest of this guide is about making it good enough to actually ship.
Pick a Transport: stdio vs. Streamable HTTP
An MCP server needs exactly one transport, and the decision is mostly about who's calling it. stdio — the server runs as a local subprocess and talks to its one client over standard input/output — is the default for anything a single user runs locally, like Claude Desktop or a CLI agent. It's what the example above uses, and it's the fastest path from zero to a working server.
For anything remote — a server other people's agents connect to over the network — the current standard is Streamable HTTP, introduced in the 2025-03-26 spec revision and carried forward into the November 2025 revision. It replaces the older two-endpoint HTTP+SSE transport from the original 2024-11-05 spec with a single endpoint: clients POST JSON-RPC messages, and the server either replies directly or upgrades the response to a Server-Sent Events stream for anything long-running. HTTP+SSE is now officially deprecated — platforms are retiring it on real deadlines (Atlassian's Rovo MCP server, for one, dropped it on 2026-06-30) — so there's little reason to build a new remote server on it in 2026. If your server needs to serve more than one client at a time, build on Streamable HTTP from day one.
Test It Before Anyone Else Does
Before pointing a real agent at your server, use the MCP Inspector — the official visual testing tool maintained alongside the SDKs, with over 10,000 GitHub stars. Run npx @modelcontextprotocol/inspector against your server, and it opens a browser UI that calls tools/list and tools/call directly, so you can see the exact schema an agent will see and manually trigger each tool with test arguments before anything talks to it automatically. It catches most of the embarrassing bugs — a missing description, a schema that doesn't match the function signature, a tool that throws instead of returning a usable error — in minutes instead of after a confused agent hallucinates its way around them.
Design Tools an Agent Will Actually Call Correctly
A server that runs isn't the same as a server an agent will use well. A few things matter more than they look like they should:
- Write the docstring for the model, not for a teammate. The agent decides whether to call a tool based almost entirely on its name and description — vague copy like "handles product stuff" gets skipped or misused far more often than a precise one-liner with a concrete example.
- One tool, one job. A
manage_productstool that takes anactionparameter ("search", "create", "delete") forces the agent to guess the right combination of arguments; three separate tools with narrow, obvious purposes are easier for a model to pick correctly. - Fail with structure, not exceptions. Return a clear, readable error string or object instead of letting an unhandled exception crash the call — the agent can often recover and retry differently if it understands what went wrong.
- Keep argument counts small. Every parameter is something the agent has to correctly infer from a conversation; two or three well-named arguments outperform an eight-field configuration object almost every time.
None of this is unique to MCP — it's the same discipline that makes a good REST API good — but it matters more here because there's no human reading the docs before the first call.
Ship It: Deploy and Get Discovered
Once it works and tests clean in Inspector, deploy it wherever you'd run any other long-lived process or HTTP service — a container, a serverless function with a persistent endpoint, whatever your team already uses. The MCP-specific step is getting found: submit it to the official MCP Registry (registry.modelcontextprotocol.io) and, for broader reach, community directories like PulseMCP and Smithery, which is how most developers actually discover servers to connect to rather than searching GitHub by hand.
Where IntentLink Fits In
IntentLink's own server is a working example of most of this in production: it's built on Streamable HTTP, exposes a small number of narrowly-scoped tools (search_products, search_travel), and every result comes back with a live, trackable purchase link already attached — so a tool call can end in an actual transaction, not just a suggestion. If you're building a server for your own product and want commerce in the mix without standing up a whole affiliate integration yourself, the quick-start guide walks through connecting to it over MCP or REST in a few minutes.
FAQ
Which language should I use for my first MCP server?
Python or TypeScript, in most cases — both have high-level SDKs (like Python's FastMCP-style decorators) that turn a plain function into a fully-described tool in a few lines. If your team's existing backend is in Java, Go, C#, Kotlin, Rust, Swift, or PHP, use that instead; the Model Context Protocol org maintains an official SDK for each, and they all speak the identical wire protocol.
Do I need FastMCP or another framework, or is the official SDK enough?
The official SDK is enough for almost every server. High-level wrappers like FastMCP live inside the official Python SDK itself rather than being a separate third-party dependency — it's the decorator-based API (@mcp.tool()), not an alternative to the SDK.
Should I use stdio or Streamable HTTP?
stdio for anything run locally by a single user or client, like a CLI agent or Claude Desktop. Streamable HTTP for anything remote that multiple clients connect to over a network — it's the current standard, replacing the deprecated HTTP+SSE transport from MCP's original 2024-11-05 spec.
How do I test a server before connecting it to a real agent?
Run the MCP Inspector (npx @modelcontextprotocol/inspector) against it. It's the official testing tool and gives you a browser UI to call tools/list and tools/call directly, so you can verify schemas and try each tool with test arguments before any agent touches it.
How many tools should one server expose?
As few as the job actually requires. Narrow, single-purpose tools are easier for a model to select correctly than one flexible tool with a mode parameter — most well-designed servers expose a handful of tools, not dozens.
Where do I publish an MCP server so agents can find it?
Submit it to the official MCP Registry (registry.modelcontextprotocol.io), and list it in community directories like PulseMCP or Smithery for broader discovery — most developers find servers to connect to through these rather than searching for them individually.
Sources: Digital Applied, "MCP Ecosystem H1 2026 Retrospective: Adoption Data Points" (2026); Model Context Protocol specification and SDK documentation, modelcontextprotocol.io (2026).