Architecture guideChecked for spec 2026-07-28

How MCP Works: Hosts, Clients, Servers, and Every Request

A version-aware explanation of MCP architecture, primitives, message patterns, transports, and trust boundaries under the 2026-07-28 specification.

On this page

Version verifiedChecked August 25, 2026 against MCP 2026-07-28. Review method.

The short version

  • An MCP host coordinates the model, user consent, and one isolated client for each connected server.
  • In the modern protocol, every request carries its version and client capabilities; there is no initialization handshake or protocol session.
  • Servers expose three main primitives: user-controlled prompts, application-controlled resources, and model-controlled tools.
  • MCP standardizes messages and trust boundaries, but the host still decides what context to share and which actions to approve.

Model Context Protocol is the common language between an AI application and the services that give it data or actions. It does not run the model, replace an API, or decide whether an action is safe. It defines how an application discovers capabilities, supplies context, calls functions, and receives structured results. The companion MCP vs function calling guide explains how a host translates those capabilities into provider-native tool requests.

This page follows the request lifecycle. For the full role comparison, model placement, product classification, and responsibility matrices, read MCP client vs server vs host.

If you need the definition and wider context before the request mechanics, start with what an MCP server is.

That simple description hides an important version boundary. The current MCP specification dated 2026-07-28 S054 is stateless: every request is self-contained. Articles that begin with an initialize handshake or an Mcp-Session-Id are describing MCP through 2025-11-25, not the modern core. The current changelog records the break explicitly S055.

This guide uses the 2026-07-28 wire model. Legacy behavior is called out where it remains relevant for clients and servers that support both eras.

MCP is a protocol between a host and focused servers

The current architecture separates three roles S054:

MCP is a protocol between a host and focused servers comparison table
RoleWhat it ownsTypical responsibilities
HostThe user-facing AI applicationRuns or calls the model, manages consent, combines context, creates clients, and enforces policy
ClientOne host-to-server protocol relationshipSends MCP requests, declares per-request capabilities, routes results, and manages subscriptions
ServerA focused set of capabilitiesExposes tools, resources, and prompts backed by local code, files, databases, or remote APIs

A host can connect to many servers, but each MCP client communicates with exactly one server. This 1:1 relationship matters because it gives the host a place to isolate permissions and data. A filesystem server does not automatically see what a CRM server returns, and neither server is entitled to the complete conversation. The host decides what each request contains.

User
  |
  v
