What you are actually building when you build an MCP server
A custom MCP server is the shortest path between a language model and the systems your business actually runs on. The Model Context Protocol handles discovery, schemas, transport and authorization; you write only the part that knows your data. That division is the point, and it makes the build smaller than most teams expect.
This guide covers the build: what to expose, how to write the server, how to connect it to an MCP client, how to test it, and what must be right before it touches production. For background on what the protocol is and why it exists, read our explainer on the Model Context Protocol first. Everything below assumes you already want to build one.
Details here reflect the specification and quickstarts at modelcontextprotocol.io as of September 2026, where the current protocol revision is dated 2026-07-28. MCP revises on a dated schedule, and package names and even the connection handshake have moved between revisions. Learn the mechanism here; copy the exact import lines from the official quickstart on the day you build.
The three roles: MCP host, MCP client, MCP server
MCP names three participants. The host is the AI application — Claude Desktop, an IDE, or your own product. The host creates one MCP client per server it talks to, each holding a dedicated connection. The MCP server is your program: it provides context and executes actions on request. Underneath, a data layer carries JSON-RPC 2.0 messages and a transport layer moves the bytes.
Servers expose three primitives. Tools are executable functions the model calls to take an action. Resources supply context, like a file or a database schema. Prompts are reusable templates. Each has a list method for discovery, and tools add `tools/call` to execute. Most first servers expose tools only, which is a fine place to stop.
The current revision is stateless: every request carries the protocol version and the caller's capabilities in a `_meta` field, and a client discovers what a server supports via `server/discover`. If you learned MCP from a tutorial built around a persistent initialize handshake, check the spec — though your SDK should be hiding this level from you entirely.
Design the tools before you write the code
Tool design decides whether an AI agent uses your server well; code quality barely matters by comparison. A model picks a tool from its name, description and input schema alone, so those three fields are the actual product.
Give each tool one job a person could name out loud. Namespace the name so it stays unambiguous across every server the host has loaded — `invoices_create_draft` beats `create`. Write the description for the model, saying when to use the tool and when not to. Define the inputSchema as real JSON Schema with typed, described fields, because that schema is what stops malformed calls before they reach your business systems.
Resist mirroring your whole REST API. Sixty auto-generated tools burn context and make tool selection worse; ten well-named tools matching how work actually gets done beat them on every use case. Separate read tools from write tools, which is what lets you approve them at different risk levels later. And return a compact labelled summary rather than a raw JSON blob the LLM has to reverse-engineer.
Build the MCP server in Python or TypeScript
Official SDKs cover TypeScript, Python, C#, Go, Rust, Java, Ruby, Swift, PHP and Kotlin, published under the modelcontextprotocol organization on GitHub and graded into support tiers. Pick the language your integration code already lives in; the protocol is identical across all of them.
In Python, the quickstart uses `uv init` then `uv add "mcp[cli]"`. Import the server class from `mcp.server`, instantiate it with a name, and decorate async functions with `@mcp.tool()`. The SDK turns your type hints and docstring into the tool's schema and description, so the docstring is not documentation — it is what the model reads. Finish with `mcp.run(transport="stdio")` under a `__main__` guard and the file is a runnable server.
In TypeScript, install the server package plus `zod`, create a server instance with a name and version, then call `server.registerTool()` for each tool with a description, a `zod` inputSchema and an async handler returning a content array. Construct a stdio server transport and `await server.connect(transport)`. Build before you connect it to anything — an unbuilt TypeScript server is the most common reason a new server silently fails to appear.
One gotcha catches everybody. On stdio, standard output is the protocol channel, so anything printed to stdout corrupts the JSON-RPC stream and the connection dies without a useful error. Log to stderr: `console.error` in Node, a stderr logger in Python, never a bare `print`.
Connect the server to Claude Desktop or another MCP client
For a local server the host launches your program as a child process and talks over stdio. In Claude Desktop that lives in `claude_desktop_config.json`, at `~/Library/Application Support/Claude/` on macOS and `%APPDATA%\Claude\` on Windows. Add an entry under the `mcpServers` key with a name, a `command` and an `args` array, then quit and relaunch the app fully — closing the window is not a restart.
Use absolute paths everywhere in that config; relative paths are the next most common failure, because the host does not launch your server from the directory you assume. Pass secrets through an `env` object in the same entry instead of hardcoding them.
Nothing in your server is Claude-specific. Any host with MCP support — other desktop apps, IDEs, agent frameworks, your own product — can integrate the same binary through its own MCP client. That portability is the payoff of building against a standardized protocol instead of a custom integration per host, and it is what lets you connect AI agents from different vendors to one server.
Test with the MCP Inspector and read the logs
The MCP Inspector is the official tool for driving a server directly, with no AI agent in the loop. Run `npx @modelcontextprotocol/inspector` for the web UI, `--cli` for a scriptable client you can put in CI, or `--tui` for a terminal interface. List the tools, call them with hand-written arguments, read the raw responses.
That separates two very different bugs: a tool that does not work, and a tool the model does not understand. The Inspector proves the first. Only when it is clean should you connect a host and watch tool selection in real time.
When a server refuses to connect, read the logs instead of guessing. Claude Desktop writes to `~/Library/Logs/Claude` on macOS and `%APPDATA%\Claude\logs` on Windows, with a general `mcp.log` plus one file per server carrying that server's stderr. Then run the exact command from your config by hand in a terminal — most failures reproduce instantly.
Stdio or Streamable HTTP: transport and deployment
MCP defines two transports, and the choice sets your whole deployment story. Stdio runs the server as a local process over standard streams, typically serving one MCP client, with no network exposure. Streamable HTTP uses HTTP POST with optional Server-Sent Events for streaming, serves many clients, and supports standard HTTP authentication including bearer tokens and API keys, with OAuth recommended for obtaining them.
For a personal tool on one laptop, stdio is right. For anything touching shared business systems, deploy over Streamable HTTP: one deployment instead of an install per laptop, credentials held centrally rather than in every user's config file, one audit log, and real-time data from the source of record instead of a stale local copy. Treat that deployment like any other production service — containerized, behind your own authorization, rate-limited on expensive tools, with every call logged against the identity that made it.
Security rules a self-built MCP server must follow
The specification states two of its security requirements as hard rules. On tokens: an MCP server MUST NOT accept any token that was not explicitly issued for that server. Validating the audience claim is not optional, and forwarding a client's token to a downstream API is named in the spec as a forbidden anti-pattern. On state: because the protocol is stateless, a server needing continuity mints its own handle and gets it back as a tool argument, and possession of that handle must never be treated as authentication. Generate handles randomly, bind them server-side to the authenticated user, reject them from anyone else.
Keep scopes small. Wildcard scopes like `all` or `full-access` mean one leaked token unlocks everything the server can reach. Start from a minimal read-only set and challenge for more only when a privileged tool is first called.
Then the unglamorous rule that causes the most real damage: your tools execute with your server's privileges. A generic `run_sql` tool is a database account handed to a language model; a filesystem tool with no path allowlist is your home directory. Narrow each tool to the operation it needs, use a least-privilege service account, and make destructive actions require confirmation rather than trusting prompt wording to prevent them.
When to build your own MCP server, and when not to
Do not build what already exists. There is a public collection of reference server implementations, and a growing number of vendors ship an official server for their own product. If a maintained one covers your CRM or repository host, install it and spend the time elsewhere.
Build your own when your business logic lives in a system nobody has wrapped — an internal database, a legacy ERP, a bespoke scheduling engine; when you need a narrow, safe surface over a dangerous API, exposing four reviewed operations instead of a general-purpose HTTP tool; or when you need per-tool authorization and audit the vendor's server does not provide.
We build custom MCP servers as part of integration work when a client's operational data has no off-the-shelf server, usually alongside the AI agent that consumes it. Builds start at $7,500, typical timeline around 30 days, with model costs bring-your-own-key at roughly $30 to $150 a month paid straight to the provider. If you are earlier than that, the free automation audit is a three-minute questionnaire that ranks which workflow is worth connecting first — no call, no cost. The free automation playbook covers how these builds get scoped.
Frequently asked questions
Common questions from teams building their first MCP server.
What language should I write an MCP server in?
The one your integration code already lives in. Official SDKs cover TypeScript, Python, C#, Go, Rust, Java, Ruby, Swift, PHP and Kotlin, and each implements the same protocol, so the model cannot tell the difference. Python and TypeScript have the most examples, which matters only for your first hour.
How is an MCP server different from a REST API?
A REST API is designed for a programmer who reads documentation; an MCP server is designed for an LLM that reads a tool list at runtime. It ships machine-readable schemas and standardizes discovery, execution and authorization identically for every client. Most MCP servers are a thin layer over existing APIs adding the descriptions and guardrails a model needs.
Do I need to be a developer to build an MCP server?
Yes, though less of one than you would expect — a server with two or three tools is under a hundred lines in either SDK. The hard parts are not code: deciding which operations to expose, writing descriptions the model interprets correctly, and getting authorization right.
Can one MCP server serve multiple AI agents at once?
Over Streamable HTTP, yes — a remote server routinely serves many MCP clients concurrently, which is why it is the right transport for shared business systems. A stdio server typically serves only the single client that launched it as a child process.
How do I connect an MCP server to a database safely?
Do not expose arbitrary SQL. Write one tool per question you actually want answered, parameterize every query, and connect with a role that reads exactly the tables involved. If writes are needed, put them in a separate tool with its own confirmation step and log every call against the identity behind it.
Do MCP servers work with models other than Claude?
Yes. MCP is an open standard, not an Anthropic-only feature, and adoption spans multiple model vendors, IDEs and agent frameworks. Your server talks to an MCP client, and the client decides which model sits behind it, so one server works across hosts running different LLMs.
How long does it take to build a production MCP server?
A prototype exposing a handful of tools is an afternoon. Production time goes to authorization, error handling, deployment and iterating on tool descriptions until the agent reliably picks the right tool. Budget days for the prototype, weeks before it touches customer data.
