If you have wired an AI assistant into a database, a file store, or an internal API lately, you have probably run into the same wall everyone hits: every integration is a one-off. MCP server setup is the answer the industry settled on for that problem. The Model Context Protocol, an open standard introduced by Anthropic in late 2024 and since adopted by OpenAI, Google and Microsoft, gives AI applications a single, predictable way to reach external systems. Instead of writing bespoke glue for each model and each data source, you build one server that speaks a documented protocol, and any compatible client can use it.
- MCP is an open, JSON-RPC 2.0 protocol that standardizes how AI hosts connect to external tools and data, often described as a USB-C port for AI applications.
- A server exposes three primitives to clients: tools, resources and prompts. Clients can offer their own capabilities back, such as sampling and elicitation.
- Two official transports cover most needs: stdio for local processes and Streamable HTTP for remote servers.
- Official SDKs for Python, TypeScript and several other languages make a working server a matter of a few dozen lines.
- You test a server by wiring it into a host like Claude Desktop or by running the MCP Inspector against it.
What the Model Context Protocol actually is
The official documentation frames MCP with a hardware analogy. Before USB-C, every device needed its own cable and its own port. The connector standardized the physical link so any compliant device could plug into any compliant host. MCP plays the same role for AI software. It is an open-source standard for connecting AI applications to the systems where real work lives, whether that is a local SQLite file, a Notion workspace, a Figma design, or a company data warehouse.
The protocol deliberately keeps a narrow scope. It defines how context moves between an AI application and an external program, and nothing more. It does not tell you which model to run, how to manage your prompt budget, or how to orchestrate an agent loop. That restraint is the reason it spread so fast. A server author does not need to know whether the client is Claude, ChatGPT, or a custom internal tool. A client author does not need to know how a given server fetches its data. Both sides agree on the wire format and stay independent of each other.
That independence is worth sitting with for a moment, because it is the whole point. Anthropic could have shipped a proprietary plugin format tied to its own products. Instead the specification, the SDKs, and a large set of reference servers were released under open licenses. By early 2026 the protocol had backing across the industry, and according to Wikipedia's tracking of the ecosystem, official SDKs existed for TypeScript, Python, C#, Java, and Swift, with a Go SDK maintained alongside Google and a C# SDK maintained alongside Microsoft. The same overview counted more than 500 public servers covering databases, file storage, messaging platforms, and project management systems.
The architecture behind MCP server setup
Understanding MCP server setup starts with the shape of the system. MCP follows a client-server model, but the naming trips people up, so it pays to be precise. The architecture overview names three participants. The host is the AI application itself, for example Claude Code or Claude Desktop. The client is a connector object the host creates, one per server, that maintains a single dedicated link. The server is the program that actually supplies context, and it can run on your laptop or on a remote platform.
A host that connects to several servers spins up several clients, each holding its own connection. If Visual Studio Code opens a link to a Sentry server and another to a local filesystem server, the editor instantiates two separate client objects. This one-client-per-server design keeps connections isolated and makes capability negotiation cleaner, since each pairing settles its own terms.
The protocol splits into two conceptual layers. The data layer is the inner layer, and it defines a JSON-RPC 2.0 exchange: the message structure, the lifecycle, and the primitives that carry context. The transport layer is the outer layer, and it handles the actual communication channel, message framing, and authentication. The neat consequence of that separation is that the same JSON-RPC messages flow unchanged regardless of whether they travel over a local pipe or an HTTP connection. You write your server logic once, and the transport becomes a configuration detail rather than a rewrite.
How a connection comes alive
MCP is a stateful protocol, so every session opens with a handshake. The client sends an initialize request carrying a protocolVersion field, its declared capabilities, and identifying information. The official walkthrough uses the version string 2025-06-18 in its example. The server replies with its own protocol version, its capabilities, and its server info. If the two sides cannot agree on a compatible version, the connection is supposed to terminate rather than limp along. Once they agree, the client fires a notifications/initialized message to signal it is ready, and normal traffic begins.
This negotiation matters because it lets each side advertise exactly what it supports. A server might declare that it offers tools and that it can emit a notification whenever its tool list changes. A client might declare that it can handle user-input requests. Each party then avoids calling methods the other cannot service, which keeps the conversation efficient and predictable.
The three server primitives: tools, resources and prompts
The most interesting part of the protocol, and the part you spend the most time on during MCP server setup, is the set of primitives a server can expose. The specification defines exactly three. Tools are executable functions the AI can invoke to take an action, such as querying a database, calling an API, or writing a file. Resources are data sources that supply context to read, such as file contents, database records, or API responses. Prompts are reusable templates that structure an interaction, such as a system prompt or a few-shot example set.
Each primitive type follows a consistent method pattern. Discovery happens through a */list method, retrieval through a */get or read method, and for tools, execution through tools/call. A client typically begins by calling tools/list to learn what is available, then invokes specific tools as the model decides to use them. Because listing is a live operation rather than a static manifest, a server can change its offerings at runtime and tell connected clients to refresh.
Tool discovery and execution in practice
Walk through the lifecycle of a single tool. The client sends a tools/list request, which carries no parameters. The server answers with an array of tool objects, and each object includes a unique name, a human-readable title, a description explaining when to use it, and an inputSchema written as JSON Schema. That schema is the contract. It declares which arguments exist, which are required, and what types they take, so the host can validate a call before it ever reaches your code.
When the model decides to act, the client sends a tools/call request naming the tool and passing arguments that match the schema. In the documentation example, a weather tool named weather_current receives a location of San Francisco and a units value of imperial. The server runs its logic and returns a content array. That array can hold text, images, or other typed content, which is why a single tool can return a rich, multi-format answer rather than a bare string. The host then feeds that result back into the conversation as fresh context for the model.
Tool names are namespaced per server and should be specific. The documentation recommends a clear pattern such as calculator_arithmetic rather than a vague calculate, so that a host combining tools from many servers never faces a collision.
Why notifications keep clients honest
A server whose tool set never changes is simple. Real servers are rarely that static. Tools can appear when a dependency comes online, disappear when a permission is revoked, or change shape after a configuration update. To handle that, a server that declared listChanged during initialization can send a notifications/tools/list_changed message. Following JSON-RPC notification semantics, that message carries no id and expects no reply. The client reacts by re-issuing tools/list and updating the model's available capabilities on the fly. The result is a connection that stays accurate without the client polling for changes.
Client primitives that make servers smarter
MCP is not a one-way street. The protocol also defines primitives that clients can expose back to servers, and these unlock patterns that surprise people new to the standard. The most powerful is sampling. Through the sampling/createMessage method, a server can ask the client's host to run a language-model completion on its behalf. This is how a server author gets access to an LLM without bundling a model SDK or an API key into the server itself. The server stays model-agnostic, and the host decides which model answers.
The second client primitive is elicitation. Using elicitation/create, a server can ask the user for more information mid-operation or request confirmation before doing something consequential. A server that is about to delete records, for instance, can pause and elicit an explicit yes. The third client capability is logging, which lets a server stream debug and monitoring messages to the client. There is also an experimental cross-cutting primitive called tasks, which wraps a request in durable execution so that an expensive or long-running job can be tracked and its result retrieved later.
Together these client-side features turn a server from a passive data tap into something closer to a collaborator. A well-built server can reason with the host's model, check in with the user when it is uncertain, and report its progress, all without owning any model infrastructure of its own.
Transports: choosing how your server talks
Once you understand the primitives, the next decision in MCP server setup is the transport. The protocol ships with two official options, and they map cleanly onto two deployment styles. Stdio uses standard input and output streams to talk between processes on the same machine. It has no network overhead, which makes it the fastest path and the natural choice for a local server that a host launches as a child process. When Claude Desktop starts the filesystem reference server on your own computer, it uses stdio.
The Streamable HTTP transport is built for distance. It sends client-to-server messages over HTTP POST and can stream responses back using Server-Sent Events when a server wants to push incremental output. This transport carries standard HTTP authentication, so a remote server can require bearer tokens, API keys, or custom headers, and the documentation recommends OAuth for obtaining those tokens. The hosted Sentry server is a good example of a remote server that many clients reach at once over Streamable HTTP. A rough rule holds up well: reach for stdio when the server lives next to the host, and reach for Streamable HTTP when it lives somewhere else and needs to serve many clients with real authentication.
Building your first server step by step
The theory is dense, but the practice is light, because the official SDKs absorb most of the protocol machinery. The build-a-server tutorial walks through a weather server that exposes two tools, get_alerts and get_forecast, and connects it to Claude for Desktop. The Python path is the quickest to read.
You begin by creating a project with the uv tool, then add the dependencies with uv add "mcp[cli]" httpx. The mcp package is the official Python SDK, and httpx handles the outbound web requests the weather tools need. Inside the server file you import FastMCP and instantiate it with a name:
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("weather")
FastMCP reads your Python type hints and docstrings to generate tool definitions automatically, which keeps the boilerplate near zero. You define a tool by writing an ordinary async function and decorating it with @mcp.tool(). The function signature becomes the input schema, and the docstring becomes the description the model reads. At the bottom of the file you start the server with mcp.run(transport="stdio"), and you launch the whole thing with uv run weather.py. That is the entire shape of a working server: a name, one or more decorated functions, and a run call.
The TypeScript route mirrors the same idea with different idioms. You initialize an npm project and install the SDK with npm install @modelcontextprotocol/sdk zod@3, where Zod supplies runtime schema validation for tool inputs. The TypeScript SDK repository documents the server classes and the registration calls, and the resulting server exposes the same tools-list and tools-call surface that a Python server does. Because both speak the identical protocol, a host cannot tell which language built the server it is talking to.
Connecting and testing what you built
A server that no client can reach is not much use, so the final stretch of MCP server setup is wiring it into a host and proving it works. For Claude Desktop, you edit a JSON configuration file. On macOS that file lives at ~/Library/Application Support/Claude/claude_desktop_config.json, and on Windows it sits under the equivalent AppData path. You register your server there by giving it a name and the command that launches it, for example a uv --directory invocation pointing at your project folder and your server file. After you restart the host, the server's tools appear and the model can call them, subject to user approval on each invocation.
Before you involve a full host, the faster feedback loop is the MCP Inspector, a development tool from the core project. The Inspector connects directly to your server, lists its tools, resources and prompts, and lets you invoke them by hand and read the raw responses. That lets you confirm your schemas validate and your handlers return the right content before any model enters the picture. When something misbehaves, the Inspector tells you whether the fault sits in the protocol layer or in your own logic, which saves a great deal of guesswork.
Tools run with user approval in compliant hosts. The host intercepts each tools/call, can show the user what is about to happen, and only then routes the call to your server. Design your tool descriptions so a person reading the approval prompt understands the action.
The SDK and specification landscape in 2026
The standard moved quickly in its first eighteen months. By the first half of 2026 the official SDKs spanned a broad set of languages, and the major repositories saw active maintenance, with the TypeScript, Python, Go and C# SDKs all receiving updates in mid-June 2026 according to the project's GitHub organization. The SDKs are organized into tiers based on feature completeness and maintenance commitment, but each one provides the same core ability to expose tools, resources and prompts from a server and to build clients that connect to any compliant server.
The specification itself is versioned by date, which is why you see strings like 2025-06-18 in the handshake. New revisions add capabilities while preserving the negotiation mechanism that lets old and new participants find common ground. That versioning discipline is part of why adoption stuck. A client built against one revision keeps working against servers built against another, as long as both honor the handshake and fall back to a shared version. For anyone tracking the wider shift toward agentic tooling, the steady cadence of these releases is a useful signal, and you can follow that thread through our ongoing AI coverage.
Where MCP sits in the agent stack
It helps to end by placing the protocol in context, because MCP is not trying to be the whole stack. It is the connective tissue. Above it sits the host and its model, which decide what to do. Below it sit your data and your actions, which know how to do specific things. MCP is the agreed grammar between those layers, and its value comes precisely from how little it tries to own. By standardizing only the exchange, it lets the model layer evolve on its own schedule and lets the integration layer grow a public ecosystem of reusable servers that any host can adopt.
For a developer, the practical payoff is leverage. Build one MCP server for your internal API, and every compliant assistant your team uses can reach it without further work. Publish that server, and the wider community can too. The setup cost is modest, a name and a handful of decorated functions over a chosen transport, and the SDKs carry the protocol weight so you do not have to. That combination of a narrow, well-documented contract and broad client support is what turned a single company's proposal into something close to default infrastructure for connecting AI to the systems it needs. The protocol will keep changing, but the core bet, that a shared connector beats a thousand custom cables, looks settled.