The Model Context Protocol changed its foundations this summer. Since protocol version 2026-07-28, MCP is stateless. Every request carries the protocol version and capabilities it relies on, and a server can process each one on its own without remembering an earlier handshake.1 For anyone who built against the original design, which Anthropic open-sourced in November 2024,2 that is the most important thing to know about MCP today. It is also a good place to start understanding what the protocol actually does.
This article explains MCP from the wire up: the roles in a connection, the messages, the primitives, the transports, and the parts of security the protocol deliberately leaves to you. It is based on the current specification and architecture documentation at modelcontextprotocol.io, as of 24 September 2026. The specification link goes to the versioned page for this revision, so it will stay accurate after the next one.
The problem MCP solves
Before MCP, connecting a model to a system meant writing a bespoke integration for each pairing of AI application and data source. Anthropic's announcement put it plainly: "Every new data source requires its own custom implementation."2 MCP replaces those pairings with one protocol. A data source is exposed once as an MCP server, and any MCP-capable application can use it.
The specification credits the Language Server Protocol as inspiration. LSP standardised how editors add support for programming languages, and MCP standardises how AI applications add context and tools.3 The analogy is useful. LSP succeeded because it moved language intelligence out of every editor and into one server per language. MCP makes the same bet for integrations.
The three roles
MCP has three participants:1
- Host. The AI application the user interacts with, such as Claude Desktop, Claude Code or Visual Studio Code.
- Client. A component inside the host that keeps a connection to one server. The host creates one client per server.
- Server. A program that provides context and capabilities. It may run locally on the same machine or remotely as a service.
Free to reuse under CC BY 4.0 with a link to this article. Download
The one-client-per-server rule is easy to overlook, and it shapes a lot. Each server sees only its own connection, which keeps servers isolated from one another. The host is the only place where everything comes together: the model, the user, and all the servers.
Two layers: data and transport
MCP separates what is said from how it travels.1
The data layer is a JSON-RPC 2.0 protocol. It defines discovery, the server primitives (tools, resources, prompts), client features, and utilities such as notifications and progress tracking.
The transport layer moves those messages. The specification defines two transports:
| Transport | How it works | Typical use |
|---|---|---|
| stdio | Standard input and output between processes on the same machine | Local servers launched by the host, usually serving one client |
| Streamable HTTP | HTTP POST for client-to-server messages, with optional Server-Sent Events for streaming | Remote servers serving many clients. It supports standard HTTP authentication, and the specification recommends OAuth for obtaining tokens. |
Because the message format is identical on both transports, a server can usually be moved from local to remote without changing its logic.
What a request looks like now
The 2026-07-28 revision puts everything a server needs into each request's _meta field: the protocol version, the client's capabilities and, unless configured otherwise, the client's identity.1 A tool call looks like this (abbreviated from the specification's example):
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "weather_current",
"arguments": { "location": "Oslo", "units": "metric" },
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": { "name": "example-client", "version": "1.0.0" },
"io.modelcontextprotocol/clientCapabilities": { "elicitation": {} }
}
}
}
Servers must implement server/discover, which returns the versions they support, their capabilities and their identity. Clients may call it first, but they don't have to. Because every request is self-describing, a client can send any request directly and handle an UnsupportedProtocolVersionError if the server rejects the version.1 Discovery responses, like tool lists, carry caching hints: ttlMs for freshness and cacheScope for who may reuse the response.1
The primitives
Primitives are the part of MCP most developers work with. Servers can expose three:1
- Tools. Executable functions the model can invoke: querying a database, calling an API, writing a file. Each has a
name, a human-readabletitle, adescription, and aninputSchemain JSON Schema. - Resources. Data that provides context: file contents, database records, API responses.
- Prompts. Reusable templates that structure interactions with the model, such as system prompts or few-shot examples.
Each primitive is discovered with a */list method and retrieved with */get, and tools are executed with tools/call.1 The documentation's example of a database server shows how they fit together: tools to run queries, a resource containing the schema, and a prompt with few-shot examples of using the tools.1
Clients can expose features to servers too. The main one today is elicitation, which lets a server ask the user for more information or for confirmation, through the elicitation/create method.1
Two client features are deprecated as of 2026-07-28:1
- Sampling, which let a server request a completion from the host's model. The documentation now advises new implementations to integrate directly with model provider APIs.
- Logging, which let a server send log messages to the client. New implementations should log to
stderr(for stdio) or use OpenTelemetry.
Beyond the core, optional extensions add functionality that both sides must explicitly support. Examples include Tasks, which gives durable handles for long-running operations, and MCP Apps, which renders interactive UI elements inline.3
Notifications
Servers can tell clients when something changes, for example when a tool is added or removed. Since the stateless revision, notifications are opt-in. The client opens a long-lived subscriptions/listen stream naming the notification types it wants, and the server acknowledges which of them it will honour.1 The documentation is candid about the guarantees: notifications are best effort, especially across reconnects, and clients should also poll to keep results fresh.1
Security is the host's job
MCP's security section starts from an uncomfortable fact: the protocol "enables powerful capabilities through arbitrary data access and code execution paths".3 It sets out three principles:3
- User consent and control. Users must explicitly consent to data access and operations, and keep control of what is shared and done.
- Data privacy. Hosts must obtain explicit consent before exposing user data to servers, and must not send resource data elsewhere without consent.
- Tool safety. Tools represent arbitrary code execution. Hosts must obtain explicit user consent before invoking any tool. Descriptions of tool behaviour, including annotations, should be considered untrusted unless they come from a trusted server.
Then comes the critical caveat: "MCP itself cannot enforce these security principles at the protocol level."3 Consent flows, access controls and data protection are the implementer's responsibility.
When MCP is the right choice, and when it is not
Limitations and open questions
- The protocol is still moving. The 2026-07-28 revision deprecated features and changed the connection model. Expect further change, and choose SDKs that track the specification closely.
- Security depends on hosts. The specification states principles but cannot enforce them, so the quality of consent flows varies between hosts.
- Notifications are best effort, so clients that need current data must poll as well.
- Tool quality is outside the protocol. MCP standardises how a tool is described and called, not whether it is well designed. Poorly named tools with vague descriptions make models perform worse, and no protocol version fixes that.
Frequently asked questions
- Who created the Model Context Protocol?
- Anthropic open-sourced MCP on 25 November 2024. It was created at Anthropic by David Soria Parra and Justin Spahr-Summers, and is developed as an open-source project with a public specification and SDKs.
- Is MCP stateful or stateless?
- As of protocol version 2026-07-28, MCP is stateless. Every request carries the protocol version and the relevant capabilities in its _meta field, so a server can process each request on its own. Servers advertise their versions and capabilities through the mandatory server/discover request.
- What is the difference between MCP tools, resources and prompts?
- Tools are functions the model can invoke to take actions. Resources are data sources that provide context, such as file contents or database records. Prompts are reusable templates that structure interactions with the model. All three are exposed by servers and discovered with list methods.
- Does MCP handle security for me?
- No. The specification sets out principles of user consent, data privacy and tool safety, but states that MCP cannot enforce them at the protocol level. Hosts must obtain explicit user consent before invoking any tool, and tool descriptions from untrusted servers should themselves be treated as untrusted.
Sources
-
Model Context Protocol, "Architecture overview" (documentation for protocol version 2026-07-28). https://modelcontextprotocol.io/docs/learn/architecture ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13 ↩14
-
Anthropic, "Introducing the Model Context Protocol", 25 November 2024. https://www.anthropic.com/news/model-context-protocol ↩ ↩2
-
Model Context Protocol, "Specification" (protocol version 2026-07-28). https://modelcontextprotocol.io/specification/2026-07-28 ↩ ↩2 ↩3 ↩4 ↩5