Chapter 6

Separate the MCP Host, Client, and Server

The MCP side rests on three roles, and confusing them is the most common cause of insecure design. The Host is the AI application itself: a chat, an IDE, an agent, or a backend. It controls permissions, UX, and the model, chooses which servers to connect to, shows confirmations, holds the user's identity, and decides what reaches the model at all. The Client is one protocol session: inside the host, a separate client is created per server connection, and it does discovery, sends calls, and checks capabilities. The Server is a capability provider: it wraps a database, an API, or local data into tools, resources, and prompts, validates input, and applies authorization. One host, many clients, many servers - and each server sees only its own.

On a diagram this looks like a host with two independent connections.

Release Review Host
  ├─ MCP Client A ── stdio ── Runbook Server
  └─ MCP Client B ── HTTP  ── CI Evidence Server

The model loop sees the permitted union of capabilities.
Server A does not receive the internal state of Server B.

The key point here is that the model loop sees the permitted union of capabilities, but server A does not receive the internal state of server B. Trust boundaries run between servers, not smeared across one big process.

The naive design puts up one monolithic server that receives the user transcript, the secrets of every system, and the right to any operation. In a demo it's convenient, but it destroys least privilege, and audit becomes impossible: it's unclear who invoked what and on what grounds.

The professional design splits servers by data owner and risk level. The host filters the capability list by user and environment, and the server re-checks authorization itself and never relies on the model having "understood the rights correctly". The split costs a few extra objects, but it's exactly what makes the system verifiable.

Who owns orchestration. An MCP server answers protocol requests. The decision "which tool to call next" usually lives in the host. If the server itself runs long agentic work, that's already a separate runtime and, possibly, an A2A boundary rather than MCP.

The roles are separated - we can pick up a concrete SDK. And here it's important not to drag along habits from old tutorials.

Knowledge check

In MCP, who usually decides which tool to call next?

Links