MCP Architecture: How Hosts, Clients and Servers Work

See how hosts, clients and servers connect over JSON-RPC 2.0, how data and transport layers split, and what the stateless spec changed.

10 min read

MCP Architecture

MCP architecture is the client-host-server design the Model Context Protocol uses to connect AI applications to external tools and data. An MCP host, such as Claude Desktop or Cursor, runs one MCP client per MCP server, each client keeps a one-to-one connection with its server, and every message is a JSON-RPC 2.0 request carried over stdio or Streamable HTTP.

Anthropic introduced MCP in November 2024, and the Model Context Protocol is now governed by the Agentic AI Foundation under the Linux Foundation. Its current architecture specification, revision 2026-07-28, made the protocol stateless: every request carries its own version and capabilities, and servers no longer send requests to clients. Many published diagrams still show the older handshake.

Bifrost, the open-source AI gateway, sits inside this architecture as an MCP server to hosts and an MCP client to upstream servers.

How does MCP architecture work?

MCP architecture works by splitting an AI integration into three roles. The host is the AI application that runs the large language model (LLM) and creates one MCP client per configured MCP server. Each server exposes tools, resources and prompts for one system, and the client exchanges JSON-RPC messages with it.

An MCP host runs three MCP clients; two reach local servers over stdio, one reaches a remote server over Streamable HTTP, and each server fronts its own system

Figure 1: The host owns the model and the conversation; each client holds a one-to-one link to a single server, whatever transport that server uses.

A tool call crosses the architecture in five steps:

  1. Discover. The client can send server/discover to learn the server's supported versions and capabilities, then tools/list to fetch each tool's name, description and input JSON Schema.
  2. Register. The host merges the tool lists from every client into one set and passes it to the model in the provider's tool-calling format.
  3. Select. The model returns a tool call with arguments. The host checks consent and policy before anything runs.
  4. Invoke. The client that owns that tool sends tools/call to its server, which runs the work against the system behind it, such as a database or a GitHub repository.
  5. Return. The server's result goes back through the client to the host, which adds it to the model's context.

The official architecture overview notes that local servers on stdio typically serve one client, while remote servers on Streamable HTTP typically serve many.

MCP hosts, clients and servers

MCP hosts, clients and servers are the three participants the specification defines. The host is the application a person uses, the client is a connector object inside the host, and the server is a separate program that provides context. A host connected to five servers runs five clients, even when two of them reach the same remote server.

ParticipantWhat it isResponsibilitiesExamples
MCP hostThe AI applicationCreates and manages clients, runs the LLM, enforces consent and security policy, aggregates contextClaude Desktop, Claude Code, Cursor, VS Code, a custom agent
MCP clientA connector inside the host, one per serverTalks to exactly one server, attaches protocol version and capabilities to every request, manages subscriptionsOne client object per configured server
MCP serverA program that exposes one systemServes tools, resources and prompts; runs locally or remotely; asks for user input only inside a replyFilesystem, Postgres, GitHub or Sentry servers

MCP host

The MCP host is the container and coordinator. It decides which servers to connect, starts their clients, holds the conversation history and handles user authorization decisions, so it is the only participant that sees results from every server.

MCP client

The MCP client is the protocol endpoint on the application side. It keeps a dedicated connection to one server, so a failure or a misbehaving server stays isolated to that client. Under revision 2026-07-28, the client adds the protocol version and its capabilities to the _meta field of every request rather than negotiating them once.

MCP server

The MCP server is the program that serves context, wherever it runs. A server on the user's machine launched over stdio is called a local server; one reached at a URL over Streamable HTTP is a remote server. Servers are meant to be small and focused, and many wrap an existing API.

The MCP data layer and transport layer

The MCP data layer and transport layer split what a message means from how it travels. The data layer is the inner layer: a JSON-RPC 2.0 protocol that defines discovery, primitives and notifications. The transport layer is the outer layer: it frames messages, delivers them and carries authorization. The same JSON-RPC message works unchanged on every transport.

