MCP· Lesson 3 of 3
MCP from the Other Side — Clients and Hosts
In one line · **The Server offers the capabilities, the Client talks to exactly one Server, and the Host is the application that manages all the Clients and connects them to the LLM — and if you're building an agent product, this is the part you're building.**
- MCP has three roles, not one: the Server (offers capabilities), the Client (talks to a single Server), and the Host (the application that manages all the Clients and wires them to the model).
- Most content teaches you to build a Server. This concept covers the side nobody talks about: how to consume, and what the Host actually does.
- The Host is responsible for: Discovery (finding out what tools the Servers offer), connection lifecycle management, Tool Aggregation across multiple Servers, routing the model's requests to the right tool, and the permissions and approvals UI.
- Sampling: when a Server asks the Host to query the LLM on its behalf — a powerful feature, but it flips the direction of control, so it needs attention.
- Roots: define for the Server "what you are allowed to see" — a fence around its scope of visibility (like files).
- A common myth: "MCP is just plugins for Claude." No — it's an open standard any Host can implement.
If you're building a real AI product — an agent platform, an IDE-like tool that assists developers, or an internal Copilot for your company — you are not just building a Server. You are building the part that consumes Servers, manages them, and connects them to the model. In other words, you're building a Host. The problem is that every tutorial stops at "how to make a Server that offers a tool" and leaves you alone with the harder part: how do I take in ten Servers, aggregate their tools, route the model's request to the right one, and control permissions?
Even if you'll never build a Host from scratch — if you only use a ready-made one — understanding the three roles tells you who is responsible for what: who controls approvals? who decides which tool executes? when something breaks, where do you look?
Arabic content (and courses in general) teaches the producing side. This consuming side is what separates "I made a Server demo" from "I built a product that actually manages tools."
Think of it as a restaurant:
- The Server = a kitchen. It offers dishes (tools) and says "here's my menu."
- The Client = the waiter dedicated to one kitchen. He shuttles between the dining room and that kitchen only.
- The Host = the restaurant itself. It manages all the waiters, merges the menus from all the kitchens into one, and delivers orders to the customer (the model).
The customer (the model) sees one menu. It has no idea that behind the scenes there are five kitchens and Servers. The Host is what hides that complexity and presents everything as a single interface.
Imagine an office with a new employee (the model) on his first day. The office has many departments: legal, finance, HR — each with its own services and its own system.
- Each department = a Server, offering its own services.
- Every time the employee needs to talk to a department, there is a dedicated coordinator for that department = a Client.
- But who organized all of this? Who told the new employee "here are all the available departments and what each one does"? Who routes his request to the right department? Who tells him "this request needs the director's approval first"? That's the front office = the Host.
The new employee (the model) is smart, but lost on his own. The Host is what draws him the map, connects him to the departments, and sets the rules of the game. Notice: the intelligence is in the employee, but the organization is in the office. The Host doesn't think in the model's place — it enables the model to work in an orderly way.
A real example
Say you have an internal company Copilot, connected to three Servers:
> - Server 1 — Docs: tool search_wiki > - Server 2 — Jira: tools list_issues + create_issue > - Server 3 — Calendar: tool find_free_slot
An employee types: "Find me the open bug tickets, and book me an hour tomorrow to review them."
What happens inside the Host: 1. Aggregation: the Host merged the four tools from the three Servers into one menu presented to the model. 2. Routing: the model decided to use list_issues → the Host routed the request to the Jira Client exactly, not any other Client. 3. Approval: the model then chose find_free_slot followed by a booking → the Host prompted the employee: "Book 11am tomorrow?" 4. Return: every result went back to the model through the Host, so it could finish the reply.
The employee saw one smooth experience. The Host is what held all the complexity.
The Host has five core jobs. This is its "job description":
1. Discovery: ask every connected Server "what capabilities do you have?" and collect the answers. This happens at connection start (Capability Negotiation). 2. Connection lifecycle management: open the connection to each Server, keep it alive, close it cleanly, and handle disconnects. 3. Tool Aggregation: merge the tools of all Servers into a single list presented to the model — resolving name collisions along the way (when two Servers offer a tool with the same name). 4. Routing: when the model requests a tool, the Host knows which Server that tool belongs to, and sends the request to the right Client. 5. Permissions and approvals (Permissions UI): show the user which tool the agent wants to use, and take approval on sensitive actions.
The part that trips people up: the Client is not the Host. The Client is small and boring — it talks to one Server, period. The Host is the mastermind that manages all of those Clients. One application (the Host) contains multiple Clients inside it, one Client per Server.
Step by step — a full request journey
Let's trace a single question end-to-end, across the three roles:
Setup (once, at startup): 1. The Host decides to connect to 3 Servers → it creates a Client for each one. 2. Each Client opens a connection to its Server and asks about its capabilities (Discovery). 3. The Host merges all the tools (Aggregation) into one menu.
Question time (every time): 4. The user sends a question to the Host. 5. The Host sends the question + the aggregated tool menu to the LLM. 6. The model decides: "I need the search_wiki tool." 7. The Host checks which Server that tool belongs to → routes the request to the right Client (Routing). 8. The Client sends it to the Server, the Server executes, and returns the result. 9. The result flows back through the Client to the Host, and the Host places it into the model's context. 10. The model continues — answers, or requests another tool (back to step 6).
Note: steps 6→9 may repeat several times within the same question (the agent loop). The Host holds the thread through every cycle.
Diagram
The three roles, and the full request journey:
┌───────────────────────── HOST (your app) ───────────────────────┐
│ │
│ User ──► [ Host logic ] │
│ │ ▲ │
│ ▼ │ │
│ [ LLM ] ◄── aggregated tool menu (Aggregation) │
│ │ ▲ │
│ Tool Call │ │ Tool Result │
│ ▼ │ │
│ [ Routing: which Server owns this tool? ] │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ Client A Client B Client C │
└───────────┼────────────┼─────────────┼─────────────────────────┘
│ │ │
▼ ▼ ▼
Server A Server B Server C
(Docs) (Jira) (Calendar)
offers tools offers tools offers tools
Full round trip:
user → host → LLM → tool call → routing → client → server
→ result → client → host → LLM → answerNotice something in the drawing: the model sees one box (an aggregated menu) — it never sees the three Servers. That's the essence of the Host's job: hiding the multiplicity and presenting a single interface. And the Clients (A, B, C) are each blind to the others — each one knows only its own Server. The Host alone sees the whole picture.
First thing to fix in your head: the Client-to-Server relationship is 1-to-1; the Host-to-Clients relationship is 1-to-many. The Host contains N Clients, each bound to exactly one Server. That's the architectural split — understand it and the rest follows.
Second: the Client is deliberately thin and dumb. Its whole job is speaking the MCP protocol with one Server: open a connection, run Discovery, send requests, receive responses. It carries no business logic. That's intentional design — it makes the Client reusable, and concentrates all the complexity in one place (the Host).
Third — and this is the most important control point: Sampling flips the direction of initiative. Normally the Host asks the Server ("use a tool"). Sampling reverses it: the Server asks the Host to query the LLM on its behalf. Why does this exist? So a Server can do a smart step (summarize, classify) without owning a model or an API key of its own. The Server borrows the Host's "brain." The control implication: the Host must remain the decision-maker — review the Sampling request, possibly surface it to the user, and control the cost — never pass it through blindly. Because you'd be handing third-party Server code a channel to consume your model (and your money).
Fourth: Roots define the Server's scope of visibility. A Root is like an "allowed folder" — the Host tells the Server "you may see within these bounds only" (say, one project folder, not the whole machine). It's a fence on "what the Server can reach," and an important safety control.
At the system level — the practical reality
Five facts you'll hit the moment you build a Host:
- Tool name collisions are real. If two Servers both offer a tool named
search, you must apply namespacing (likejira.searchanddocs.search) before presenting them to the model — otherwise routing scrambles. - The connection lifecycle needs explicit management. Servers disconnect, break, get slow. The Host must handle a downed Server without the whole system collapsing — its tools should disappear from the menu gracefully.
- A big tool menu costs tokens and distracts the model. Every tool description enters the model's context. 50 tools from 10 Servers = a bloated context + worse decisions. Filter the available tools by context — don't put everything in front of the model all the time.
- Sampling needs governance. If you let Servers do Sampling, set a cost ceiling, review the requests, and prefer approval at least the first time. A Server requesting Sampling in a loop can surprise you with a bill.
- Approvals must be visible to the user. The permissions UI is not a UI detail — it's the security layer through which the user sees what the agent is doing. Show the tool, the Server, and the inputs — before execution.
The code
This code is not from any specific SDK — it's the bare idea: how a simple Host connects multiple Clients, aggregates their tools, and routes the model's request to the right Client. Read it as pseudocode:
# ---------- 1) The Host creates a Client per Server and discovers its tools ----------
servers = {
"docs": connect_client("docs-server"), # Client ← Server (1:1)
"jira": connect_client("jira-server"),
"calendar": connect_client("calendar-server"),
}
tool_registry = {} # the aggregated menu
for name, client in servers.items():
for tool in client.discover_tools(): # Discovery
key = f"{name}.{tool.name}" # Namespacing prevents collisions
tool_registry[key] = (client, tool) # remember which Client owns this tool
# ---------- 2) Present the aggregated menu to the model ----------
tools_for_model = [t.schema for (_, t) in tool_registry.values()]
# ---------- 3) The loop: the model requests, the Host routes ----------
while True:
step = llm.step(conversation, tools=tools_for_model) # Agent loop
if step.is_final_answer:
return step.text
# The model requested a tool — route it to the right Client (Routing)
client, tool = tool_registry[step.tool_call.name]
if tool.is_sensitive: # permissions UI
if not ask_user_approval(step.tool_call):
conversation.add_tool_result("rejected by user")
continue
result = client.call(tool.name, step.tool_call.args) # Client ← Server
conversation.add_tool_result(result) # the result goes back to the modelNote three things before moving on:
- The Host owns the `tool_registry`. That's the heart of aggregation and routing: it knows which Client each tool belongs to. Without that map, the model requests a tool and the Host doesn't know where to send it.
- Namespacing (`docs.search`) is not a luxury. Without it, name collisions break routing silently.
- The Clients are completely invisible to the model. The model sees tool names only. Connection management and routing are all internal Host work.
Exercise (25 minutes): On paper, design a simple Host for 3 imaginary Servers (Docs, Database, Email). Sketch: (1) how you'll do Discovery and aggregate the tools, (2) how you'll resolve a collision if two Servers both have a search tool, (3) when the model requests send_email, how the Host knows which Client to route it to, and (4) exactly where you'll place the human approval. Then ask yourself: if the Email Server goes down, what happens to the menu presented to the model? If you can't answer confidently, go back to the connection lifecycle section.
| # | ❌ Wrong | ✅ Right |
|---|---|---|
| 1 | Confusing Client and Host and treating them as one thing | Client = talks to one Server (thin). Host = manages all the Clients and wires them to the model |
| 2 | Always presenting every tool from every Server to the model | Filter tools by context — a bloated menu costs tokens and degrades the model's decisions |
| 3 | Ignoring tool name collisions | Namespace every tool with its Server's name (jira.search) before presenting |
| 4 | Passing Sampling requests from Servers through without governance | The Host stays the decision-maker: cost ceiling, review, approval — the Server is borrowing your model |
| 5 | Assuming every Server is always up | Manage the connection lifecycle: a downed Server = its tools disappear gracefully, not the system collapsing |
| 6 | Treating the approvals UI as cosmetic | It's the visible security layer — show the tool, the Server, and the inputs before execution |
⚠️ Watch out: mistake #1 is the most common of all — people hear "Client" and "Host" and assume they're synonyms. No. One application (Host) contains many Clients.
Misconceptions
1) "MCP is just plugins for Claude" — ❌ No. MCP is an open standard that any Host can implement: an IDE, a chat app, an agent platform, an internal tool. The fact that it emerged in the context of one assistant doesn't make it exclusive to it. You can build your own Host from scratch that consumes any MCP Server.
2) "The Client and the Host are the same thing" — ❌ The most widespread mix-up. The Client talks to one Server and nothing else — thin and simple. The Host is the application that contains multiple Clients and manages them. That containment relationship is the key: one Host ← many Clients ← one Server each.
3) "If I use MCP, I have to build a Host" — ❌ No. If you only want to consume tools inside an existing application, use a ready-made Host. You build your own Host when you're building a product that needs to manage tools your way (an agent platform, an IDE, a Copilot). Distinguish "tool consumer" from "platform builder."
4) "Sampling means the Server has its own model" — ❌ The opposite. Sampling exists because the Server does not have a model — so it asks the Host to query the LLM on its behalf. The model and the bill belong to the Host, not the Server. That's exactly why governance matters.
Security
The Host is the single enforcement point for security — because it holds the permissions, the approvals, and the routing. Three points to stay conscious of:
1) The Host is the guardian of approvals. Any approval gate on a sensitive action is enforced in the Host layer — not the Server, not the model. If the Host doesn't surface sensitive tools to the user before execution, there is no protection. (Full threat details live in the MCP Security concept.)
2) Sampling is a consumption channel you must govern. When you let Servers request Sampling, you're giving third-party code a way to consume your model and your money. The Host must remain the decision-maker: ceiling, review, approval. Never pass Sampling requests through blindly.
3) Roots are the visibility fence. Use Roots to confine what each Server can see — like one project folder instead of the whole machine. A Host that doesn't set Roots gives its Servers broader visibility than necessary.
Cost
Where does the money go in Host design? Two main places, and both are under your control:
- Tool menu size = fixed tokens on every request. Every tool description sits in the model's context on every call. With 40 tools averaging 60 tokens per description, that's 2,400 extra tokens on every request — before the user types a single character. At 100k requests per month, the difference between presenting 40 tools and 10 filtered ones can be a tangible line on the bill. Filter tools by context.
- Sampling from Servers = unpredictable consumption. A Server requesting Sampling in a loop can multiply your model calls behind your back. Set a ceiling and monitor.
> 💸 Note: the numbers illustrate the thinking frame (volatile fragment — check your provider's pricing). The constant idea: the Host controls how much context is presented to the model — and that's the biggest cost lever in your hand.
Performance
- Parallel Discovery is faster. Discovering the tools of 10 Servers sequentially is slow at startup — do it in parallel.
- One slow Server stalls the whole loop. Set a timeout per Client, and let a lagging Server fail gracefully instead of hanging the request.
- Tool filtering improves performance and quality together. Smaller menu = shorter context = faster responses + sharper decisions. A rare double win.
- You're building an agent platform: users connect their own tools, and you need to manage connection, aggregation, and routing — that's a Host through and through.
- You're building a product like an IDE or editor: you want the model inside your tool to reach changing tools and context (files, terminal, extensions) — you need a Host to manage that.
- You're building an internal company Copilot: connected to multiple internal systems (Wiki, Jira, database), with a unified experience and centralized permission control — a Host.
- You want fine-grained control over aggregation, routing, and approvals: if you need to control which tools appear, when, and who approves — you build this layer yourself.
- You're using a ready-made application with a working Host: if your tool already manages tools well, don't build a Host from scratch — it's heavy infrastructure work.
- You need just one known tool: direct tool integration is simpler than a whole Host architecture for a single tool.
- The team is small and the product is still proving itself: building a solid Host (connection management, aggregation, Sampling governance) is real work — defer it until you actually need it.
- You won't manage multiple Servers: the Host's architectural payoff shows up with multiplicity. One Server? Small return for the complexity.
💡 Tip: the working rule: building a product that manages tools for other people → Host. Wiring your own tools for yourself inside an existing app → consume. If you find yourself writing aggregation and routing logic, you're in Host territory.
Alternatives
| Alternative | What it means | When it wins |
|---|---|---|
| A ready-made Host (you consume it) | Use an application with a Host already implemented | You want to consume MCP Servers without building the management layer |
| Direct tool integration | Write the tools and wire them to the model yourself, no MCP | Few fixed tools; no need for standardization or multiple Servers |
| Your own plugin system | A closed tool protocol you design for your product | You need full control and don't care about compatibility with the MCP Server ecosystem — at the cost of isolating yourself from it |
| A ready-made agent framework | A library that manages the tools and the loop for you | You want to build an agent fast without dropping to the protocol-management level yourself |
The alternatives aren't enemies: plenty of systems build a Host on top of a ready framework, and keep a few direct tools alongside their MCP Servers.
Trade-offs
| Criterion | Build a Host yourself | Consume a ready-made Host |
|---|---|---|
| Control | ✅ Full: aggregation, routing, approvals your way | ⚠️ Bounded by the ready app's decisions |
| Time to start | ❌ Slow: full connection-management infrastructure | ✅ Fast: connect and go |
| Suits | A product managing tools for users (platform/IDE/Copilot) | A tool consumer within an existing context |
| Maintenance burden | ❌ High: connection lifecycle, collisions, Sampling governance | ✅ The app takes care of it |
| Scalability to many tools | ✅ Design it however you like | ⚠️ Subject to the app's limits |
The rule: control versus speed. Build a Host when managing tools *is* the core of your product. Consume when tools are a means, not the product.
Interview questions
Q1: Explain the three roles in MCP and the relationships between them. The Server offers capabilities (tools, data). The Client speaks the protocol with one Server (a 1:1 relationship, thin, no business logic). The Host is the application that contains multiple Clients, manages them, and wires them to the LLM (a 1:many relationship). The key: one Host ← many Clients ← one Server each.
Q2: What is Sampling in MCP, and what's its impact on control? Sampling is when a Server asks the Host to query the LLM on its behalf — reversing the usual direction of initiative. It exists so a Server can perform a smart step without owning its own model. The impact: the Server borrows the Host's model and money, so the Host must remain the decision-maker — review, set a cost ceiling, take approval — never pass the request through blindly.
Q3: What are Roots, and why do they matter? Roots define the Server's scope of visibility — "you may see within these bounds only" (say, a project folder, not the whole machine). They matter because they're a security fence: they prevent the Server from reaching more than necessary, and give you explicit control over "what the Server can access."
Q4: When do you build a Host yourself instead of consuming a ready-made one? When managing tools is the core of your product: an agent platform, an IDE, or an internal Copilot managing multiple Servers where you need control over aggregation, routing, and approvals. If you're just a tool consumer inside an existing app, or you need one tool, building a Host is cost without return. The rule: building a product that manages tools for other people → Host; wiring your own tools for yourself → consume.
- Inside BuildAI (in order): MCP basics → this concept → MCP Security → Building an MCP Server → The agent loop.
- The official MCP specification: read the Host/Client, Sampling, and Roots sections after finishing this concept — you'll find you now understand "who asks whom" instead of drowning in the details.
- An architectural note: if you've worked with plugin systems or the Language Server Protocol (LSP in editors) before, you'll notice that "a Host managing Clients for multiple servers" is not a new idea — MCP applies it to tools and models. That resemblance will speed up your understanding.