Host application + model
  |-- MCP client A <----> Filesystem server
  |-- MCP client B <----> Issue-tracker server
  `-- MCP client C <----> Remote database server

“Client” and “host” are therefore not interchangeable. The desktop app, coding agent, or custom assistant is usually the host. The protocol component it creates for one server is the client. The command-line program or HTTP service that supplies capabilities is the server.

Every modern request carries its own protocol context

MCP messages use JSON-RPC 2.0 as their envelope S001. A request has an id, a method, and optional params; its response uses the same id and contains either a result or an error. A notification has a method but no id and receives no response.

Under 2026-07-28, the server must not infer protocol context from an earlier message or from the connection. Each client request includes these reserved _meta fields:

  • io.modelcontextprotocol/protocolVersion, required on every request;
  • io.modelcontextprotocol/clientCapabilities, required even when it is an empty object;
  • io.modelcontextprotocol/clientInfo, recommended but optional; and
  • io.modelcontextprotocol/logLevel, optional and scoped to that request.

A server should identify itself in each result with io.modelcontextprotocol/serverInfo, but that identity is also optional and self-reported. Client and server info help display and debugging; they are not authentication and must not drive security decisions.

Here is the shape of a modern tool call, abbreviated to highlight the protocol envelope:

{
  "jsonrpc": "2.0",
  "id": 17,
  "method": "tools/call",
  "params": {
    "name": "get_weather",
    "arguments": { "city": "Singapore" },
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientCapabilities": {},
      "io.modelcontextprotocol/clientInfo": {
        "name": "example-host",
        "version": "1.0.0"
      }
    }
  }
}

Servers implement server/discover so clients can ask which versions and server capabilities they support. Calling it first is optional for a modern-only client: a client can send its preferred version with an ordinary request and retry after an UnsupportedProtocolVersion error. Discovery is especially useful when a client also supports legacy handshake-era servers. The detailed transition is covered in the stateful-to-stateless migration guide.

Tools, resources, and prompts divide control

Servers advertise three main primitives. They share JSON-RPC mechanics but have different control models, as the server-features overview explains S054.

Tools, resources, and prompts divide control comparison table
PrimitiveUsually controlled byUse it forRepresentative methods
PromptsUserNamed templates and guided workflows a person deliberately selectsprompts/list, prompts/get
ResourcesApplicationReadable context identified by URI, such as a file, schema, or documentresources/list, resources/read
ToolsModel, within host policyFunctions that retrieve information or create side effectstools/list, tools/call

The control labels are a design guide, not permission. A model may propose a tool call, but the host can require confirmation, deny it, alter the arguments, or hide the tool entirely. Likewise, listing a resource does not mean the host must attach it to the model’s context.

Tools use JSON Schema to describe inputs and may describe structured outputs. Descriptions are operational metadata: they help the host and model choose the correct capability, but they are also untrusted input from a separate system. Resources use URIs and MIME types to make context addressable. Prompts package reusable messages and arguments without giving the server control of the whole conversation.

Modern list and read results include cache hints. ttlMs tells a client how long a result may remain fresh, and cacheScope distinguishes public from private caching. Lists should be deterministic so clients can avoid needless prompt churn. These details make a large capability catalog practical without changing the three-primitive mental model.

Three message patterns cover the useful work

The current base protocol defines three interaction patterns: ordinary request/response, Multi Round-Trip Requests, and subscribe/notify. The first handles most work.

Client                         Server
  |--- tools/call -------------->|
  |<-- complete result -----------|

Sometimes the server cannot finish without information only the client can provide: user input through elicitation, a model-generated answer through sampling, or a list of allowed roots. In modern MCP the server does not originate a JSON-RPC request. It returns an InputRequiredResult with resultType: "input_required". The client gathers the requested input, then retries the original method with matching inputResponses. This is the Multi Round-Trip Requests pattern S062.

Client                         Server
  |--- tools/call -------------->|
  |<-- input_required -----------|
  |    [ask user to confirm]     |
  |--- tools/call + response --->|
  |<-- complete result -----------|

For change events that are not tied to one short request, the client opens subscriptions/listen and explicitly names the notification classes it wants. On HTTP, the response is a long-lived SSE stream. On stdio, notifications share the existing byte stream and carry a subscription identifier. This opt-in channel replaces the old HTTP GET stream and the old resource subscribe/unsubscribe methods.

The transport changes delivery, not meaning

The two standard transport bindings are stdio and Streamable HTTP. The transport specification says their protocol semantics are identical S057.

  • With stdio, the host launches a local subprocess. Client requests enter through stdin; server responses and notifications leave through stdout, one JSON-RPC message per line. Logs belong on stderr.
  • With Streamable HTTP, every message is a new POST to one MCP endpoint. A request receives either a JSON response or a request-scoped SSE response stream.

SSE still appears inside modern Streamable HTTP, but it is a response format, not the deprecated two-endpoint “HTTP+SSE transport.” Modern Streamable HTTP has no standalone GET stream, no protocol session ID, and no resumable Last-Event-ID stream. See the complete MCP transport comparison before implementing an HTTP endpoint.

Transport also changes cancellation. A stdio client sends notifications/cancelled because all work shares one stream. For an HTTP request with an SSE response, closing that response stream cancels the request. In both cases, the operation being cancelled is identified explicitly rather than by a durable protocol session.

The host remains the security boundary

MCP makes capabilities interoperable; it does not make them trustworthy. A tool can write files, send messages, change infrastructure, or return content designed to influence a model. The host must treat server metadata, tool output, resource contents, icons, and schemas as untrusted.

The specification’s security guidance emphasizes consent, least privilege, audience validation, and preventing token passthrough S047. The modern HTTP binding additionally requires Origin validation, recommends binding local servers to 127.0.0.1, and recommends authentication. Statelessness makes one requirement sharper: every request must be authenticated and authorized independently.

Practical host policy should answer four questions before a call runs:

  1. Which server supplied this capability? A familiar tool name is not proof of provenance.
  2. What data will leave the host? Send only arguments and context required for the operation.
  3. What can the call change? Read, write, delete, publish, and purchase actions deserve different approval rules.
  4. What result can influence the model? Tool output is data, not a trusted instruction channel.

The resulting mental model is deliberately modest: MCP is typed, versioned plumbing between a host and focused servers. The host remains responsible for the model, the user experience, permissions, context assembly, and the consequences of every action.

Evidence6 cited primary or authoritative sources
Last reviewedAugust 25, 2026
How we research