The data layer defines what servers and clients can offer each other. MCP tools are the only primitive the model controls:

PrimitiveOffered byDiscoveryUsePurpose
ToolsServertools/listtools/callFunctions the model can invoke
ResourcesServerresources/listresources/readData the host can load into context, addressed by URI
PromptsServerprompts/listprompts/getReusable templates a user selects
ElicitationClientClient capabilitieselicitation/createA server asks the user for missing input

Sampling and logging, two older client features, are deprecated as of revision 2026-07-28. List results now carry ttlMs and cacheScope caching hints, so a host can reuse a tool list instead of fetching it on every turn.

Every request in the data layer has the same shape. This tools/call follows the 2026-07-28 schema, with version and capabilities in _meta:

json
{"jsonrpc": "2.0", "id": 4, "method": "tools/call",
 "params": {"name": "query_orders", "arguments": {"status": "open"},
  "_meta": {"io.modelcontextprotocol/protocolVersion": "2026-07-28",
            "io.modelcontextprotocol/clientCapabilities": {"elicitation": {}}}}}

How do stdio and Streamable HTTP transports differ?

Stdio and Streamable HTTP differ in where the MCP server runs. With stdio, the client launches the server as a subprocess and exchanges newline-delimited JSON-RPC over standard input and output. With Streamable HTTP, the server is an independent service, and each message is an HTTP POST to one endpoint that answers with JSON or a short server-sent events stream.

DimensionstdioStreamable HTTP
Where the server runsSubprocess of the client, same machineIndependent service behind a URL
FramingOne JSON-RPC message per line on stdin and stdoutOne HTTP POST per message to a single MCP endpoint
Request metadataOnly in the JSON bodyIn the body, mirrored into MCP-Protocol-Version, Mcp-Method and Mcp-Name headers
AuthenticationNone per call; credentials come from the environmentOAuth 2.1 bearer tokens, API keys or custom headers
Cancellationnotifications/cancelledClient closes the response stream
Clients per serverUsually oneUsually many
LoggingServer may write to stderr; stdout carries only MCP messagesServer logs on its own infrastructure

The transports specification treats each transport as a binding that changes delivery, never meaning. The older HTTP+SSE transport is deprecated; MCP SSE vs Streamable HTTP covers the migration.

What changed in the stateless specification

The stateless specification, revision 2026-07-28, removed the initialize handshake and protocol sessions. A client now sends any request directly, with version and capabilities in _meta, and servers must answer server/discover for up-front discovery. A server that does not support the requested version returns UnsupportedProtocolVersionError and the supported list, and the client retries.

The change also fixed the direction of every message. Clients send requests and notifications; servers send responses and notifications. Servers no longer initiate JSON-RPC requests, so a server that needs user input returns an InputRequiredResult inside its reply, and the client re-sends the original request with the answer. Change notifications, such as a new tool list, arrive on a subscriptions/listen stream the client opens.

For architecture, that means any server instance can answer any request, which lets remote servers scale behind a plain load balancer. Servers that need state across calls return an explicit handle as a tool result and accept it as an argument later. The specification topic covers how older and newer revisions interoperate.

MCP security boundaries and authorization

MCP security boundaries follow from one design principle: servers should not read the whole conversation or see into other servers. The host keeps the full history, sends each server only the arguments for its own tools, and must get user consent before invoking a tool.

Authorization sits in the transport layer. The authorization specification makes it optional, and when used over HTTP the MCP server acts as an OAuth 2.1 resource server and the client obtains a token through the MCP OAuth flow. Stdio servers skip that flow and read credentials from the environment, the split that MCP authentication covers, which means they run with the launching user's permissions.

The architecture cannot enforce its own rules. A host that passes untrusted tool descriptions straight to the model, or a server holding one shared token for every user, breaks the boundaries the specification describes. Teams close those gaps with tool allow-lists, per-user credentials, guardrails on tool calls and an audit record for every call, the controls that MCP security maps to each risk.

Scaling MCP architecture across many servers

MCP architecture scales poorly when every host connects to every server directly. Ten developers each configuring eight servers means 80 client connections, 80 sets of credentials and no shared view of which tools are in use. Each connected tool's definition is also sent to the model on every turn, so large tool sets add tokens and wrong tool choices.

The common fix is an MCP gateway: one service that is an MCP server to every host and an MCP client to every upstream server. Hosts configure one endpoint; the gateway holds upstream credentials, filters tools per caller and logs each call. The Model Context Protocol overview places this layer next to the hosts, clients and servers it connects.

MCP architecture with Bifrost

Bifrost, the open-source AI gateway built by Maxim AI, takes both roles in the MCP architecture as an MCP gateway. As an MCP client, Bifrost connects to upstream servers over STDIO, HTTP or SSE, or generates a server from an OpenAPI document (beta). As an MCP server, it exposes the connected tools at one /mcp endpoint.

MCP hosts and an application connect to Bifrost, which authenticates them, filters tools per key, and calls local stdio servers, remote HTTP or SSE servers and OpenAPI-generated tools

Figure 2: Hosts configure one endpoint instead of one client per server, and credentials, tool access and logs live in one place.

On the upstream side, Bifrost runs the client duties the specification assigns:

  • Connections. HTTP connections open per call by default; SSE and STDIO connections stay open. Bifrost health-checks each server every 10 seconds and retries transient failures up to 5 times with backoff from 1 to 30 seconds.
  • Versions. A max protocol version setting, auto (currently 2026-07-28), can pin one server to 2025-11-25 or 2025-06-18.
  • Server instructions. Bifrost forwards each server's usage instructions in a tagged block, capped at 4,096 bytes per server and 16,384 bytes in total.

On the host side, gateway authentication accepts virtual keys or OAuth 2.1, and tool filtering scopes tools per key, per client and per request.

By default, Bifrost does not run tool calls the model returns; the application approves each one through a separate tool execution request. For large tool sets, Code Mode cut input tokens from 75.1M to 5.4M (92.8%) with 508 tools across 16 servers.

The same gateway routes model traffic to 25+ providers and 10,000+ models with 11 microseconds of overhead at 5,000 RPS. To put one endpoint in front of your MCP servers, start with the gateway quickstart.

Frequently asked questions

Is MCP a client-server or peer-to-peer protocol?

MCP is a client-server protocol with a host coordinating the clients. Each MCP client connects to exactly one MCP server, and since revision 2026-07-28 messages flow in fixed directions: clients send requests, servers send responses and notifications. Servers do not connect to each other; any interaction between servers passes through the host, which keeps them isolated.

What is the difference between an MCP host and an MCP client?

An MCP host is the AI application a person uses, such as Claude Desktop or Cursor, and it runs the model and holds the conversation. An MCP client is a connector object the host creates for one MCP server. A host connected to four servers contains four MCP clients, and each client handles only its own server's messages.

Can one MCP server serve multiple clients?

Yes. A remote MCP server on Streamable HTTP usually serves many clients, from many hosts and users, at one endpoint. A local server on stdio is usually launched by one client as a subprocess and serves only that client.

What protocol does MCP use underneath?

MCP uses JSON-RPC 2.0, a lightweight remote procedure call (RPC) format in JSON, for every message. Those messages travel over one of two standard transports: stdio for local subprocesses, or Streamable HTTP for remote servers. The message format is identical on both, and the specification allows custom transports that keep the same JSON-RPC messages.

Does MCP need a gateway?

MCP does not require a gateway; the specification only defines hosts, clients and servers. A gateway becomes useful once many hosts share many servers, because it centralizes credentials, tool access and logs. To each host it is one MCP server, and to each upstream server it is one MCP client.

  • mcp architecture
  • model context protocol architecture
  • mcp clients

[ Keep reading ]

More on MCP Gateway

View all →